背景
在介绍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();
}
至此,我们做好了数据拨号前的所有工作,用户点击数据业务开关后,就可以开始拨号流程了。
当然上述过程过于繁杂,涉及的细节比较多,因此还是需要整理一下流程图和类图:
流程图对应链接
类图对应链接
结束语
以上的流程图和类图都是比较简易的。
实际终端的开机过程,可能和流程图存在一定时序上的偏差,但大致流程应该一致;类图并没有严格分析每个类之间的关系,仅仅描述了主要类的关系。
最后需要说明的是,目前的逻辑都是按照Android 7.0原生流程来分析的,实际终端的软件版本应该与此有些差异。不论MTK还是Qualcomm应该都会根据自己的芯片能力,对原生流程进行修改。
举例来说,原生流程中,PhoneSwitcher直接通过setDataAllowed激活Phone的数据拨号能力,然后立马就通知TelephonyNetworkFactory。
这实在是高估了底层芯片的能力,自己目前还没有拿到Qualcomm和MTK的代码,但觉得这里应该会像Android6.0一样,必须等底层芯片返回数据能力设置成功的信息后,才会通知TelephonyNetworkFactory。甚至考虑到底层的异常,厂商应该还是会引入状态机进行控制。