您的位置:首页 > 移动开发 > Android开发

Android 5.1 open data flow 数据开启流程

2016-03-21 19:55 701 查看
首先我们来看看下面的关系图:



底层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);





<span style="background-color: rgb(255, 255, 255);"> 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);
}
}
}</span>




下面这个方法比较长,有很多条件的检查

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
这个类是通讯中的使用类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: