美文网首页
Android S源码手动搜网流程

Android S源码手动搜网流程

作者: 无痕1024 | 来源:发表于2022-03-25 06:55 被阅读0次

    1 手动搜网应用程序

    1.1 MobileNetworkSettings入口

    我们首先从apk的Manifest找入口,如下:
    /packages/apps/Settings/AndroidManifest.xml

            <activity android:name=".network.telephony.MobileNetworkActivity"
                      android:label="@string/network_settings_title"
                      android:exported="true"
                      android:launchMode="singleTask">
                <intent-filter android:priority="1">
                    <!-- Displays the MobileNetworkActivity and opt-in dialog for capability discovery. -->
                    <action android:name="android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN" />
                    <action android:name="android.settings.NETWORK_OPERATOR_SETTINGS" />
                    <action android:name="android.settings.DATA_ROAMING_SETTINGS" />
                    <action android:name="android.settings.MMS_MESSAGE_SETTING" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
    

    紧接着的调用关系,会使用到布局xml文件:
    /packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkActivity.java
    /packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkSettings.java

        @Override
        protected int getPreferenceScreenResId() {
            return R.xml.mobile_network_settings;
        }
    

    1.1.1 MobileNetworkSettings布局

    从上述的R.xml.mobile_network_settings引入布局,这里摘抄部分:
    /packages/apps/Settings/res/xml/mobile_network_settings.xml

    <PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:settings="http://schemas.android.com/apk/res-auto"
        android:key="mobile_network_pref_screen">
    
        <com.android.settings.widget.SettingsMainSwitchPreference
            android:key="use_sim_switch"
            settings:controller="com.android.settings.network.telephony.MobileNetworkSwitchController"/>
    
        <PreferenceCategory
            android:key="enabled_state_container"
            android:title="@string/summary_placeholder"
            settings:controller="com.android.settings.network.telephony.DisabledSubscriptionController"
            android:layout="@layout/preference_category_no_label">
    
            <SwitchPreference
                android:key="mobile_data_enable"
                android:title="@string/mobile_data_settings_title"
                android:summary="@string/mobile_data_settings_summary"
                settings:controller="com.android.settings.network.telephony.MobileDataPreferenceController"
                settings:allowDividerAbove="true"/>
    
            <com.android.settingslib.RestrictedSwitchPreference
                android:key="button_roaming_key"
                android:title="@string/roaming"
                android:persistent="false"
                android:summaryOn="@string/roaming_enable"
                android:summaryOff="@string/roaming_disable"
                settings:userRestriction="no_data_roaming"
                settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/>
    
            <SwitchPreference
                android:key="carrier_wifi_toggle"
                android:title="@string/carrier_wifi_offload_title"
                android:summary="@string/carrier_wifi_offload_summary"
                settings:controller="com.android.settings.network.CarrierWifiTogglePreferenceController"/>
    
            <Preference
                android:key="carrier_wifi_network"
                android:title="@string/carrier_wifi_network_title"
                android:selectable="false"
                settings:searchable="false"/>
    
            <SwitchPreference
                android:key="4g_calling"
                android:title="@string/enhanced_4g_lte_mode_title_4g_calling"
                android:persistent="false"
                android:summary="@string/enhanced_4g_lte_mode_summary_4g_calling"
                settings:keywords="@string/keywords_enhance_4g_lte"
                settings:controller="com.android.settings.network.telephony.Enhanced4gCallingPreferenceController"/>
            
            <ListPreference
                android:key="preferred_network_mode_key"
                android:title="@string/preferred_network_mode_title"
                android:summary="@string/preferred_network_mode_summary"
                android:entries="@array/preferred_network_mode_choices"
                android:entryValues="@array/preferred_network_mode_values"
                android:dialogTitle="@string/preferred_network_mode_dialogtitle"
                settings:controller="com.android.settings.network.telephony.PreferredNetworkModePreferenceController"/>
    
            <PreferenceCategory
                android:key="network_operators_category_key"
                android:title="@string/network_operator_category"
                settings:controller="com.android.settings.network.telephony.NetworkPreferenceCategoryController">
    
                <SwitchPreference
                    android:key="auto_select_key"
                    android:title="@string/select_automatically"
                    settings:controller="com.android.settings.network.telephony.gsm.AutoSelectPreferenceController"/>
    
                <Preference
                    android:key="choose_network_key"
                    android:title="@string/choose_network_title"
                    android:fragment="com.android.phone.NetworkSelectSetting"
                    settings:controller="com.android.settings.network.telephony.gsm.OpenNetworkSelectPagePreferenceController"/>
            </PreferenceCategory>
    
            <!--We want separate APN setting from reset of settings because we want user to change it with caution-->
            <com.android.settingslib.RestrictedPreference
                android:key="telephony_apn_key"
                android:persistent="false"
                android:title="@string/mobile_network_apn_title"
                settings:allowDividerAbove="true"
                settings:controller="com.android.settings.network.telephony.ApnPreferenceController"/>
            
    </PreferenceScreen>
    

    1.1.2 MobileNetworkSettings字符串位置

    通过字符串也可以快速查找一些难以确认的界面程序入口:
    /packages/apps/Settings/res/values/strings.xml

    1.1.3 MobileNetworkSettings初始化

    在onAttach进行一些初步的初始化:
    /packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkSettings.java

        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
    
            use(MobileNetworkSwitchController.class).init(getLifecycle(), mSubId);
            use(DisabledSubscriptionController.class).init(getLifecycle(), mSubId);
            use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId);
            use(MobileDataPreferenceController.class).setWifiPickerTrackerHelper(
                    new WifiPickerTrackerHelper(getSettingsLifecycle(), context,
                            null /* WifiPickerTrackerCallback */));
            use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
            use(ApnPreferenceController.class).init(mSubId);
            use(PreferredNetworkModePreferenceController.class).init(mSubId);
            use(CarrierWifiTogglePreferenceController.class).init(getLifecycle(), mSubId);
    
            final WifiCallingPreferenceController wifiCallingPreferenceController =
                    use(WifiCallingPreferenceController.class).init(mSubId);
    
            final OpenNetworkSelectPagePreferenceController openNetworkSelectPagePreferenceController =
                    use(OpenNetworkSelectPagePreferenceController.class).init(getLifecycle(), mSubId);
            final AutoSelectPreferenceController autoSelectPreferenceController =
                    use(AutoSelectPreferenceController.class)
                            .init(getLifecycle(), mSubId)
                            .addListener(openNetworkSelectPagePreferenceController);
            use(NetworkPreferenceCategoryController.class).init(getLifecycle(), mSubId)
                    .setChildren(Arrays.asList(autoSelectPreferenceController));
    
            use(NetworkPreferenceCategoryController.class).init(getLifecycle(), mSubId)
                    .setChildren(Arrays.asList(autoSelectPreferenceController));
            use(Enhanced4gCallingPreferenceController.class).init(mSubId)
                    .addListener(videoCallingPreferenceController);
    

    1.2 手动搜网代码入口

    从上述分析可以得知,手动搜网的代码入口java文件如下:
    /packages/apps/Settings/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java

    1.3 手动搜网应用流程

    如果用户选择了手动搜网,则走else流程:
    /packages/apps/Settings/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java

        @Override
        public boolean setChecked(boolean isChecked) {
            if (isChecked) {
                setAutomaticSelectionMode();
                return false;
            } else {
                final Bundle bundle = new Bundle();
                bundle.putInt(Settings.EXTRA_SUB_ID, mSubId);
                new SubSettingLauncher(mContext)
                        .setDestination(NetworkSelectSettings.class.getName())
                        .setSourceMetricsCategory(SettingsEnums.MOBILE_NETWORK_SELECT)
                        .setTitleRes(R.string.choose_network_title)
                        .setArguments(bundle)
                        .launch();
                return false;
            }
        }
    

    如下界面被发起,startNetworkQuery()被调用。mUseNewApi来自config_enableNewAutoSelectNetworkUI,该值为false,所以选择了NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS:
    /packages/apps/Settings/src/com/android/settings/network/telephony/NetworkSelectSettings.java

        @Override
        public void onStart() {
            super.onStart();
    
            updateForbiddenPlmns();
            if (isProgressBarVisible()) {
                return;
            }
            if (mWaitingForNumberOfScanResults <= 0) {
                startNetworkQuery();
            }
        }
    
        private void startNetworkQuery() {
            setProgressBarVisible(true);
            if (mNetworkScanHelper != null) {
                mRequestIdManualNetworkScan = getNewRequestId();
                mWaitingForNumberOfScanResults = MIN_NUMBER_OF_SCAN_REQUIRED;
                mNetworkScanHelper.startNetworkScan(
                        mUseNewApi
                                ? NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS
                                : NetworkScanHelper.NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS);
            }
        }
    

    接下来通过startNetworkScan()来启动手动搜网,走该代码的if分支,逐步完成对TelephonyManager API的调用。这里也需要注意,对于网络侧返回信息,则callback函数onSuccess()或onFailure()会被调用:
    /packages/apps/Settings/src/com/android/settings/network/telephony/NetworkScanHelper.java

        /**
         * Performs a network scan for the given type {@code type}.
         * {@link #NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS} is recommended if modem supports
         * {@link TelephonyManager#requestNetworkScan(
         * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}.
         *
         * @param type used to tell which network scan API should be used.
         */
        public void startNetworkScan(@NetworkQueryType int type) {
            if (type == NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS) {
                mNetworkScanFuture = SettableFuture.create();
                Futures.addCallback(mNetworkScanFuture, new FutureCallback<List<CellInfo>>() {
                    @Override
                    public void onSuccess(List<CellInfo> result) {
                        onResults(result);
                        onComplete();
                    }
    
                    @Override
                    public void onFailure(Throwable t) {
                        if (t instanceof CancellationException) {
                            return;
                        }
                        int errCode = Integer.parseInt(t.getMessage());
                        onError(errCode);
                    }
                }, MoreExecutors.directExecutor());
                mExecutor.execute(new NetworkScanSyncTask(
                        mTelephonyManager, (SettableFuture) mNetworkScanFuture));
            } else if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS) {
                if (mNetworkScanRequester != null) {
                    return;
                }
                mNetworkScanRequester = mTelephonyManager.requestNetworkScan(
                        createNetworkScanForPreferredAccessNetworks(),
                        mExecutor,
                        mInternalNetworkScanCallback);
                if (mNetworkScanRequester == null) {
                    onError(NetworkScan.ERROR_RADIO_INTERFACE_ERROR);
                }
            }
        }
    
        private static final class NetworkScanSyncTask implements Runnable {
            private final SettableFuture<List<CellInfo>> mCallback;
            private final TelephonyManager mTelephonyManager;
    
            NetworkScanSyncTask(
                    TelephonyManager telephonyManager, SettableFuture<List<CellInfo>> callback) {
                mTelephonyManager = telephonyManager;
                mCallback = callback;
            }
    
            @Override
            public void run() {
                final CellNetworkScanResult result = mTelephonyManager.getAvailableNetworks();
                if (result.getStatus() == CellNetworkScanResult.STATUS_SUCCESS) {
                    final List<CellInfo> cellInfos = result.getOperators()
                            .stream()
                            .map(operatorInfo
                                    -> CellInfoUtil.convertOperatorInfoToCellInfo(operatorInfo))
                            .collect(Collectors.toList());
                    Log.d(TAG, "Sync network scan completed, cellInfos = "
                            + CellInfoUtil.cellInfoListToString(cellInfos));
                    mCallback.set(cellInfos);
                } else {
                    final Throwable error = new Throwable(
                            Integer.toString(convertToScanErrorCode(result.getStatus())));
                    mCallback.setException(error);
                    Log.d(TAG, "Sync network scan error, ex = " + error);
                }
            }
        }
    

    2 手动搜网Framework

    2.1 Framework涉及到的类

    frame_class.png

    四个主要的类:
    TelephonyManager : 提供API给应用。
    PhoneInterfaceManager : 实现ITelephony接口,实现对Phone的控制操作。其内部类MainThreadHandler继承于Handler。
    GsmCdmaPhone : Phone,其父类继承于Handler。
    RIL : RILJ,提供API给Phone

    2.2 流程图

    这些类的工作流程一般如下:


    getAvailableNetworks_framework.png

    Step1: 通过TelephonyManager API调用Telephony Service(PhoneInterfaceManager)
    Step2: 通过Telephony Service调用控制Phone
    Step3: 通过Phone调用RILJ
    Step4: RILJ通过HIDL实现对RILD的调用
    Step5: RILD通过RadioResponse把返回值反馈给Phone
    Step6: Phone把返回值传给Telephony Service
    Step7: Telephony Service把返回值通知给应用程序

    3 手动搜网RILD

    3.1 流程图

    rild.png

    3.2 AT Command

    可参考3GPP TS 27.007之7.3 PLMN selection +COPS
    如下是联通卡搜网的一个结果示例:

    AT> AT+COPS=?
    AT< +COPS: (1,"China Unicom","CU-GSM","46001","25C7",7),(1,"China Unicom","CU-GSM","46001","A5AB",2),(2,"China Unicom","CU-GSM","46001","77B600",11),(3,"46011","46011","46011","7C06",7),(3,"China Mobile","CMCC","46000","2441",7),(3,"46011","46011","46011","77B600",11),,(0-3),(0-2)
    AT< OK
    

    界面效果如下:
    China Unicom 4G (Available)
    China Unicom 3G (Available)
    China Unicom 5G (Current)
    China Telecom 4G (Forbidden)
    China Mobile 4G (Forbidden)
    China Telecom 5G (Forbidden)

    版权声明:本文为 无痕1024 原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://www.jianshu.com/p/e56e83ca520d

    相关文章

      网友评论

          本文标题:Android S源码手动搜网流程

          本文链接:https://www.haomeiwen.com/subject/ddsrjrtx.html