Android 5.1 close data flow 数据关闭流程

惯例流程图先
dataconnection disconnect.jpg


流程是入口是Settings->Data Usage 的开关,后面会看一下从下拉快速设置的入口进入。

android/packages/apps/Settings/src/com/android/settings/DataUsageSummary.java
关闭数据开关时,会弹出确认窗口
ConfirmDataDisableFragment . show ( DataUsageSummary . this );

    
    
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);
}
};

点击确认后即开始关闭数据的后续流程
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);
}
 
@Override
public 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() {
@Override
public 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 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);
}

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 . 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/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 );
    
    
@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;
}
...
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.
*/
 
@Override
protected 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 disconnected
apnContext.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) {//3
if (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) {//4
if (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 connections
disconnectAll = true;
}
}
if (DBG) {
log("cleanUpConnection: tearing down" + (disconnectAll ? " all" :""));
}
Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, apnContext);//4
if (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,//7
new 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 {
...
 
@Override
public 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



--------------
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android 5.1是一个广泛使用的操作系统版本,支持HDMI输出功能。要设置HDMI分辨率,可以按照以下步骤进行: 1. 首先,将Android设备与HDMI显示器或电视连接。确保HDMI线缆正常连接。 2. 在Android设备上打开设置菜单。可以通过下拉通知栏或点击主屏幕上的设置图标来访问设置菜单。 3. 在设置菜单中,向下滚动并找到“显示”选项。点击进入显示设置页面。 4. 在显示设置页面中,可能会看到“屏幕投射”或“显示模式”的选项。点击进入相关设置。 5. 在屏幕投射或显示模式设置页面中,可以看到HDMI选项。点击进入HDMI设置。 6. 在HDMI设置页面中,通常会有分辨率选项。点击进入分辨率设置。 7. 在分辨率设置页面中,可以看到可用的分辨率选项列表。根据显示器或电视的支持能力和个人偏好,选择所需的分辨率。 8. 选择完分辨率后,点击确认或应用。系统将应用所选的分辨率设置。 9. 返回到上一个菜单或主屏幕,查看是否已成功设置HDMI分辨率。显示器或电视上的画面应该会根据所选的分辨率进行调整。 需要注意的是,不同的Android设备或系统版本可能会有略微不同的设置流程。因此,根据具体的设备和系统版本,上述步骤可能会有所变化。但总体而言,通过进入设置菜单,找到显示设置,再进入HDMI设置,选择适当的分辨率,就可以完成Android 5.1设置HDMI分辨率的流程。 ### 回答2: Android 5.1版本的设备在设置HDMI分辨率时,可以按照以下步骤进行操作: 1. 连接HDMI线缆:首先,将一端的HDMI线缆插入Android设备的HDMI输出接口,另一端插入显示设备(如电视或投影仪)的HDMI输入接口。 2. 打开设置界面:在Android设备上,找到并点击打开“设置”应用程序,通常可以在应用程序列表中找到该选项。 3. 进入显示设置:在“设置”主界面中,向下滚动并找到“显示”选项,点击进入显示设置界面。 4. 选择HDMI设置:在显示设置界面中,找到并点击“HDMI”选项,这将打开HDMI设置界面。 5. 选择分辨率:在HDMI设置界面中,通常会显示可用的HDMI分辨率选项。根据你的显示设备和个人需求,选择适当的分辨率选项。 6. 保存设置:选择完分辨率后,点击界面上的“保存”或“应用”按钮,以保存并应用新的HDMI分辨率设置。 7. 测试分辨率:你可以通过在显示设备上观察图像是否清晰和完整来测试新的HDMI分辨率设置。如果满意,设置流程就结束了。 请注意,以上步骤仅适用于Android 5.1版本的系统设备,不同的Android版本或设备类型可能略有不同。确保你的设备支持HDMI输出功能并运行在Android 5.1版本或更高版本。 ### 回答3: 要设置Android 5.1的HDMI分辨率,可以按照以下流程操作: 1. 首先,确保你的Android设备已连接到HDMI显示器上。 2. 在设备上滑动屏幕,进入主菜单,找到并点击“设置”图标。 3. 在设置菜单中,向下滚动找到“显示”或类似的选项,并点击进入。 4. 在显示设置菜单中,找到“屏幕分辨率”或类似的选项,并点击进入。 5. 系统会列出可用的屏幕分辨率选项。根据你的需求和HDMI显示器的能力,选择一个适合的分辨率。 6. 点击选中分辨率后,系统会提示你是否确认应用此分辨率。确认后,系统会应用新的分辨率设置。 7. 返回到主菜单或桌面,你会注意到HDMI显示器的分辨率已经改变为你所设置的分辨率。 需要注意的是,不同的Android设备可能会在设置菜单的布局和选项名称上有所区别,具体操作可能会有所不同。但一般来说,通过“设置”-“显示”-“屏幕分辨率”可以找到相关的选项。 如果你在Android设备上找不到上述选项,可能是因为该设备的固件版本或制造商定制的界面导致了菜单布局的差异。在这种情况下,你可能需要查阅设备的用户手册或进行在线搜索来了解具体的设置方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值