惯例流程图先

流程是入口是Settings->Data Usage 的开关,后面会看一下从下拉快速设置的入口进入。
android/packages/apps/Settings/src/com/android/settings/DataUsageSummary.java
关闭数据开关时,会弹出确认窗口
ConfirmDataDisableFragment.show(DataUsageSummary.this);
private View.OnClickListener mDataEnabledListener = new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mBinding) return;final boolean dataEnabled = !mDataEnabled.isChecked();final String currentTab = mCurrentTab;if (TAB_MOBILE.equals(currentTab) || currentTab.startsWith(TAB_SIM)) {if (dataEnabled) {setMobileDataEnabled(true);if (mPolicyEditor.getPolicyWarningBytes(mTemplate) == WARNING_DISABLED) {mPolicyEditor.setPolicyWarningBytes(mTemplate, 2 * GB_IN_BYTES);}} else {// disabling data; show confirmation dialog which eventually// calls setMobileDataEnabled() once user confirms.ConfirmDataDisableFragment.show(DataUsageSummary.this);}}updatePolicy(false);}};
点击确认后即开始关闭数据的后续流程
target.setMobileDataEnabled(false);
/*** Dialog to request user confirmation before disabling data.*/public static class ConfirmDataDisableFragment extends DialogFragment {public static void show(DataUsageSummary parent) {if (!parent.isAdded()) return;final ConfirmDataDisableFragment dialog = new ConfirmDataDisableFragment();dialog.setTargetFragment(parent, 0);dialog.show(parent.getFragmentManager(), TAG_CONFIRM_DATA_DISABLE);}@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {final Context context = getActivity();final AlertDialog.Builder builder = new AlertDialog.Builder(context);builder.setMessage(R.string.data_usage_disable_mobile);builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {final DataUsageSummary target = (DataUsageSummary) getTargetFragment();if (target != null) {// TODO: extend to modify policy enabled flag.target.setMobileDataEnabled(false);}}});builder.setNegativeButton(android.R.string.cancel, null);return builder.create();}}
获得当前TAB对应的SIM卡subId
mTelephonyManager.setDataEnabled(subId[0],
enabled);
private void setMobileDataEnabled(boolean enabled) {if (LOGD) Log.d(TAG, "setMobileDataEnabled()");// How about exposing sub based API like TelephonyManager.setDataEnabled(int subId);if (mCurrentTab.startsWith(TAB_SIM)) {int phoneId = multiSimGetCurrentSub();// as per phone, set the individual flagandroid.provider.Settings.Global.putInt(getActivity().getContentResolver(),android.provider.Settings.Global.MOBILE_DATA + phoneId, enabled ? 1 : 0);int[] subId = SubscriptionManager.getSubId(phoneId);mTelephonyManager.setDataEnabled(subId[0], enabled);} else {mTelephonyManager.setDataEnabled(enabled);mMobileDataEnabled = enabled;}updatePolicy(false);}
android/frameworks/base/telephony/java/android/telephony/TelephonyManager.java
getITelephony().setDataEnabled(subId,
enable);
/** @hide */@SystemApipublic void setDataEnabled(int subId, boolean enable) {try {AppOpsManager appOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);if (enable) {if (appOps.noteOp(AppOpsManager.OP_DATA_CONNECT_CHANGE) != AppOpsManager.MODE_ALLOWED) {Log.w(TAG, "Permission denied by user.");return;}}Log.d(TAG, "setDataEnabled: enabled=" + enable);getITelephony().setDataEnabled(subId, enable);} catch (RemoteException e) {Log.e(TAG, "Error calling setDataEnabled", e);}}
android/packages/services/Telephony/src/com/android/phone/PhoneInterfaceManager.java
phone.setDataEnabled(enable);
/*** Set mobile data enabled* Used by the user through settings etc to turn on/off mobile data** @param enable {@code true} turn turn data on, else {@code false}*/@Overridepublic void setDataEnabled(int subId, boolean enable) {enforceModifyPermission();int phoneId = mSubscriptionController.getPhoneId(subId);log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);Phone phone = PhoneFactory.getPhone(phoneId);if (phone != null) {log("setDataEnabled: subId=" + subId + " enable=" + enable);phone.setDataEnabled(enable);} else {loge("setDataEnabled: no phone for subId=" + subId);}}
android/frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GSMPhone.java
mDcTracker.setDataEnabled(enable);
@Overridepublic void setDataEnabled(boolean enable) {mDcTracker.setDataEnabled(enable);}
android/frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
/*** Modify {@link android.provider.Settings.Global#MOBILE_DATA} value.*/public void setDataEnabled(boolean enable) {Message msg = obtainMessage(DctConstants.CMD_SET_USER_DATA_ENABLE);msg.arg1 = enable ? 1 : 0;sendMessage(msg);}
onSetUserDataEnabled(enabled);
@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {log("DISCONNECTED_CONNECTED: msg=" + msg);DcAsyncChannel dcac = (DcAsyncChannel) msg.obj;mDataConnectionAcHashMap.remove(dcac.getDataConnectionIdSync());dcac.disconnected();break;}...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;}...
onCleanUpAllConnections
protected void onSetUserDataEnabled(boolean enabled) {synchronized (mDataEnabledLock) {if (mUserDataEnabled != enabled) {mUserDataEnabled = enabled;Settings.Global.putInt(mPhone.getContext().getContentResolver(),Settings.Global.MOBILE_DATA + mPhone.getPhoneId(), enabled ? 1 : 0);if (getDataOnRoamingEnabled() == false &&mPhone.getServiceState().getRoaming() == true) {if (enabled) {notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);} else {notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);}}if (enabled) {onTrySetupData(Phone.REASON_DATA_ENABLED);} else {onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);//1}}}}
android/frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
这个类比较复杂,我们只看本次重点。
cleanUpAllConnections(true,
cause);
/*** Cleanup all connections.** TODO: Cleanup only a specified connection passed as a parameter.* Also, make sure when you clean up a conn, if it is last apply* logic as though it is cleanupAllConnections** @param cause for the clean up.*/@Overrideprotected void onCleanUpAllConnections(String cause) {cleanUpAllConnections(true, cause);}
下面这里会循环多次。for(ApnContext
apnContext :
mApnContexts.values())
/*** If tearDown is true, this only tears down a CONNECTED session. Presently,* there is no mechanism for abandoning an CONNECTING session,* but would likely involve cancelling pending async requests or* setting a flag or new state to ignore them when they came in* @param tearDown true if the underlying DataConnection should be* disconnected.* @param reason reason for the clean up.* @return boolean - true if we did cleanup any connections, false if they* were already all disconnected.*/protected boolean cleanUpAllConnections(boolean tearDown, String reason) {if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);boolean didDisconnect = false;boolean specificdisable = false;if (!TextUtils.isEmpty(reason)) {specificdisable = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED);}for (ApnContext apnContext : mApnContexts.values()) {if (apnContext.isDisconnected() == false) didDisconnect = true;if (specificdisable) {if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IMS)) {if (DBG) log("ApnConextType: " + apnContext.getApnType());apnContext.setReason(reason);cleanUpConnection(tearDown, apnContext);//2}} else {// TODO - only do cleanup if not disconnectedapnContext.setReason(reason);cleanUpConnection(tearDown, apnContext);}}stopNetStatPoll();stopDataStallAlarm();// TODO: Do we need mRequestedApnType?mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;log("cleanUpConnection: mDisconnectPendingCount = " + mDisconnectPendingCount);if (tearDown && mDisconnectPendingCount == 0) {notifyDataDisconnectComplete();notifyAllDataDisconnected();}return didDisconnect;}
每一次进来后if(apnContext.isDisconnected()) 的判断结果是不一样的,apnContext={mApnType=default
mState=CONNECTED mApnType为其他时,其mState一般是IDLE的
protected void cleanUpConnection(boolean tearDown, ApnContext apnContext) {if (apnContext == null) {if (DBG) log("cleanUpConnection: apn context is null");return;}DcAsyncChannel dcac = apnContext.getDcAc();if (DBG) {log("cleanUpConnection: E tearDown=" + tearDown + " reason=" + apnContext.getReason() +" apnContext=" + apnContext);}if (tearDown) {//3if (apnContext.isDisconnected()) {// The request is tearDown and but ApnContext is not connected.// If apnContext is not enabled anymore, break the linkage to the DCAC/DC.apnContext.setState(DctConstants.State.IDLE);if (!apnContext.isReady()) {if (dcac != null) {dcac.tearDown(apnContext, "", null);}apnContext.setDataConnectionAc(null);}} else {// Connection is still there. Try to clean up.if (dcac != null) {//4if (apnContext.getState() != DctConstants.State.DISCONNECTING) {boolean disconnectAll = false;if (PhoneConstants.APN_TYPE_DUN.equals(apnContext.getApnType())) {// CAF_MSIM is this below condition required.// if (PhoneConstants.APN_TYPE_DUN.equals(PhoneConstants.APN_TYPE_DEFAULT)) {if (teardownForDun()) {if (DBG) log("tearing down dedicated DUN connection");// we need to tear it down - we brought it up just for dun and// other people are camped on it and now dun is done. We need// to stop using it and let the normal apn list get used to find// connections for the remaining desired connectionsdisconnectAll = true;}}if (DBG) {log("cleanUpConnection: tearing down" + (disconnectAll ? " all" :""));}Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, apnContext);//4if (disconnectAll) {apnContext.getDcAc().tearDownAll(apnContext.getReason(), msg);} else {apnContext.getDcAc().tearDown(apnContext, apnContext.getReason(), msg);}apnContext.setState(DctConstants.State.DISCONNECTING);mDisconnectPendingCount++;}} else {// apn is connected but no reference to dcac.// Should not be happen, but reset the state in case.apnContext.setState(DctConstants.State.IDLE);mPhone.notifyDataConnection(apnContext.getReason(),apnContext.getApnType());}}} else {// force clean up the data connection.if (dcac != null) dcac.reqReset();apnContext.setState(DctConstants.State.IDLE);mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());apnContext.setDataConnectionAc(null);}if (mOmhApt != null) {mOmhApt.clearActiveApnProfile();}// Make sure reconnection alarm is cleaned up if there is no ApnContext// associated to the connection.if (dcac != null) {cancelReconnectAlarm(apnContext);}setupDataForSinglePdnArbitration(apnContext.getReason());if (DBG) {log("cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason() +" apnContext=" + apnContext + " dcac=" + apnContext.getDcAc());}}
android/frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
sendMessage
/*** Tear down the connection through the apn on the network.** @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.* With AsyncResult.userObj set to the original msg.obj.*/public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) {if (DBG) {log("tearDown: apnContext=" + apnContext+ " reason=" + reason + " onCompletedMsg=" + onCompletedMsg);}sendMessage(DataConnection.EVENT_DISCONNECT,//7new DisconnectParams(apnContext, reason, onCompletedMsg));}
android/frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
这个也挺复杂的 维护了一个状态机 StateMachine
tearDownData(dp);
/*** The state machine is connected, expecting an EVENT_DISCONNECT.*/private class DcActiveState extends State {...@Overridepublic boolean processMessage(Message msg) {...case EVENT_DISCONNECT: {DisconnectParams dp = (DisconnectParams) msg.obj;if (DBG) {log("DcActiveState: EVENT_DISCONNECT dp=" + dp+ " dc=" + DataConnection.this);}if (mApnContexts.contains(dp.mApnContext)) {if (DBG) {log("DcActiveState msg.what=EVENT_DISCONNECT RefCount="+ mApnContexts.size());}if (mApnContexts.size() == 1) {mApnContexts.clear();mDisconnectParams = dp;mConnectionParams = null;dp.mTag = mTag;tearDownData(dp);transitionTo(mDisconnectingState);} else {mApnContexts.remove(dp.mApnContext);notifyDisconnectCompleted(dp, false);}} else {log("DcActiveState ERROR no such apnContext=" + dp.mApnContext+ " in this dc=" + DataConnection.this);notifyDisconnectCompleted(dp, false);}retVal = HANDLED;break;}
mPhone.mCi.deactivateDataCall
/*** TearDown the data connection when the deactivation is complete a Message with* msg.what == EVENT_DEACTIVATE_DONE and msg.obj == AsyncResult with AsyncResult.obj* containing the parameter o.** @param o is the object returned in the AsyncResult.obj.*/private void tearDownData(Object o) {int discReason = RILConstants.DEACTIVATE_REASON_NONE;if ((o != null) && (o instanceof DisconnectParams)) {DisconnectParams dp = (DisconnectParams)o;if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF)) {discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;} else if (TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) {discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;}}if (mPhone.mCi.getRadioState().isOn()|| (mPhone.getServiceState().getRilDataRadioTechnology()== ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN )) {if (DBG) log("tearDownData radio is on, call deactivateDataCall");mPhone.mCi.deactivateDataCall(mCid, discReason,obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o));} else {if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");AsyncResult ar = new AsyncResult(o, null, null);sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, ar));}}
调用到RIL.java中的方法
android/frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
--------------
本文详细解析了Android系统中数据开关的实现流程,从用户界面上的开关操作开始,逐步深入到内核层面的数据连接断开过程。涉及关键组件包括Settings应用、TelephonyManager、DcTracker等。

1万+

被折叠的 条评论
为什么被折叠?



