Telephony解析之Phone启动流程

本文代码基于Android 9.0

概述

之前Telephony解析这篇文章总结了一下,Telephony在Android系统中的整体分层架构,那么接下来重点来学习Phone启动流程。即:Telephony应用框架层的启动

Phone实体是Telephony框架对象,可以向该对象发起各种通讯相关的请求,Phone对象是Telephony整个框架的核心,他负责与RIL层的交互。

Phone对象是在PhoneApp这个application初始化过程中被创建的

Telephony应用层之PhoneApp

PhoneApp简介

首先PhoneApp的主要功能是什么呢?

1.负责实例化创建Telephony应用框架层(phone),且和phone一起运行在com.android.phone进程中

2.管理(CallManager),控制通话相关的UI、功能操作、业务逻辑实现

Phone业务

1.CDMA 业务(支持CDMA的手机)
2.GSM 业务(支持GSM的手机)
3.IMS业务(支持IMS的手机)
4.EUICC业务(支持EUICC的手机。embedded SIM,嵌入式SIM卡)
5.MBMS业务(MBMS:Multimedia Broadcast Multicast Service,多媒体广播多播业务)
6.CAT业务(STK等在线业务)
7.数据连接业务
8.SIP业务(Session Initiation Protocol,VoLTE,ViLTE)

Phone有什么作用:

1.注册监听事件,及时上报消息(Call状态变化、Service状态变化、新来电等等)

2.间接地为其他类提供跟modem交互的服务

PhoneApp启动流程

phoneapp_start

根据此图可看出PhoneApp应用的整个启动过程以及其在启动后具体做了那些工作,接下来我们根据这个类图进行PhoneApp启动流程梳理

PhoneApp的路径是:packages\services\Telephony

既然是一个应用那么首先看看Application的定义,打开AndroidManifest.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<application android:name="PhoneApp"
<!-- 开机启动,并常驻的应用标示 -->
android:persistent="true"
android:label="@string/phoneAppLabel"
android:icon="@mipmap/ic_launcher_phone"
android:allowBackup="false"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:defaultToDeviceProtectedStorage="true"
<!-- 可直接启动应用 -->
android:directBootAware="true">
......
</application>

persistent的作用:
①该模块会在开机时被系统自动初始化
②该模块所在的进程(com.android.phone)由于任何原因被kill掉之后,都会自动重启(这种情况只针对系统内置app,第三方安装的app不会被重启)
directBootAware的作用:
从 Android N 开始,在首次开机时,在用户尚未来得及解锁设备之前,设备可直接启动到一种名为 Direct Boot(直接启动)的新模式中。在此模式下,操作系统可以全功能运行,但不允许访问私有应用数据,只能运行经过更新、可支持直接启动功能的应用。该属性使得用户在加密状态(未解锁)下能够正常使用一些手机功能,如闹钟,接电话等。

综上所述:PhoneApp在系统启动时就会被启动

那么接下来趁热乎就着源码将PhoneApp给一锅炖了

/packages/services/Telephony/src/com/android/phone/PhoneApp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class PhoneApp extends Application {
PhoneGlobals mPhoneGlobals;
TelephonyGlobals mTelephonyGlobals;

public PhoneApp() {
}

@Override
public void onCreate() {
if (UserHandle.myUserId() == 0) {
// We are running as the primary user, so should bring up the
// global phone state.
// 创建PhoneGlobals,即Phone的全局状态
mPhoneGlobals = new PhoneGlobals(this);
mPhoneGlobals.onCreate();

// 创建TelephonyGlobals,即Telephony应用的全局状态
// TelephonyGlobals在整个工程中没看到使用的地方,类中只是创建个实例和初始化TtyMananger,看解释是与PSTN call相关
mTelephonyGlobals = new TelephonyGlobals(this);
mTelephonyGlobals.onCreate();
}
}
}

由PhoneApp的onCreate()中负责创建两个对象,并且调用了各自的onCreate()方法,那么所有的启动流程重点将围绕这两个对象的onCreate()展开

PhoneGlobals

