Android 4.0 framework 数据业务学习总结(1)

编程入门 行业动态 更新时间:2024-10-08 06:29:01

Android 4.0 framework <a href=https://www.elefans.com/category/jswz/34/1760758.html style=数据业务学习总结(1)"/>

Android 4.0 framework 数据业务学习总结(1)

简介

本条目用于记录本人对Android framework侧数据业务的阶段学习总结。

内容包括流程图,代码分析,BUG用例等。

第一阶段学习成果

本阶段主要注重对数据连接设置管理流程的学习,掌握数据业务的基本流程与构造。同时尝试解决部分简单BUG。

数据连接设置管理介绍

通过Setting的常规设置页面中的数据连接开关,打开/关闭数据连接业务。

数据业务设置完成后如何更新到status bar上。

开机后如何自启动数据业务。

这些过程是基本数据业务之一。

数据连接设置管理流程图


数据连接设置管理代码分析

通过Settings控制数据连接开关

Settings.java文件提供动作的入口。通过ConnectivityManager实例的setMobileDataEnable方法设置此开关。

    /*** Invoked on each preference click in this hierarchy, overrides* PreferenceActivity's implementation.  Used to make sure we track the* preference click events.*/@Overridepublic boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {/** TODO: Refactor and get rid of the if's using subclasses */...} else if (preference == mButtonDataEnabled) {if (DBG) log("onPreferenceTreeClick: preference == mButtonDataEnabled.");ConnectivityManager cm =(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);cm.setMobileDataEnabled(mButtonDataEnabled.isChecked());return true;...}

这个方法实际上调用的是ConnectivityService实例的setMobileDataEnable方法。

     /*** @see ConnectivityManager#setMobileDataEnabled(boolean)*/public void setMobileDataEnabled(boolean enabled) {enforceChangePermission();if (DBG) log("setMobileDataEnabled(" + enabled + ")");mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,(enabled ? ENABLED : DISABLED), 0));}

通过Handler回调机制,我们在handleMessage对消息EVENT_SET_MOBILE_DATA进行处理。

走到了handleSetMobileData方法中。

     private void handleSetMobileData(boolean enabled) {if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {if (VDBG) {log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);}mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled);}if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {if (VDBG) {log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled);}mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled);}}

该方法根据传入的动作(enable or disable),设置对应的networkStateTracker标志位状态。

起作用的方法也就是MobileDataStateTracker实例的setUserDataEnable方法。

     @Overridepublic void setUserDataEnable(boolean enabled) {if (DBG) log("setUserDataEnable: E enabled=" + enabled);final AsyncChannel channel = mDataConnectionTrackerAc;if (channel != null) {channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE,enabled ? DctConstants.ENABLED : DctConstants.DISABLED);mUserDataEnabled = enabled;}if (VDBG) log("setUserDataEnable: X enabled=" + enabled);}

同样使用了Handler的回调机制,通过回调之后的消息

DctConstants.CMD_SET_USER_DATA_ENABLE

找到对应的在DataConnectionTracker里的Handler处理方法线程。

             case DctConstants.CMD_SET_USER_DATA_ENABLE: {final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);onSetUserDataEnabled(enabled);break;}

即回调至方法onSetUserDataEnabled()中

     protected void onSetUserDataEnabled(boolean enabled) {synchronized (mDataEnabledLock) {final boolean prevEnabled = getAnyDataEnabled();if (mUserDataEnabled != enabled) {mUserDataEnabled = enabled;Settings.Global.putInt(mPhone.getContext().getContentResolver(),Settings.Global.MOBILE_DATA, enabled ? 1 : 0);if (getDataOnRoamingEnabled() == false &&mPhone.getServiceState().getRoaming() == true) {if (enabled) {notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);} else {notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);}}if (prevEnabled != getAnyDataEnabled()) {if (!prevEnabled) {resetAllRetryCounts();onTrySetupData(Phone.REASON_DATA_ENABLED);} else {onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);}}}}}

这个方法主要可分成两部分理解。

传进来的enable动作影响了mUserDataEnable,同时也作为数据存放到数据库中。

