Android S源码手动搜网流程

1 手动搜网应用程序

1.1 MobileNetworkSettings入口

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

        
            
                
                
                
                
                
                
            
        

紧接着的调用关系,会使用到布局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



    

    

        

        

        

        

        
        
        

        

            

            
        

        
        
        

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>() {
                @Override
                public void onSuccess(List 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> mCallback;
        private final TelephonyManager mTelephonyManager;

        NetworkScanSyncTask(
                TelephonyManager telephonyManager, SettableFuture> callback) {
            mTelephonyManager = telephonyManager;
            mCallback = callback;
        }

        @Override
        public void run() {
            final CellNetworkScanResult result = mTelephonyManager.getAvailableNetworks();
            if (result.getStatus() == CellNetworkScanResult.STATUS_SUCCESS) {
                final List 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源码手动搜网流程)