1. 程式人生 > >Android7.0 資料撥號前的準備工作

Android7.0 資料撥號前的準備工作

背景
在介紹PhoneApp的建立過程時,我們知道為了支援雙卡手機,PhoneFactory建立了兩個Phone物件。
然而由於通訊制式、功耗等的限制,目前底層的晶片廠商規定modem工作於DSDS模式下,於是同一時間內只有一個Phone具有上網的能力。
本文旨在揭示啟用Phone撥號能力的過程,即講述資料撥號前的準備工作。

版本
android 7.0

1 TelephonyProvider的啟動
資料業務在建立之前,必須有可用的APN,因此我們首先看看Android 7.0中APN載入的過程。
之前分析PhoneApp啟動過程時,我們知道PhoneApp的onCreate函式是靠ActivityThread.java中的handleBindApplication函式呼叫的。

private void handleBindApplication(AppBindData data) {
    ........
    try {
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;

        if (!data.restrictedBackupMode) {
            if (!ArrayUtils.isEmpty(data.providers)) {
                //載入App中的provider
installContentProviders(app, data.providers); ........... } } try { mInstrumentation.onCreate(data.instrumentationArgs); } catch (Exception e) { ......... } try { //呼叫App的onCreate函式
mInstrumentation.callApplicationOnCreate(app); } catch (Exception e) { .............. } } finally { ............. } }

從上面的程式碼,我們知道在PhoneApp的onCreate被呼叫前,先載入了PhoneApp中的ContentProvider(PM解析xml得到這種包含關係)。

private void installContentProviders(Context context, List<ProviderInfo> providers) {
    ........
    for (ProviderInfo cpi : providers) {
        ..........
        //依次安裝provider
        IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
        ............
    }

    try {
        //釋出provider
        ActivityManagerNative.getDefault().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
}

從TelephonyProvider的AndroidManifest.xml,我們知道TelephonyProvider就是執行在Phone程序中的,因此結合上面的程式碼,可以得出結論:
TelephonyProvider將在PhoneApp的onCreate被呼叫前被載入。

Android7.0 TelephonyProvider啟動後的過程,與Android6.0中一致。
之前的blog分析Android6.0中APN載入過程時,已經做過描述了,其實就是建立資料庫、解析xml檔案並存入資料庫的過程,此處不再贅述。

2 設定具有撥號能力的Phone
我們回憶一下PhoneApp啟動後,利用PhoneFactory的makeDefaultPhone建立物件的程式碼,其中:

.........
//建立了一個PhoneSwitcher
sPhoneSwitcher = new PhoneSwitcher(MAX_ACTIVE_PHONES, numPhones,
                        sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces,
                        sPhones);
.........
sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
for (int i = 0; i < numPhones; i++) {
    //建立了兩個TelephonyNetworkFactory,分別與每個Phone關聯起來
    sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
        sPhoneSwitcher, sc, sSubscriptionMonitor, Looper.myLooper(),
        sContext, i, sPhones[i].mDcTracker);
}

在剛開機時,不插卡的情況下,上面程式碼提及的PhoneSwitcher和TelephonyNetworkFactory將決定具有撥號能力的Phone。
我們在這裡先分析不插卡情況下的流程,主要原因是:
框架對卡資訊有記錄,將會根據記錄資訊改變具有撥號能力的Phone。這個過程是通過呼叫Phone程序提供的介面完成的,我們以後再做分析。

2.1 PhoneSwitcher
我們先來看看PhoneSwitcher:

//PhoneSwitcher繼承自Handler
public class PhoneSwitcher extends Handler {
    ......
    public PhoneSwitcher(......) {
        ........
        //建立NetworkCapabilities,為建立NetworkFactory作準備
        //NetworkCapabilities決定了NetworkFactory可以處理的Network Request種類
        NetworkCapabilities netCap = new NetworkCapabilities();
        netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_RCS);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
        netCap.setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);

        //建立了一個NetworkFactory物件
        NetworkFactory networkFactory = new PhoneSwitcherNetworkRequestListener(looper, context,
                netCap, this);
        //每個NetworkFactory僅能處理分數比自己低的NetworkRequest
        //這裡設定分數為101,將能夠處理所有的request
        networkFactory.setScoreFilter(101);
        //註冊該NetworkFactory物件
        networkFactory.register();
    }
}

