Android 5.1 open data flow 数据开启流程

先上一张流程图

data open.jpg
Settings.apk
在Settings ->  Data Usage Summary中的某个SIM tab下开启数据开关
android/ packages/apps/Settings/src/com/android/settings/DataUsageSummary.java
setMobileDataEnabled (true);
   
   
private View.OnClickListener mDataEnabledListener = new View.OnClickListener() {
@Override
public 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);
}
};

下面这部根据phoneId获得了当前获得了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 flag
android.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);
}


frameworks/base
数据开关都会调用到TelephonyManager.setDataEnabled(),不管是从流量使用情况还是从下拉的“快速设置”(Quick Setting)里打开(这里会在后面补充说明)
android/frameworks/base/telephony/java/android/telephony/TelephonyManager.java
getITelephony (). setDataEnabled ( subId , enable );
   
   
/** @hide */
@SystemApi
public 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的数据开启
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}
*/
@Override
public 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 );
   
   
@Override
public void setDataEnabled(boolean enable) {
mDcTracker.setDataEnabled(enable);
}
  android/rameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java   
发送打开数据开关的消息CMD_SET_USER_DATA_ENABLE
Message msg = obtainMessage ( DctConstants . CMD_SET_USER_DATA_ENABLE );
   
   
/**
* 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 );
   
   
@Override
public 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;
}
...
onTrySetupData ( Phone . REASON_DATA_ENABLED );
   
   
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);
}
}
}
}

android/frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
setupDataOnConnectableApns ( reason );
   
   
@Override
// TODO: We shouldnt need this.
protected boolean onTrySetupData(String reason) {
if (DBG) log("onTrySetupData: reason=" + reason);
setupDataOnConnectableApns(reason);
return true;
}
trySetupData ( apnContext );
   
   
private void setupDataOnConnectableApns(String reason) {
if (DBG) log("setupDataOnConnectableApns: " + reason);
 
for (ApnContext apnContext : mPrioritySortedApnContexts) {
if (DBG) log("setupDataOnConnectableApns: apnContext " + apnContext);
if (apnContext.getState() == DctConstants.State.FAILED) {
apnContext.setState(DctConstants.State.IDLE);
}
if (apnContext.isConnectable()) {
log("setupDataOnConnectableApns: isConnectable() call trySetupData");
apnContext.setReason(reason);
trySetupData(apnContext);
}
}
}
下面这个方法比较长,有很多条件的检查
boolean retValue = setupData ( apnContext , radioTech );
   
   
 
private boolean trySetupData(ApnContext apnContext) {
        ...
if ( apnContext . isConnectable () && ( isEmergencyApn ||  
(isDataAllowed(apnContext) &&
getAnyDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
if (apnContext.getState() == DctConstants.State.FAILED) {
if (DBG) log("trySetupData: make a FAILED ApnContext IDLE so its reusable");
apnContext.setState(DctConstants.State.IDLE);
}
int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
if (apnContext.getState() == DctConstants.State.IDLE) {
 
ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType(),
radioTech);
if (waitingApns.isEmpty()) {
notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext);
notifyOffApnsOfAvailability(apnContext.getReason());
if (DBG) log("trySetupData: X No APN found retValue=false");
return false;
} else {
apnContext.setWaitingApns(waitingApns);
if (DBG) {
log ("trySetupData: Create from mAllApnSettings : "
+ apnListToString(mAllApnSettings));
}
}
}
 
if (DBG) {
log("trySetupData: call setupData, waitingApns : "
+ apnListToString(apnContext.getWaitingApns()));
}
boolean retValue = setupData(apnContext, radioTech);//7
notifyOffApnsOfAvailability(apnContext.getReason());
 
if (DBG) log("trySetupData: X retValue=" + retValue);
return retValue;
} else {
if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
&& apnContext.isConnectable()) {
mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
}
notifyOffApnsOfAvailability(apnContext.getReason());
if (DBG) log ("trySetupData: X apnContext not 'ready' retValue=false");
return false;
}
}
dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, radioTech, mAutoAttachOnCreation, msg );
   
   
private boolean setupData(ApnContext apnContext, int radioTech) {
if (DBG) log("setupData: apnContext=" + apnContext);
ApnSetting apnSetting;
DcAsyncChannel dcac = null;
 
apnSetting = apnContext.getNextWaitingApn();
if (apnSetting == null) {
if (DBG) log("setupData: return for no apn found!");
return false;
}
 
int profileId = apnSetting.profileId;
if (profileId == 0) {
profileId = getApnProfileID(apnContext.getApnType());
}
 
// On CDMA, if we're explicitly asking for DUN, we need have
// a dun-profiled connection so we can't share an existing one
// On GSM/LTE we can share existing apn connections provided they support
// this type.
if (apnContext.getApnType() != PhoneConstants.APN_TYPE_DUN ||
teardownForDun() == false) {
dcac = checkForCompatibleConnectedApnContext(apnContext);
if (dcac != null) {
// Get the dcacApnSetting for the connection we want to share.
ApnSetting dcacApnSetting = dcac.getApnSettingSync();
if (dcacApnSetting != null) {
// Setting is good, so use it.
apnSetting = dcacApnSetting;
}
}
}
if (dcac == null) {
if (isOnlySingleDcAllowed(radioTech)) {
if (isHigherPriorityApnContextActive(apnContext)) {
if (DBG) {
log("setupData: Higher priority ApnContext active. Ignoring call");
}
return false;
}
 
// Only lower priority calls left. Disconnect them all in this single PDP case
// so that we can bring up the requested higher priority call (once we receive
// repsonse for deactivate request for the calls we are about to disconnect
if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
// If any call actually requested to be disconnected, means we can't
// bring up this connection yet as we need to wait for those data calls
// to be disconnected.
if (DBG) log("setupData: Some calls are disconnecting first. Wait and retry");
return false;
}
 
// No other calls are active, so proceed
if (DBG) log("setupData: Single pdp. Continue setting up data call.");
}
 
dcac = findFreeDataConnection();
 
if (dcac == null) {
dcac = createDataConnection();
}
 
if (dcac == null) {
if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD");
return false;
}
}
if (DBG) log("setupData: dcac=" + dcac + " apnSetting=" + apnSetting);
 
apnContext.setDataConnectionAc(dcac);
apnContext.setApnSetting(apnSetting);
apnContext.setState(DctConstants.State.CONNECTING);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
 
Message msg = obtainMessage();
msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
msg.obj = apnContext;
dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, radioTech, mAutoAttachOnCreation,
msg);//8
 
if (DBG) log("setupData: initing!");
return true;
}

android/frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
sendMessage
   
   
/**
* 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 apnContext is the Access Point Name to bring up a connection to
* @param initialMaxRetry the number of retires for initial bringup.
* @param profileId for the conneciton
* @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().
*/
public void bringUp(ApnContext apnContext, int initialMaxRetry, int profileId,
int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg) {
if (DBG) {
log("bringUp: apnContext=" + apnContext + " initialMaxRetry=" + initialMaxRetry
+ " onCompletedMsg=" + onCompletedMsg);
}
sendMessage(DataConnection.EVENT_CONNECT,//9
new ConnectionParams(apnContext, initialMaxRetry, profileId,
rilRadioTechnology, retryWhenSSChange, onCompletedMsg));
}