如果这次动作传入有效(prevEnable与AnyDataEnable之间发生变化),

当enabled 为 TRUE(即开启数据连接开关) ,那么就有一次成功的建立链接动作(调用resetAllRetryCounts重置计数器,然后通过onTrySetupData建立链接)。

当enabled 为 FALSE (即关闭数据连接开关),那么就清空所有的链接(调用onCleanUpAllConnections)。


如果成功的话,最终这个动作走入gsmDataConnectionTracker的setupData方法。

通过bringUp方法建立数据链接。

注意带上了what=DctConstants.EVENT_DATA_SETUP_COMPLETE消息的msg方法是当该动作完成后才被回调。具体的建立链接动作进入bringUp中查看。

        Message msg = obtainMessage();msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;msg.obj = apnContext;dc.bringUp(msg, apn);if (DBG) log("setupData: initing!");return true;

进到DataConnection.java中,发现这个方法仍然是个回调处理机制。

     /*** Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.* Used for cellular networks that use Acesss Point Names (APN) such* as GSM networks.** @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.*        With AsyncResult.userObj set to the original msg.obj,*        AsyncResult.result = FailCause and AsyncResult.exception = Exception().* @param apn is the Access Point Name to bring up a connection to*/public void bringUp(Message onCompletedMsg, ApnSetting apn) {sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));}

假设这是个建立链接的过程,而不是断开链接的过程。那么实际上走入InactiveState这个case中。

         @Overridepublic boolean processMessage(Message msg) {boolean retVal;switch (msg.what) {...case EVENT_CONNECT:ConnectionParams cp = (ConnectionParams) msg.obj;cp.tag = mTag;if (DBG) {log("DcInactiveState msg.what=EVENT_CONNECT." + "RefCount = "+ mRefCount);}mRefCount = 1;onConnect(cp);transitionTo(mActivatingState);retVal = HANDLED;break;}
}

除了上述状态外,EVENT_CONNECT时数据链路的状态还可能是ActivatingState、ActiveState以及DisconnectingState。关于这几种状态之间的转换关系,可以由下图表示(图源:再论android 2.2数据连接过程 - Armily's Tech Blog - 博客频道 - CSDN.NET):

之后进入GsmDataConnection的onCreate()方法。

     /*** Begin setting up a data connection, calls setupDataCall* and the ConnectionParams will be returned with the* EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.** @param cp is the connection parameters*/@Overrideprotectedvoid onConnect(ConnectionParams cp) {mApn = cp.apn;if (DBG) log("Connecting to carrier: '" + mApn.carrier+ "' APN: '" + mApn.apn+ "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);createTime = -1;lastFailTime = -1;lastFailCause = FailCause.NONE;// msg.obj will be returned in AsyncResult.userObj;Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);msg.obj = cp;int authType = mApn.authType;if (authType == -1) {authType = TextUtils.isEmpty(mApn.user) ? RILConstants.SETUP_DATA_AUTH_NONE: RILConstants.SETUP_DATA_AUTH_PAP_CHAP;}String protocol;if (phone.getServiceState().getRoaming()) {protocol = mApn.roamingProtocol;} else {protocol = mApn.protocol;}phone.mCM.setupDataCall(Integer.toString(getRilRadioTechnology(RILConstants.SETUP_DATA_TECH_GSM)),Integer.toString(mProfileId),mApn.apn, mApn.user, mApn.password,Integer.toString(authType),protocol, msg);}

看到最后仍然是通过ril的方法setupDataCall以socket方式发送下去。

     public voidsetupDataCall(String radioTechnology, String profile, String apn,String user, String password, String authType, String protocol,Message result) {RILRequest rr= RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);rr.mp.writeInt(7);rr.mp.writeString(radioTechnology);rr.mp.writeString(profile);rr.mp.writeString(apn);rr.mp.writeString(user);rr.mp.writeString(password);rr.mp.writeString(authType);rr.mp.writeString(protocol);if (RILJ_LOGD) riljLog(rr.serialString() + "> "+ requestToString(rr.mRequest) + " " + radioTechnology + " "+ profile + " " + apn + " " + user + " "+ password + " " + authType + " " + protocol);send(rr);}

这个就是建立数据链接,从app到ril的流程。

数据连接设置成功后的消息反馈机制

接下来关注消息EVENT_DATA_SETUP_COMPLETE的回调,EVENT_DATA_SETUP_COMPLETE消息在数据连接setupData动作完成时被捕获。

其作用是对本次连接的结果进行处理。

在handleMessage@DataConnectionTracker.java中

             case DctConstants.EVENT_DATA_SETUP_COMPLETE:mCidActive = msg.arg1;onDataSetupComplete((AsyncResult) msg.obj);break;

即回调的处理方法是onDataSetupComplete()@GsmDataConnectionTracker.java。

该方法针对可能出现的连接失效情况进行异常处理或重连。

如果连接建立成功,同时其他设置皆完善的情况下,最后会以notify的方式通知Phone实例数据业务建立成功。

                DataConnection dc = apnContext.getDataConnection();ApnSetting apn = apnContext.getApnSetting();if (DBG) {log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" : apn.apn));}if (apn != null && apn.proxy != null && apn.proxy.length() != 0) {try {String port = apn.port;if (TextUtils.isEmpty(port)) port = "8080";ProxyProperties proxy = new ProxyProperties(apn.proxy,Integer.parseInt(port), null);dcac.setLinkPropertiesHttpProxySync(proxy);} catch (NumberFormatException e) {loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" +apn.port + "): " + e);}}// everything is setupif(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) {SystemProperties.set("gsm.defaultpdpcontext.active", "true");if (canSetPreferApn && mPreferredApn == null) {if (DBG) log("onDataSetupComplete: PREFERED APN is null");mPreferredApn = apn;if (mPreferredApn != null) {setPreferredApn(mPreferredApn.id);}}} else {SystemProperties.set("gsm.defaultpdpcontext.active", "false");}notifyDefaultData(apnContext);

