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 requestNetwork(NetworkRequest networkRequest, LocalLog log) {
    //与上文中定义APN优先级一样,根据NetworkRequest的NetworkCapabilities得到对应的ApnId
    final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest);
    //判断DcTracker能否处理该APN
    final ApnContext apnContext = mApnContextsById.get(apnId);
    log.log("DcTracker.requestNetwork for " + networkRequest + " found " + apnContext);
    //能够处理时,就调用ApnContext的incRefCount方法
    if (apnContext != null) apnContext.incRefCount(log);
}

上面的代码中唯一的疑点是mApnContextsById是如何定义的?这就必须提及DcTracker的构造函数了。

public DcTracker(Phone phone) {
    .......
    //初始化APN Context
    initApnContexts();
    .......
}

private void initApnContexts() {
    String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray(
                com.android.internal.R.array.networkAttributes);
    for (String networkConfigString : networkConfigStrings) {
        NetworkConfig networkConfig = new NetworkConfig(networkConfigString);
        ApnContext apnContext = null;

        switch (networkConfig.type) {
         case ConnectivityManager.TYPE_MOBILE:
                apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig);
                break;
         case ConnectivityManager.TYPE_MOBILE_MMS:
                apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig);
                break;
         ......
    }
    ..........      
}

private ApnContext addApnContext(String type, NetworkConfig networkConfig) {
    ApnContext apnContext = new ApnContext(mPhone, type, LOG_TAG, networkConfig, this);
    mApnContexts.put(type, apnContext);
    mApnContextsById.put(ApnContext.apnIdForApnName(type), apnContext);
    mPrioritySortedApnContexts.add(apnContext);
    return apnContext;
}

从上面的代码可以看出,mApnContextsById中的Apn记录也是从config.xml中读取出来的,因此ApnContext的incRefCount方法可以得到执行:

public void incRefCount(LocalLog log) {
    synchronized (mRefCountLock) {
        if (mLocalLogs.contains(log)) {
            log.log("ApnContext.incRefCount has duplicate add - " + mRefCount);
        } else {
            mLocalLogs.add(log);
            log.log("ApnContext.incRefCount - " + mRefCount);
        }
        //每种APN类型只激活一次
        if (mRefCount++ == 0) {
            //这里重新调用DcTracker的setEnabled函数,传入的参数之一是可用的ApnId
            //也就是说这一类APN是可以使用的,例如如果激活的ApnId为DctConstants.APN_DEFAULT_ID
            //那么所有具有default属性的APN均可以使用了
            mDcTracker.setEnabled(apnIdForApnName(mApnType), true);
        }
    }
}

最后我们来看看DcTracker的setEnabled函数。

public void setEnabled(int id, boolean enable) {
    //发送消息给内部handler处理,将调用onEnableApn进行处理
    Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN);
    msg.arg1 = id;
    msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
    sendMessage(msg);
}

private void onEnableApn(int apnId, int enabled) {
    ApnContext apnContext = mApnContextsById.get(apnId);
    if (apnContext == null) {
        loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
        return;
    }
    // TODO change our retry manager to use the appropriate numbers for the new APN
    if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
    //更新apnContext的state
    //DependencyMet由config.xml得到,均为true
    applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet());
}

private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
    boolean cleanup = false;
    boolean trySetup = false;
    ........
    //初始时,apnContext not ready
    if (apnContext.isReady()) {
        ......
    } else {
        //传入参数中,enabled与met均为true
        if (enabled && met) {
            if (apnContext.isEnabled()) {
                apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
            } else {
                apnContext.setReason(Phone.REASON_DATA_ENABLED);
            }
            if (apnContext.getState() == DctConstants.State.FAILED) {
                apnContext.setState(DctConstants.State.IDLE);
            }
            trySetup = true;
        }
    }

    //完成准备工作!!!拨号依赖于此条件
    apnContext.setEnabled(enabled);
    apnContext.setDependencyMet(met);

    if (cleanup) cleanUpConnection(true, apnContext);
    if (trySetup) {
        apnContext.resetErrorCodeRetries();
        //会触发拨号操作,当然此时没插卡,数据业务开关也没打开,不会通过RIL发送消息给modem
        trySetupData(apnContext);
    }
}