/packages/services/Telephony/src/com/android/phone/PhoneGlobals.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
public void onCreate() {
if (VDBG) Log.v(LOG_TAG, "onCreate()...");

ContentResolver resolver = getContentResolver();

// 缓存 "voice capable" 标志,来自资源文件的配置
sVoiceCapable = getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);

if (mCM == null) {
// 初始化 telephony framework
PhoneFactory.makeDefaultPhones(this);
// 实例化通话管理类CallManager,并把phone注册进去
mCM = CallManager.getInstance();
for (Phone phone : PhoneFactory.getPhones()) {
mCM.registerPhone(phone);
}

// 创建NotificationMgr单例,用于显示状态栏图标和控制其他状态栏行为。
notificationMgr = NotificationMgr.init(this);

// 发送EVENT_RESTART_SIP信号,如果PhoneGlobals已崩溃并正在重新启动,则重新启动。
// 走到这里已经存在phone进程,mHandler在处理EVENT_RESTART_SIP消息时,会从UserManager
// 中查找当前用户的状态,如果处于unlocked状态,才调用startSipService
mHandler.sendEmptyMessage(EVENT_RESTART_SIP);

// 创建一个CdmaPhoneCallState实例并将其初始化为IDLE
// 通话状态包括IDLE/SINGLE_ACTIVE/THRWAY_ACTIVE/CONF_CALL
cdmaPhoneCallState = new CdmaPhoneCallState();
cdmaPhoneCallState.CdmaPhoneCallStateInit();

// 获取电源管理器mPowerManager、唤醒锁mWakeLock、锁屏管理器mKeyguardManager
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
// 当我们不关心显示器时,用于保持处理器唤醒的锁定
mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
| PowerManager.ON_AFTER_RELEASE, LOG_TAG);

mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);

// 为了屏蔽在通话过程中提示系统更新相关事件,创建UpdateLock对象
mUpdateLock = new UpdateLock("phone");

// 实例化通话路由管理器
callGatewayManager = CallGatewayManager.getInstance();

// 实例化通话信息缓存类,它会记住自定义铃声发送到语音邮件设置。 异步缓存将在此调用之后立即启动。
callerInfoCache = CallerInfoCache.init(this);
// 实例化phone接口管理类,这个类可用于访问/修改phone的状态,比如通话状态/数据连接/网络状态等等
phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
// 实例化运营商配置加载类
configLoader = CarrierConfigLoader.init(this);

// 实例化CallNotifier,它处理来自电话层的异步事件(比如在有来电时启动来电呼叫UI)
notifier = CallNotifier.init(this);

// 注册ICC的EVENT_SIM_NETWORK_LOCKED状态监听处理
PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED);

// 注册MMI/USSD事件的监听处理
mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);

// 注册连接事件的监听处理,ConnectionHandler处理PHONE_STATE_CHANGED事件
PhoneUtils.initializeConnectionHandler(mCM);

// 注册一些广播事件处理
IntentFilter intentFilter =
new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
registerReceiver(mReceiver, intentFilter);

IntentFilter sipIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
sipIntentFilter.addAction(SipManager.ACTION_SIP_SERVICE_UP);
sipIntentFilter.addAction(SipManager.ACTION_SIP_CALL_OPTION_CHANGED);
sipIntentFilter.addAction(SipManager.ACTION_SIP_REMOVE_PHONE);
registerReceiver(mSipReceiver, sipIntentFilter);

mCarrierVvmPackageInstalledReceiver.register(this);

// 设置手机中偏好设置的默认值
PreferenceManager.setDefaultValues(this, R.xml.network_setting_fragment, false);

PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);

// 在给定手机的当前状态的情况下,确保正确初始化音频模式(以及我们自己的一些音频模式相关状态)。
PhoneUtils.setAudioMode(mCM);
}

// 尝试加载SimProvider以使其准备就绪
resolver.getType(Uri.parse("content://icc/adn"));

// TODO: 注册Cdma信息记录
// phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);

// 读取HAC设置并配置音频硬件
if (getResources().getBoolean(R.bool.hac_enabled)) {
int hac = android.provider.Settings.System.getInt(
getContentResolver(),
android.provider.Settings.System.HEARING_AID,
0);
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.setParameter(SettingsConstants.HAC_KEY,
hac == SettingsConstants.HAC_ENABLED
? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF);
}
}