这个方法最终调用DefaultPhoneNotifier.java实例的doNotifyDataConnection()方法。

如果上层在NetworkController.java里已经注册过对应的消息。

     /*** Construct this controller object and register for updates.*/public NetworkController(Context context) {...// telephonymPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);mPhone.listen(mPhoneStateListener,PhoneStateListener.LISTEN_SERVICE_STATE| PhoneStateListener.LISTEN_SIGNAL_STRENGTHS| PhoneStateListener.LISTEN_CALL_STATE| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE| PhoneStateListener.LISTEN_DATA_ACTIVITY);}

那么该方法用于相应这些注册消息。

        try {mRegistry.notifyDataConnection(convertDataState(state),sender.isDataConnectivityPossible(tmpApnType[0]), reason,sender.getActiveApnHost(tmpApnType[0]),apnType,linkProperties,linkCapabilities,((telephony!=null) ? telephony.getNetworkType() :TelephonyManager.NETWORK_TYPE_UNKNOWN),roaming);} catch (RemoteException ex) {// system process is dead}

找到对应实现方法处。

在TelephonyRegistry.java实例的notfiyDataConnection()方法中,有

            if (modified) {if (DBG) {Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState+ ", " + mDataConnectionNetworkType + ")");}for (Record r : mRecords) {if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {try {r.callback.onDataConnectionStateChanged(mDataConnectionState,mDataConnectionNetworkType);} catch (RemoteException ex) {mRemoveList.add(r.binder);}}}handleRemoveListLocked();}}broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,apnType, linkProperties, linkCapabilities, roaming);

注意mRecords.events实际上就是之前在NetworkController.java中注册的消息。如果这些消息存在,同时LISTEN_DATA_CONNECTION_STATE状态正常,那么就回调各自对应的onDataConnectionStateChanged()方法。

这是典型的OBSERVER模式。

最终这个回调的实现在消息所注册的类NetworkController.java中。

               @Overridepublic void onDataConnectionStateChanged(int state, int networkType) {if (DEBUG) {Slog.d(TAG, "onDataConnectionStateChanged: state=" + state+ " type=" + networkType);}mDataState = state;mDataNetType = networkType;updateDataNetType();updateDataIcon();refreshViews();}