至此,TelephonyNetworkFactory再次完成了一部分数据拨号前的准备工作,激活了一个类型的APN。

3 DcTracker装载卡对应的APN信息
从这一节的标题就知道,我们要开始分析插入卡后的流程了,毕竟拨号是离不开SIM卡的(网络运营商提供的虚拟卡暂不考虑)。

我们先看看框架是如何知道手机中插入了卡。
卡实际上可以看做一种硬件设备,当卡插入手机后,会产生相应的电信号,触发相应的驱动工作。当然,这不是我们关注的重点,我们只需要知道的是,当检测到卡后,modem将主动上报RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED事件。

RIL收到该事件后,将通知其观察者:

case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
    if (RILJ_LOGD) unsljLog(response);

    if (mIccStatusChangedRegistrants != null) {
        mIccStatusChangedRegistrants.notifyRegistrants();
    }
    break;

那么谁是该事件的观察者呢?我们知道在PhoneFactory的makeDefaultPhone中,创建过UiccController,看看UiccController构造函数的片段:

private UiccController(Context c, CommandsInterface []ci) {
    ..........
    for (int i = 0; i < mCis.length; i++) {
        Integer index = new Integer(i);
        //从这里可以看出UiccController将监听IccStatusChanged事件
        //监听到IccStatusChanged发送EVENT_ICC_STATUS_CHANGED消息给自己处理
        mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
        .............
    }
}
@Override
public void handleMessage (Message msg) {
    .......
    switch (msg.what) {
        case EVENT_ICC_STATUS_CHANGED:
            if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
            //利用RIL从modem获取卡信息,获取到卡信息后,发送EVENT_GET_ICC_STATUS_DONE给自己处理
            mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
            break;
        case EVENT_GET_ICC_STATUS_DONE:
            if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
            //获取到卡信息后,进行处理
            onGetIccCardStatusDone(ar, index);
            break;
        ......
    }
    .......
}

private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
    ........
    IccCardStatus status = (IccCardStatus)ar.result;
    //利用获取的卡信息,形成抽象的卡对象
    if (mUiccCards[index] == null) {
        //Create new card
        mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index);
    } else {
        //Update already existing card
        mUiccCards[index].update(mContext, mCis[index] , status);
    }

    if (DBG) log("Notifying IccChangedRegistrants");
    //通知自己的观察者
    mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
}

UiccController的观察者比较多,其中就有我们关注的DcTracker,在DcTracker的构造函数中,就有如下片段:

public DcTracker(Phone phone) {
    .......
    mUiccController = UiccController.getInstance();
    //收到UiccController的通知后,将发送EVENT_ICC_CHANGED给自己处理,调用函数为onUpdateIcc
    mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null);
    .......
}

private void onUpdateIcc() {
    if (mUiccController == null ) {
        return;
    }

    //利用UiccController获取卡信息
    IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP);

    IccRecords r = mIccRecords.get();
    if (r != newIccRecords) {
        if (r != null) {
            log("Removing stale icc objects.");
            r.unregisterForRecordsLoaded(this);
            mIccRecords.set(null);
        }
        if (newIccRecords != null) {
            if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
                log("New records found.");
                mIccRecords.set(newIccRecords);
                //监听卡信息是否载入完成,IccRecords的子类负责通知
                newIccRecords.registerForRecordsLoaded(
                    this, DctConstants.EVENT_RECORDS_LOADED, null);
                SubscriptionController.getInstance().setSimProvisioningStatus(
                    SubscriptionManager.SIM_PROVISIONED, mPhone.getSubId());
            }
        } else {
            onSimNotReady();
        }
    }
}

当DcTracker监听到卡信息载入完成后,处理EVENT_RECORDS_LOADED事件:

..........
case DctConstants.EVENT_RECORDS_LOADED:
    // If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on
    // onSubscriptionsChanged() when a valid subId is available.
    int subId = mPhone.getSubId();
    //卡载入完成,应该已经有了有效的subId
    if (SubscriptionManager.isValidSubscriptionId(subId)) {
        //调用该函数
        onRecordsLoadedOrSubIdChanged();
    } else {
        log("Ignoring EVENT_RECORDS_LOADED as subId is not valid: " + subId);
    }
    break;