上面的程式碼涉及到了很多內容,以後有機會再分析,此時我們僅需要有一個映像就是:
PhoneSwitcher建立了一個能夠處理所有Network Request的NetworkFactory(實際上是子類),並呼叫了register方法。

我們來看看NetworkFactory的register方法:

//NetworkFactory繼承Handler
public class NetworkFactory extends Handler {
    ........
    public void register() {
        if (DBG) log("Registering NetworkFactory");
        if (mMessenger == null) {
            //構造Messenger物件,其中包含Handler
            mMessenger = new Messenger(this);
            //呼叫ConnectivityManager的registerNetworkFactory方法
            ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
        }
    }
    ..........
}

繼續跟進ConnectivityManager中的函式:

public static ConnectivityManager from(Context context) {
    return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
}

public void registerNetworkFactory(Messenger messenger, String name) {
    try {
        //可以看到將呼叫用mService的registerNetworkFactory函式
        mService.registerNetworkFactory(messenger, name);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

mService的型別為IConnectivityManager,其實是ConnectivityService的Binder通訊的服務端代理,因此上述程式碼最終將呼叫到ConnectivityService的registerNetworkFactory函式。

ConnectivityService是開機時,由SystemServer載入的,這裡我們不分析ConnectivityService啟動的過程,以後有機會單獨介紹ConnectivityService。這裡我們只需要知道ConnectivityService主要負責管理Android中的各種網路。
我們看看ConnectivityService的registerNetworkFactory函式:

@Override
public void registerNetworkFactory(Messenger messenger, String name) {
    //許可權檢查
    enforceConnectivityInternalPermission();
    //構造NetworkFactoryInfo, 該變數用於在ConnectivityService中代表註冊的NetworkFactory
    //注意Messager中,包含註冊NetworkFactory內部的Handler
    NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
    //傳送訊息給給內部的Handler處理,將並行的介面呼叫變為序列的訊息處理
    mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
}

ConnectivityService內部的handler將呼叫handleRegisterNetworkFactory處理EVENT_REGISTER_NETWORK_FACTORY訊息:

............
case EVENT_REGISTER_NETWORK_FACTORY: {
    handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj);
    break;
}
...........
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
    if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
    //以鍵值對的方式,儲存NetworkFactory的messenger和對應的NetworkFactoryInfo
    mNetworkFactoryInfos.put(nfi.messenger, nfi);
    //呼叫AsyncChannel的connect方法,將ConnectivityService的TrackerHandler與NetworkFactory的Messenger聯絡起來
    nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
}

我們看看AsyncChannel的connect方法:

//此處傳遞的srcHandler是ConnectivityService的mTrackerHandler
//dstMessenger為NetworkFactory內部的Messenger
public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
    if (DBG) log("connect srcHandler to the dstMessenger  E");

    // We are connected
    connected(srcContext, srcHandler, dstMessenger);

    // Tell source we are half connected
    replyHalfConnected(STATUS_SUCCESSFUL);

    if (DBG) log("connect srcHandler to the dstMessenger X");
}

public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
    if (DBG) log("connected srcHandler to the dstMessenger  E");

    // Initialize source fields
    mSrcContext = srcContext;
    mSrcHandler = srcHandler;
    mSrcMessenger = new Messenger(mSrcHandler);

    // Initialize destination fields
    mDstMessenger = dstMessenger;
    //監聽目的端斷開
    linkToDeathMonitor();
    if (DBG) log("connected srcHandler to the dstMessenger X");
}

看到connnected函式,我們知道每個NetworkFactory註冊後,ConnectivityService將維護對應的NetworkFactoryInfo,對應的鍵值為NetworkFactory中的Messenger物件。
每個NetworkFactoryInfo中有一個AsyncChannel物件,該物件的源端Messenger包裹著ConnectivityService的mTrackerHandler,目的端Messenger為註冊NetworkFactory的Messenger。
ConnectivityService這麼做的目的是:簡化ConnectivityService與每個NetworkFactory通訊時的函式呼叫。

//這裡傳送CMD_CHANNEL_HALF_CONNECTED給ConnectivityService的mTrackerHandler
//replyTo NetworkFactory中的Messenger
private void replyHalfConnected(int status) {
    Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
    msg.arg1 = status;
    msg.obj = this;
    msg.replyTo = mDstMessenger;
    if (!linkToDeathMonitor()) {
        // Override status to indicate failure
        msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
    }

    mSrcHandler.sendMessage(msg);
}