该方法实现了status bar上对于数据业务图标的显示和更新。

开机后系统自动启动数据连接业务

如果关机前用户已经开启了“数据连接”业务,且未进入飞行模式。

那么重新开机后,系统应该自动进入“数据连接”的连接态。

具体流程如下:

注意到GsmDataConnectionTracker.java中会监听已注册的关于数据连接相关的消息。在handler中进行处理:

         switch (msg.what) {case EVENT_RECORDS_LOADED:onRecordsLoaded();break;case EVENT_DATA_CONNECTION_DETACHED:onDataConnectionDetached();break;case EVENT_DATA_CONNECTION_ATTACHED:onDataConnectionAttached();break;case EVENT_DATA_STATE_CHANGED:onDataStateChanged((AsyncResult) msg.obj);break;case EVENT_POLL_PDP:onPollPdp();break;case EVENT_DO_RECOVERY:doRecovery();break;case EVENT_APN_CHANGED:onApnChanged();break;case EVENT_PS_RESTRICT_ENABLED:/*** We don't need to explicitly to tear down the PDP context* when PS restricted is enabled. The base band will deactive* PDP context and notify us with PDP_CONTEXT_CHANGED.* But we should stop the network polling and prevent reset PDP.*/if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);stopNetStatPoll();stopDataStallAlarm();mIsPsRestricted = true;break;case EVENT_PS_RESTRICT_DISABLED:/*** When PS restrict is removed, we need setup PDP connection if* PDP connection is down.*/if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);mIsPsRestricted  = false;if (isConnected()) {startNetStatPoll();startDataStallAlarm();} else {// TODO: Should all PDN states be checked to fail?if (mState == State.FAILED) {cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);resetAllRetryCounts();mReregisterOnReconnectFailure = false;}trySetupData(Phone.REASON_PS_RESTRICT_ENABLED, Phone.APN_TYPE_DEFAULT);}break;case EVENT_TRY_SETUP_DATA:onTrySetupData(msg);break;case EVENT_CLEAN_UP_CONNECTION:boolean tearDown = (msg.arg1 == 0) ? false : true;if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);if (msg.obj instanceof ApnContext) {cleanUpConnection(tearDown, (ApnContext)msg.obj);} else {loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context");}break;case EVENT_RAT_CHANGED:onRatChanged();break;default:// handle the message in the super class DataConnectionTrackersuper.handleMessage(msg);break;}

这些消息被捕获到时,会回调对应的方法。以sim卡成功被Load为例。

将会回调onRecordsLoaded()方法。

     private void onRecordsLoaded() {if (DBG) log("onRecordsLoaded: createAllApnList");createAllApnList();if (mPhone.mCM.getRadioState().isOn()) {if (DBG) log("onRecordsLoaded: notifying data availability");notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED);}setupDataOnReadyApns(Phone.REASON_SIM_LOADED);}

即将相应的reason送给了SetupDataOnReadyApn()方法。

与之类似的,其他消息被回调时,最终都会调用该方法来完成消息的传递。

SetupDataOnReadyApn()方法在确认apnContext无误之后,会调用之前提到的trySetupData()方法。

         // Only check for default APN statefor (ApnContext apnContext :getPrioritySortedApnContextList().toArray(new ApnContext[0])) {if (apnContext.getState() == State.FAILED) {// By this time, alarms for all failed Apns// should be stopped if any.// Make sure to set the state back to IDLE// so that setup data can happen.apnContext.setState(State.IDLE);}if (apnContext.isReady()) {if (apnContext.getState() == State.IDLE ||(apnContext.getState() == State.CONNECTED &&apnContext.getDataConnectionAc().getPartialSuccessStatusSync())) {apnContext.setReason(reason);trySetupData(apnContext);}}}

最终与Settings设置的方式,将对应的消息以socket方式发给rild。

完成开机后即可以自动设置“数据连接”的动作。


至此,整个数据业务从设置到status bar的显示过程完成了。如有误请指出。

更多推荐

Android 4.0 framework 数据业务学习总结(1)

本文发布于:2024-02-14 15:37:25,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1764080.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:数据业务   Android   framework

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!