android/frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
这其实是个状态即机 StateMachine,这个类或者或机制,本身也比较复杂,以后看明白了以后会单独在写一篇文章
现在是进入其中一个状态 DcInactiveState。
DcInactiveState processmesssage
onConnect ( mConnectionParams );
   
   
     /**
* The state machine is inactive and expects a EVENT_CONNECT.
*/
private class DcInactiveState extends State {
...
 
@Override
public boolean processMessage(Message msg) {
...               
            case EVENT_CONNECT:
if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT");
ConnectionParams cp = (ConnectionParams) msg.obj;
if (initConnection(cp)) {
onConnect(mConnectionParams);//10
transitionTo(mActivatingState);
} else {
if (DBG) {
log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed");
}
notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
false);
}
retVal = HANDLED;
break;
mPhone . mCi . setupDataCall
   
   
 
/**
* 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
*/
private void onConnect(ConnectionParams cp) {
if (DBG) log("onConnect: carrier='" + mApnSetting.carrier
+ "' APN='" + mApnSetting.apn
+ "' proxy='" + mApnSetting.proxy + "' port='" + mApnSetting.port + "'");
 
// Check if we should fake an error.
if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter > 0) {
...
}
 
mCreateTime = -1;
mLastFailTime = -1;
mLastFailCause = DcFailCause.NONE;
 
// The data profile's profile ID must be set when it is created.
int dataProfileId;
if (mApnSetting.getApnProfileType() == ApnProfileType.PROFILE_TYPE_OMH) {
dataProfileId = mApnSetting.getProfileId() + RILConstants.DATA_PROFILE_OEM_BASE;
log("OMH profile, dataProfile id = " + dataProfileId);
} else {
dataProfileId = cp.mProfileId;
}
 
// msg.obj will be returned in AsyncResult.userObj;
Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
msg.obj = cp;
 
int authType = mApnSetting.authType;
if (authType == -1) {
authType = TextUtils.isEmpty(mApnSetting.user) ? RILConstants.SETUP_DATA_AUTH_NONE
: RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
}
 
String protocol;
if (mPhone.getServiceState().getRoaming()) {
protocol = mApnSetting.roamingProtocol;
} else {
protocol = mApnSetting.protocol;
}
 
mPhone.mCi.setupDataCall(//11
Integer.toString(cp.mRilRat + 2),
Integer.toString(dataProfileId),
mApnSetting.apn, mApnSetting.user, mApnSetting.password,
Integer.toString(authType),
protocol, msg);
}

android/frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java


--------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值