根據上面的程式碼,我們知道接下來應該是ConnectivityService的mTrackerHandler處理CMD_CHANNEL_HALF_CONNECTED事件。
mTrackerHandler的型別為ConnectivityService的內部類NetworkStateTrackerHandler:

private class NetworkStateTrackerHandler extends Handler {
    ...........
    @Override
    public void handleMessage(Message msg) {
        //這裡的程式碼寫法還是很讚的,特意看了Android6.0之前的程式碼
        //在Android6.0之前,是在一個handleMessage中,根據msg.what使用大量的switch-case語句
        //現在這樣寫,雖然本質上仍是大量的switch-case,但至少作了個分類
        if (!maybeHandleAsyncChannelMessage(msg) && !maybeHandleNetworkMonitorMessage(msg)) {
             maybeHandleNetworkAgentMessage(msg);
        }
    }
    .......
}

在這裡我們看看maybeHandleAsyncChannelMessage:

private boolean maybeHandleAsyncChannelMessage(Message msg) {
    switch (msg.what) {
        //說實話這個程式碼寫的辣眼睛
        //自己寫switch-case,一直將default寫在最後,導致自己認為default是可以匹配所有的case
        //實際上,當剩餘的case匹配不上時,default才會去匹配,default寫在之前之後,沒有關係
        default:
            return false;
        case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
            //這裡我們呼叫這個函式
            handleAsyncChannelHalfConnect(msg);
            break;
        }
        case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
            NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
            if (nai != null) nai.asyncChannel.disconnect();
            break;
        }
        case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
            handleAsyncChannelDisconnected(msg);
            break;
        }
    }
    return true;
}

private void handleAsyncChannelHalfConnect(Message msg) {
    AsyncChannel ac = (AsyncChannel) msg.obj;
    //從前面的程式碼,我們知道msg.replyTo為NetworkFactory對應的Messenger
    if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
            if (VDBG) log("NetworkFactory connected");
            // A network factory has connected.  Send it all current NetworkRequests.
            //這裡的NetworkRequest等下說明
            for (NetworkRequestInfo nri : mNetworkRequests.values()) {
                //NetworkRequest分為監聽網路用的,和申請網路用的
                //僅處理申請網路用的
                if (!nri.isRequest()) continue;
                //判斷NetworkRequest是否有對應的NetworkAgentInfo
                //當一個網路建立後,將會生成對應的NetworkAgent註冊到ConnectivityService
                //這裡是取出NetworkRequest對應的NetworkAgentInfo
                NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
                //將CMD_REQUEST_NETWORK的訊息傳送給NetworkFactory,同時指定該request的分數
                ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
                            (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
            }
        } else {
            loge("Error connecting NetworkFactory");
            mNetworkFactoryInfos.remove(msg.obj);
        }
    } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
       //這裡是傳送給NetworkAgent的訊息,我們暫時不關注
        .........        
    }
}

上面的程式碼其實就是發訊息給NetworkFactory。這裡存在的疑點是:1、開機時是否有NetworkRequest?
2、傳送CMD_REQUEST_NETWORK時為什麼要攜帶分數?

我們先來分析第一個問題:

//建構函式
public ConnectivityService(.......) {
    if (DBG) log("ConnectivityService starting up");

    //初始時建立了DefaultRequest
    mDefaultRequest = createInternetRequestForTransport(-1);
    //建立對應的NetworkRequestInfo
    NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder(), NetworkRequestType.REQUEST);
    //按鍵值對儲存
    mNetworkRequests.put(mDefaultRequest, defaultNRI);
    mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
    ............
}

//初始時,ConnectivityService建立NetworkRequest傳入的引數為-1
private NetworkRequest createInternetRequestForTransport(int transportType) {
    NetworkCapabilities netCap = new NetworkCapabilities();
    netCap.addCapability(NET_CAPABILITY_INTERNET);
    netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
    if (transportType > -1) {
        netCap.addTransportType(transportType);
    }
    return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId());
}

從上面的程式碼,我們知道了開機後,ConnectivityService中預設就會存在一個NetworkRequest,於是每當一個新的NetworkFactory註冊到ConnectivityService後,都會處理這個預設的NetworkRequest。