PhoneGlobals.onCreate()主要做了以下工作:

1.初始化 telephony framework

2.实例化各种管理类CallManager,NotificationMgr,PowerManager,KeyguardManager,CallGatewayManager,PhoneInterfaceManager

3.设置Phone的一些初始化配置,注册相关广播,初始化SimProvider,配置音频硬件等

其中,各大管理类和各种配置可根据注释以及源码自己查看,这里继续解析Phone,即Telephony framework (PhoneFactory.makeDefaultPhones(this));

Telephony应用框架层

Telephony应用框架层启动流程

/frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
public static void makeDefaultPhone(Context context) {
synchronized (sLockProxyPhones) {
if (!sMadeDefaults) {
sContext = context;
// 实例化telephony硬件资源控制接口,这里的硬件资源包括SIM/MODEM/RIL
TelephonyDevController.create();

int retryCount = 0;
// 通过尝试创建地址为"com.android.internal.telephony"的LocalServerSocket来中断循环
for(;;) {
boolean hasException = false;
retryCount ++;

try {
// 使用UNIX域套接字来防止后续初始化
new LocalServerSocket("com.android.internal.telephony");
} catch (java.io.IOException ex) {
hasException = true;
}

if ( !hasException ) {
break;
} else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
throw new RuntimeException("PhoneFactory probably already running");
} else {
try {
Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
} catch (InterruptedException er) {
}
}
}

// Phone的状态通知器,对外发出通知,包括通话状态/网络服务状态/信号强度/SS(运营商补充服务--呼叫转移等)/网络小区信息/数据连接等等,
// DefaultPhoneNotifier其实就是个中转站,本质上各接口都是通过ITelephonyRegistry代理来访问"telephony.registry"服务
sPhoneNotifier = new DefaultPhoneNotifier();

// CDMA subscription状态管理
int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);

// 在多SIM模式的情况下,创建两个Phone,RIL实例,isMultiSimEnabled()函数检查它是单SIM还是多SIM模式
int numPhones = TelephonyManager.getDefault().getPhoneCount();
// 返回设备是否应使用动态绑定或静态实现(不建议使用)
boolean isDynamicBinding = sContext.getResources().getBoolean(
com.android.internal.R.bool.config_dynamic_bind_ims);
// 获取默认IMS实现的包名称
String defaultImsPackage = sContext.getResources().getString(
com.android.internal.R.string.config_ims_package);
// 启动ImsResolver并绑定到ImsServices
sImsResolver = new ImsResolver(sContext, defaultImsPackage, numPhones,
isDynamicBinding);
sImsResolver.initPopulateCacheAndStartBind();

int[] networkModes = new int[numPhones];
// 创建Phones数组,用来存储Phone实例
sPhones = new Phone[numPhones];
// 创建RIL数组,用来存储RIL实例
sCommandsInterfaces = new RIL[numPhones];
// TelephonyNetworkFactory是创建网络代理的工厂,默认网络代理的评判根据分数和能力来进行,也可以通过重载来实现更复杂的计算来评判
sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];

for (int i = 0; i < numPhones; i++) {
// 读取系统属性并生成命令接口获取首选网络类型。
// 初始化网络模式和RIL,支持几张卡就初始化几个RIL
networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;
sCommandsInterfaces[i] = new RIL(context, networkModes[i],
cdmaSubscription, i);
}
// SubscriptionController提供访问SubscriptionInfo的IPC接口,SubscriptionInfo是framework层对sim卡信息的抽象表示,
// 数据都存储在数据库中,比如设置SIM卡的icon/名称/号码,读取plmn/mccmnc等等
SubscriptionController.init(context, sCommandsInterfaces);

// 实例化UiccController/assets/images/android/tele/用于访问UICC卡的相关信息,通过在RIL中注册事件监听来实现
sUiccController = UiccController.make(context, sCommandsInterfaces);

