• Android 5.1 open data flow 数据开启流程


     首先我们来看看下面的关系图:


    底层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 这个类是通讯中的使用类。


  • 相关阅读:
    Centos7部署jenkins
    查看杀死django进程
    【填坑】python3 manage.py migrate:?: (mysql.W002) MySQL Strict Mode is not set for database connection 'default'
    Amazon S3 加密
    向 Elastic Beanstalk 环境中添加数据库
    Amazon RDS 监控概览
    AWS Lambda 环境变量
    使用 DynamoDB Auto Scaling 自动管理吞吐容量
    使用 Amazon Aurora Auto Scaling 扩展 Aurora 副本
    ECS 服务 Auto Scaling 和 Application Auto Scaling
  • 原文地址:https://www.cnblogs.com/new0801/p/6175787.html
Copyright © 2020-2023  润新知