現在我們再來回答第二個問題,為什麼傳送CMD_REQUEST_NETWORK時,需要攜帶分數。
這個問題其實涉及了Android框架,管理整個網路的架構。具體的情況,今後介紹ConnectivityService時,會詳細介紹。
在這裡直接丟擲近似的答案:Android通過ConnectivityService管理所有的網路,每一種網路都有各自的NetworkFactory。當NetworkFactory收到NetworkRequest後,將建立實際的網路物件。ConnectivityService用NetworkAgent和NetworkAgentInfo來抽象實際的網路物件的一些特性(還有其它的物件,例如Network,LinkProperties等共同抽象網路)。
然而,同一個裝置在同一時間內不需要連線多個網路。比如說,使用者的目的就是上網,但WiFi和行動網路均能滿足使用者上網的需求,因此裝置沒有必要同時連線WiFi和行動網路。因此,Android需要一種機制來權衡各種網路的是否應該保留。
為此android引入了分數的概念,當兩個網路能同時滿足一個NetworkRequest時,分數高者就留下。根據這個規則,我們其實也知道如果兩個網路分別滿足不同的NetworkRequest時,是可以共存的。
以上是基本的結論,今後分析ConnectivityService時,會分析對應的原始碼。

知道原理後,現在回過頭來看看傳送CMD_REQUEST_NETWORK時,為什麼要攜帶分數。
當訊息傳送給NetworkFactory後,NetworkFactory如果能滿足NetworkRequest的需求,需要生成對應當NetworkAgent註冊到ConnectivityService。如果這個新生成的NetworkAgent的分數,比之前滿足NetworkRequest的已存在的NetworkAgent分數低,那麼這個NetworkAgent將被處理掉。
因此,與其浪費資源生成一個無用的NetworkAgent,不如一開始就讓NetworkFactory通過比較分數,不處理高分NetworkRequest。
這種設計類似於從聲源阻止噪聲吧!

回答完問題後,讓我們繼續回到之前ConnectivityService的流程,接下來看看AsyncChannel如何傳送訊息:

//一層層的sendMessage呼叫,最後會呼叫到這個sendMessage
public void sendMessage(Message msg) {
    //根據前面的分析,我們知道ConnectivityService中NetworkFactoryInfo的AsyncChannel中
    //mSrcMessenger中包裹的是mTrackerHandler
    msg.replyTo = mSrcMessenger;
    try {
        //DstMessenger中包裹的是NetworkFactory中的handler
        //binder通訊,發往了NetworkFactory
        mDstMessenger.send(msg);
    } catch (RemoteException e) {
        replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
    }
}

至此,訊息終於又發回了PhoneSwitcher中建立的NetworkFactory,訊息的處理由父類NetworkFactory處理:

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case CMD_REQUEST_NETWORK: {
            //呼叫該函式處理
            handleAddRequest((NetworkRequest)msg.obj, msg.arg1);
            break;
        }
        case CMD_CANCEL_REQUEST: {
            handleRemoveRequest((NetworkRequest) msg.obj);
            break;
        }
        case CMD_SET_SCORE: {
            handleSetScore(msg.arg1);
            break;
        }
        case CMD_SET_FILTER: {
            handleSetFilter((NetworkCapabilities) msg.obj);
            break;
        }
    }
}

@VisibleForTesting
protected void handleAddRequest(NetworkRequest request, int score) {
    //判斷之前是否處理過該NetworkRequest
    NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
    if (n == null) {
        if (DBG) log("got request " + request + " with score " + score);
        n = new NetworkRequestInfo(request, score);
        mNetworkRequests.put(n.request.requestId, n);
    } else {
        if (VDBG) log("new score " + score + " for exisiting request " + request);
        //對於處理過的NetworkRequest,僅更新器分數
        //原因是:ConnectivityService中匹配該NetworkRequest的NetworkAgent可能變化,所以需要更新分數
        n.score = score;
    }
    if (VDBG) log("  my score=" + mScore + ", my filter=" + mCapabilityFilter);

    //評估NetworkRequest
    evalRequest(n);
}