if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TELEPHONY_EUICC)) {
sEuiccController = EuiccController.init(context);
sEuiccCardController = EuiccCardController.init(context);
}

// 根据SIM卡数量创建Phone实例,Phone实例分为两种类型GSM和CDMA
// 7.0开始没有CDMAPhone类,把之前的GSMPhone和CDMAPhone合并成了GsmCdmaPhone
// 同样的就有了GsmCdmaCallTracker/GsmCdmaConnection
for (int i = 0; i < numPhones; i++) {
Phone phone = null;
int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
phone = new GsmCdmaPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_GSM,
TelephonyComponentFactory.getInstance());
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
phone = new GsmCdmaPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_CDMA_LTE,
TelephonyComponentFactory.getInstance());
}

sPhones[i] = phone;
}

// 在基类中设置默认Phone
sPhone = sPhones[0];
sCommandsInterface = sCommandsInterfaces[0];

// 确保我们有一个默认的短信应用程序。 请求将updateIfNeeded设置为true的应用程序足以配置默认的SMS应用程序。
ComponentName componentName =
SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */);
String packageName = "NONE";
if (componentName != null) {
packageName = componentName.getPackageName();
}

// 设置监视器以监视SMS程序包的更改
SmsApplication.initSmsPackageMonitor(context);

sMadeDefaults = true;
// SubscriptionInfoUpdater主要监听sim卡的插入/拔出/上锁/加载等情况
sSubInfoRecordUpdater = new SubscriptionInfoUpdater(
BackgroundThread.get().getLooper(), context, sPhones, sCommandsInterfaces);
SubscriptionController.getInstance().updatePhonesAvailability(sPhones);

// 在默认设置完成后开始监控。 在创建ImsPhone之前,必须准备好默认Phone,因为ImsService在打开时可能需要它
// 这应该为ImsService的ImsResolver实现初始化多个ImsPhones。
for (int i = 0; i < numPhones; i++) {
sPhones[i].startMonitoringImsService();
}

// ITelephonyRegistry提供了访问通话状态/网络服务状态/信号强度/SS(运营商补充服务--呼叫转移等)/网络小区信息/数据连接等等的接口
ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(
ServiceManager.getService("telephony.registry"));
SubscriptionController sc = SubscriptionController.getInstance();

sSubscriptionMonitor = new SubscriptionMonitor(tr, sContext, sc, numPhones);
//PhoneSwitcher监听subscription的变化和网络请求来决定启用哪个phone
sPhoneSwitcher = new PhoneSwitcher(MAX_ACTIVE_PHONES, numPhones,
sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces,
sPhones);

// ProxyController类用于get/set radio相关的操作
sProxyController = ProxyController.getInstance(context, sPhones,
sUiccController, sCommandsInterfaces, sPhoneSwitcher);

sIntentBroadcaster = IntentBroadcaster.getInstance(context);

sNotificationChannelController = new NotificationChannelController(context);

// 网络数据连接辅助类
sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
for (int i = 0; i < numPhones; i++) {
sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
sPhoneSwitcher, sc, sSubscriptionMonitor, Looper.myLooper(),
sContext, i, sPhones[i].mDcTracker);
}
}
}
}

总结一下上面对makeDefaultPhone()方法的分析:

1.初始化各种控制接口SubscriptionController,UiccController,主要负责SIM卡状态信息的控制监听

2.根据SIM卡数量创建Phone和RIL实例,并且设置默认Phone和RIL,Phone分为GSM和CDMA两大种类

3.启动ImsResolver并绑定到ImsServices

Android中有三种PhoneFactory
1.PhoneFactory.java ——–>用于创建GsmCdmaPhone对象
2.ImsPhoneFactory.java ——–>用于创建ImsPhone对象
3.SipPhoneFactory.java ——–>用于创建SipPhone对象

总结

这篇文章主要讲述了Telephony从PhoneApp创建开始,一步步唤醒Android系统中Telephony这个庞然大物的过程,这篇文章不是大纲,却能帮助你找到Telephony相关的大部分线索,借此坚持下去,总有一天会找到你想要的枝繁叶茂。虽然传说程序员心中的树是倒着生长的 ^_^