........
private void onRecordsLoadedOrSubIdChanged() {
    ............
    //创建APN list
    createAllApnList();
    //从所有可用APN中,选择一个APN通过RIL发送给modem
    //选择顺序是IA(支持IA类型的APN)、prefer(用户选择的)、 default(支持default类型的)、 first(mApnSettings中的第一个)
    setInitialAttachApn();
    //判断modem的radio是否处于开启状态
    if (mPhone.mCi.getRadioState().isOn()) {
        if (DBG) log("onRecordsLoadedOrSubIdChanged: notifying data availability");
        //发送一个通知而已
        notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED);
    }
    //进行数据拨号,注意此时数据业务开关如果是开的,才能利用RIL发送信息给modem
    setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
}

我们看看createAllApnList函数:

private void createAllApnList() {
    .......
    mAllApnSettings = new ArrayList<ApnSetting>();
    IccRecords r = mIccRecords.get();
    String operator = (r != null) ? r.getOperatorNumeric() : "";
    String operator = (r != null) ? r.getOperatorNumeric() : "";
    if (operator != null) {
        //根据运营商构造selection语句
        String selection = "numeric = '" + operator + "'";
        String orderBy = "_id";

        //查询数据库
        Cursor cursor = mPhone.getContext().getContentResolver().query( Telephony.Carriers.CONTENT_URI, null, selection, null, orderBy);

        if (cursor != null) {
            if (cursor.getCount() > 0) {
                //该函数内部利用makeApnSettings函数,根据数据库字段,构造当前卡可以使用的Apn
                mAllApnSettings = createApnList(cursor);
            }
            cursor.close();
        }

        //增加紧急拨号类型的APN
        addEmergencyApnSetting();

        //删除重复的APN
        dedupeApnSettings();

        if (mAllApnSettings.isEmpty()) {
            mPreferredApn = null;
        } else {
            //获取prefer APN(即优先使用的APN)
            //根据subId匹配,将数据库中对应的APN按名称ASC(升序)排列后,取出数据库中第一个APN的id
            //轮询当前卡的AllApnSettings,匹配id并且能满足NetworkRequest要求的APN就是prefer APN
            //用户不设置的话,初始时应该是没有的
            mPreferredApn = getPreferredApn();
            //优选APN不适用于当期运营商的话,则不设定优选APN
            if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
                mPreferredApn = null;
                setPreferredApn(-1);
            }
        }
    }
    //调用RIL的接口setDataProfile,向modem发送dataProfie,即发送当期卡可用的APN信息给modem
    setDataProfilesAsNeeded();
}

至此,我们做好了数据拨号前的所有工作,用户点击数据业务开关后,就可以开始拨号流程了。
当然上述过程过于繁杂,涉及的细节比较多,因此还是需要整理一下流程图和类图:
Android7.0 数据拨号前的准备工作_第1张图片
流程图对应链接


类图对应链接

结束语
以上的流程图和类图都是比较简易的。
实际终端的开机过程,可能和流程图存在一定时序上的偏差,但大致流程应该一致;类图并没有严格分析每个类之间的关系,仅仅描述了主要类的关系。

最后需要说明的是,目前的逻辑都是按照Android 7.0原生流程来分析的,实际终端的软件版本应该与此有些差异。不论MTK还是Qualcomm应该都会根据自己的芯片能力,对原生流程进行修改。
举例来说,原生流程中,PhoneSwitcher直接通过setDataAllowed激活Phone的数据拨号能力,然后立马就通知TelephonyNetworkFactory。
这实在是高估了底层芯片的能力,自己目前还没有拿到Qualcomm和MTK的代码,但觉得这里应该会像Android6.0一样,必须等底层芯片返回数据能力设置成功的信息后,才会通知TelephonyNetworkFactory。甚至考虑到底层的异常,厂商应该还是会引入状态机进行控制。

你可能感兴趣的:(android)