private void evalRequest(NetworkRequestInfo n) {
    if (VDBG) log("evalRequest");
    //n.requested == false表示該request未被處理過
    //n.score < mScore表示request的分數小於NetworkFactory的分數(子類定義)
    //satisfiedByNetworkCapabilities是為了判斷NetworkFactory(子類)的網路能力能滿足NetworkRequest
    //acceptRequest函式衡返回true,這是留給子類覆蓋用的吧,一般沒有覆蓋
    if (n.requested == false && n.score < mScore &&
            n.request.networkCapabilities.satisfiedByNetworkCapabilities(
            mCapabilityFilter) && acceptRequest(n.request, n.score)) {
        if (VDBG) log("  needNetworkFor");
        //進入子類的實現
        needNetworkFor(n.request, n.score);
        n.requested = true;
    } else if (n.requested == true &&
            (n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities(
            mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false)) {
        if (VDBG) log("  releaseNetworkFor");

        releaseNetworkFor(n.request);
        n.requested = false;
    } else {
        if (VDBG) log("  done");
    }
}

繞了一圈,我們現在可以看看PhoneSwitcher中建立的NetworkFactory的needNetworkFor函式:

@Override
protected void needNetworkFor(NetworkRequest networkRequest, int score) {
    if (VDBG) log("needNetworkFor " + networkRequest + ", " + score);
    Message msg = mPhoneSwitcher.obtainMessage(EVENT_REQUEST_NETWORK);
    msg.obj = networkRequest;
    //傳送訊息給自己的handler處理,將呼叫PhoneSwitcher中的onRequestNetwork處理
    msg.sendToTarget();
}
private void onRequestNetwork(NetworkRequest networkRequest) {
    //利用NetworkRequest構造DcRequest
    final DcRequest dcRequest = new DcRequest(networkRequest, mContext);
    //之前沒有處理過的dcRequest,才會進行處理
    if (mPrioritizedDcRequests.contains(dcRequest) == false) {
        mPrioritizedDcRequests.add(dcRequest);
        //根據優先順序進行排序
        Collections.sort(mPrioritizedDcRequests);
        //評估,REQUESTS_CHANGED的值為true
        onEvaluate(REQUESTS_CHANGED, "netRequest");
    }
}

這裡的唯一的問題就是“根據優先順序排序”的概念。
我們花點時間來看看DcRequest這個類:

public class DcRequest implements Comparable<DcRequest> {
    ..........
    public DcRequest(NetworkRequest nr, Context context) {
        //初始化優先順序排序規則
        initApnPriorities(context);
        networkRequest = nr;
        //從NetworkReqeust得出對應的匹配APN id
        apnId = apnIdForNetworkRequest(networkRequest);
        //得到這個NetworkReqeust的優先順序
        priority = priorityForApnId(apnId);
    }
    .........

    private void initApnPriorities(Context context) {
        synchronized (sApnPriorityMap) {
            //初始化優先順序配置僅用執行一次
            if (sApnPriorityMap.isEmpty()) {
                //解析xml檔案,得到配置資訊
                String[] networkConfigStrings = context.getResources().getStringArray(
                        com.android.internal.R.array.networkAttributes);
                for (String networkConfigString : networkConfigStrings) {
                    NetworkConfig networkConfig = new NetworkConfig(networkConfigString);
                    //從配置資訊中,得到apnId
                    final int apnId = ApnContext.apnIdForType(networkConfig.type);
                    //以鍵值對的方式,將apnId和優先順序資訊放入到sApnPriorityMap中
                    sApnPriorityMap.put(apnId, networkConfig.priority);
                }
            }
        }
    }
    .........
    private int apnIdForNetworkRequest(NetworkRequest nr) {
        NetworkCapabilities nc = nr.networkCapabilities;
        // For now, ignore the bandwidth stuff
        if (nc.getTransportTypes().length > 0 &&
                nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == false) {
            return APN_INVALID_ID;
        }

        int apnId = APN_INVALID_ID;

        boolean error = false;
        //其實就是根據NetworkRequest申請的NetworkCapbility,來決定對應的apnId
        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
            if (apnId != APN_INVALID_ID) error = true;
            apnId = APN_DEFAULT_ID;
        }
        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
            if (apnId != APN_INVALID_ID) error = true;
            apnId = APN_MMS_ID;
        }
        ......
        return apnId;
    }
    ..........
    public int compareTo(DcRequest o) {
        return o.priority - priority;
    }
}

從上面的程式碼,我們知道DcRequest其實就是根據xml中的配置檔案得到每個Apn對應的優先順序;然後,根據每個NetworkRequest需要的NetworkCapabilities得到對應的apnId;最終,根據apnId的優先順序,完成對NetworkRequest的優先順序排序。
其中,networkAttributes定義於frameworks/base/core/res/res/values/config.xml中:

<string-array translatable="false" name="networkAttributes">
    <item>"wifi,1,1,1,-1,true"</item>
    <item>"mobile,0,0,0,-1,true"</item>
    <item>"mobile_mms,2,0,2,60000,true"</item>
    <item>"mobile_supl,3,0,2,60000,true"</item>
    <item>"mobile_hipri,5,0,3,60000,true"</item>
    <item>"mobile_fota,10,0,2,60000,true"</item>
    <item>"mobile_ims,11,0,2,60000,true"</item>
    <item>"mobile_cbs,12,0,2,60000,true"</item>
    <item>"wifi_p2p,13,1,0,-1,true"</item>
    <item>"mobile_ia,14,0,2,-1,true"</item>
    <item>"mobile_emergency,15,0,2,-1,true"</item>
</string-array>

根據NetworkConfig的建構函式,我們看出每一行的第4位表示優先順序。結合DcReqeust中的compareTo函式,我們知道數字越大,優先順序越高,例如mobile_mms的優先順序要高於mobile:

public NetworkConfig(String init) {
    String fragments[] = init.split(",");
    name = fragments[0].trim().toLowerCase(Locale.ROOT);
    type = Integer.parseInt(fragments[1]);
    radio = Integer.parseInt(fragments[2]);
    priority = Integer.parseInt(fragments[3]);
    restoreTime = Integer.parseInt(fragments[4]);
    dependencyMet = Boolean.parseBoolean(fragments[5]);
}

現在繼續回到PhoneSwitcher處理NetworkRequest的流程中來,PhoneSwitcher根據優先順序對NetworkRequest排序後,將呼叫onEvaluate方法:

private void onEvaluate(boolean requestsChanged, String reason) {
    ........
    //此時,傳入的引數為true
    boolean diffDetected = requestsChanged;
    //檢測卡資訊是否發生變化,我們此時分析不插卡的流程,暫不關注這個
    //即使插了卡,也不影響當前流程
    ........
    if (diffDetected) {
        List<Integer> newActivePhones = new ArrayList<Integer>();

        //按優先順序依次處理DcRequest
        for (DcRequest dcRequest : mPrioritizedDcRequests) {
            //根據networkRequest中NetworkCapabilities攜帶的Specifier引數,決定phoneId
            int phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest);
            if (phoneIdForRequest == INVALID_PHONE_INDEX) continue;
            if (newActivePhones.contains(phoneIdForRequest)) continue;
            newActivePhones.add(phoneIdForRequest);
            //目前mMaxActivePhones的值為1,意味者找到優先順序最高的DcRequest對應phone後,結束迴圈
            if (newActivePhones.size() >= mMaxActivePhones) break;
        }
        ..........
        for (int phoneId = 0; phoneId < mNumPhones; phoneId++) {
            if (newActivePhones.contains(phoneId) == false) {
                //去啟用 無法處理最高優先順序DcRequest的phone 的資料撥號能力
                deactivate(phoneId);
            }
        }

        // only activate phones up to the limit
        for (int phoneId : newActivePhones) {
            //啟用 能處理最高優先順序DcRequest的phone 的資料撥號能力
            activate(phoneId);
        }
    }
}

private int phoneIdForRequest(NetworkRequest netRequest) {
    //在此流程中,specifier的值為空
    //一般傳送彩信,建立彩信網路時,才會指定specifier為對應卡的subId
    String specifier = netRequest.networkCapabilities.getNetworkSpecifier();
    int subId;

    if (TextUtils.isEmpty(specifier)) {
        //為空時,取subId為預設資料卡的subId
        //我們分析不插卡的流程時,mDefaultDataSubscription為初始值0
        subId = mDefaultDataSubscription;
    } else {
        subId = Integer.parseInt(specifier);
    }
    int phoneId = INVALID_PHONE_INDEX;
    if (subId == INVALID_SUBSCRIPTION_ID) return phoneId;

    for (int i = 0 ; i < mNumPhones; i++) {
        if (mPhoneSubscriptions[i] == subId) {
            //我們分析不插卡的流程時,phoneId最後取0
            //實際插卡情況,將有specifier來具體決定
            phoneId = i;
            break;
        }
    }
    return phoneId;
}

最後,我們來看看deactivate和activate函式:

private void deactivate(int phoneId) {
    PhoneState state = mPhoneStates[phoneId];
    if (state.active == false) return;
    //記錄對應phone的啟用狀態
    state.active = false;
    log("deactivate " + phoneId);
    state.lastRequested = System.currentTimeMillis();
    //mCommandsInterfaces[phoneId]其實就是RIL物件
    //這裡其實就是通過RIL傳送訊息給modem,取消對應phone的資料撥號能力
    mCommandsInterfaces[phoneId].setDataAllowed(false, null);
    //通知觀察者
    mActivePhoneRegistrants[phoneId].notifyRegistrants();
}

private void activate(int phoneId) {
    PhoneState state = mPhoneStates[phoneId];
    if (state.active == true) return;
    state.active = true;
    log("activate " + phoneId);
    state.lastRequested = System.currentTimeMillis();
    //同樣,通過RIL傳送訊息
    mCommandsInterfaces[phoneId].setDataAllowed(true, null);
    //通知觀察者
    mActivePhoneRegistrants[phoneId].notifyRegistrants();
}

PhoneSwitcher的上述流程,最終激活了一個Phone的資料撥號能力,完成撥號前的第一部分準備工作。

2.2 TelephonyNetworkFactory
PhoneSwitcher只是決定了那一個Phone具有撥號能力,在實際撥號前還需要啟用可用的APN。這一部分工作需要TelephonyNetworkFactory來主動承擔。

public class TelephonyNetworkFactory extends NetworkFactory {
    ..........
    public TelephonyNetworkFactory(.....) {
        super(looper, context, "TelephonyNetworkFactory[" + phoneId + "]", null);
        //建立內部的handler
        mInternalHandler = new InternalHandler(looper);

        //設定TelephonyNetworkFactory的網路能力,決定了它能處理的NetworkReqeust
        setCapabilityFilter(makeNetworkFilter(subscriptionController, phoneId));
        //NetworkFactory的分數為50
        setScoreFilter(TELEPHONY_NETWORK_SCORE);

        ............
        //建立時,TelephonyNetworkFactory是非啟用的
        mIsActive = false;
        //是PhoneSwitcher的觀察者
        mPhoneSwitcher.registerForActivePhoneSwitch(mPhoneId, mInternalHandler,
                EVENT_ACTIVE_PHONE_SWITCH, null);
        //監聽卡變化的情況
        ............
        //同樣註冊到ConnectivityService
        register();
    }

    private NetworkCapabilities makeNetworkFilter(SubscriptionController subscriptionController,
            int phoneId) {
        final int subscriptionId = subscriptionController.getSubIdUsingPhoneId(phoneId);
        return makeNetworkFilter(subscriptionId);
    }

    //指定了TelephonyNetworkFactory的NetworkCapabilities
    private NetworkCapabilities makeNetworkFilter(int subscriptionId) {
        NetworkCapabilities nc = new NetworkCapabilities();
        nc.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_RCS);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
        nc.setNetworkSpecifier(String.valueOf(subscriptionId));
        return nc;
    }
}

從上面的程式碼我們知道,在初始時每個Phone對應的TelephonyNetworkFactory的啟用態均是false,並且均註冊到了ConnectivityService。於是,與PhoneSwitcher一樣,TelephonyNetworkFactory也會收到ConnectivityService傳送的NetworkReqeust請求。
由於ConnectivityService建立的DefaultRequest只要求Internet能力,並且在沒有建立其它網路的條件下(沒有連線WiFi等網路),DefaultRequest的分數為0,因此兩個Phone對應的TelephonyNetworkFactory均會處理ConnectivityService傳送的NetworkReqeust請求。
與PhoneSwitcher一樣,我們看看TelephonyNetworkFactory的needNetworkFor函式:

@Override
public void needNetworkFor(NetworkRequest networkRequest, int score) {
    //傳送訊息,由onNeedNetworkFor函式處理
    Message msg = mInternalHandler.obtainMessage(EVENT_NETWORK_REQUEST);
    msg.obj = networkRequest;
    msg.sendToTarget();
}

private void onNeedNetworkFor(Message msg) {
    NetworkRequest networkRequest = (NetworkRequest)msg.obj;
    boolean isApplicable = false;
    LocalLog localLog = null;
    //當NetworkReqeust的specifier為空時
    if (TextUtils.isEmpty(networkRequest.networkCapabilities.getNetworkSpecifier())) {
        // request only for the default network
        localLog = mDefaultRequests.get(networkRequest);
        if (localLog == null) {
            localLog = new LocalLog(REQUEST_LOG_SIZE);
            localLog.log("created for " + networkRequest);
            mDefaultRequests.put(networkRequest, localLog);
            //只有default phone才能處理這個NetworkReqeust
            isApplicable = mIsDefault;
        }
    } else {
        //當NetworkReqeust的specifier不為空時,只要之前沒有處理過,就可以處理
        //因為在收到NetworkRequest時,父類的evalRequest中,已經通過NetworkCapabilities匹配過了
        localLog = mSpecificRequests.get(networkRequest);
        if (localLog == null) {
            localLog = new LocalLog(REQUEST_LOG_SIZE);
            mSpecificRequests.put(networkRequest, localLog);
            isApplicable = true;
        }
    }

    //只有TelephonyNetworkFactory處於啟用態,並且能夠處理時,才進入該分支
    if (mIsActive && isApplicable) {
        String s = "onNeedNetworkFor";
        localLog.log(s);
        log(s + " " + networkRequest);
        mDcTracker.requestNetwork(networkRequest, localLog);
    } else {
        String s = "not acting - isApp=" + isApplicable + ", isAct=" + mIsActive;
        localLog.log(s);
        log(s + " " + networkRequest);
    }
}

從上面的程式碼我們知道,在TelephonyNetworkFactory被啟用前,它收到NetworkRequest的請求,但不會進行實際操作,直到PhoneSwitcher完成了啟用Phone撥號能力的操作。

在TelephonyNetworkFactory的建構函式中,向PhoneSwitcher註冊了觀察物件,當發現Phone的啟用態改變後,將向內部handler傳送EVENT_ACTIVE_PHONE_SWITCH訊息。內部handler收到訊息後,將呼叫onActivePhoneSwitch進行處理。

private void onActivePhoneSwitch() {
    //根據PhoneSwitcher中記錄的phoneState決定自己是否active
    final boolean newIsActive = mPhoneSwitcher.isPhoneActive(mPhoneId);
    //自己的active狀態改變後,處理request
    if (mIsActive != newIsActive) {
        mIsActive = newIsActive;
        String logString = "onActivePhoneSwitch(" + mIsActive + ", " + mIsDefault + ")";
        if (DBG) log(logString);
        //mIsActive的值,決定了requestNetwork,還是releaseNetwork
        //android7.0中,defaultRequest與specificRequest分別裝在了不同的map中
        if (mIsDefault) {
            applyRequests(mDefaultRequests, (mIsActive ? REQUEST : RELEASE), logString);
        }
        applyRequests(mSpecificRequests, (mIsActive ? REQUEST : RELEASE), logString);
    }
}

從上面的程式碼,可以看出當PhoneSwitcher改變TelephonyNetworkFactory的啟用狀態後,TelephonyNetworkFactory將根據各自的狀態,呼叫applyRequests函式:

private void applyRequests(HashMap<NetworkRequest, LocalLog> requestMap, boolean action,
            String logStr) {
    for (NetworkRequest networkRequest : requestMap.keySet()) {
        LocalLog localLog = requestMap.get(networkRequest);
        localLog.log(logStr);
        if (action == REQUEST) {
            //我們關注active phone的操作
            mDcTracker.requestNetwork(networkRequest, localLog);
        } else {
            mDcTracker.releaseNetwork(networkRequest, localLog);
        }
    }
}

根據上面的程式碼,我們知道了流程走到了DcTracker。
DcTracker是PhoneFactory建立GsmCdmaPhone時,在GsmCdmaPhone內部建立的,與TelephonyNetworkFactory一樣,每個phone物件持有一個。

public GsmCdmaPhone(.....) {
    ........
    mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
    ........
}

TelephonyComponentFactory是一個單例物件:

public static TelephonyComponentFactory getInstance() {
    if (sInstance == null) {
        sInstance = new TelephonyComponentFactory();
    }
    return sInstance;
}

public DcTracker makeDcTracker(Phone phone) {
    return new DcTracker(phone);
}

我們回到撥號前的準備流程,看看DcTracker的requestNetwork函式:

public void req