Telephony解析之TelephonyManager

本文代码基于Android 9.0

概述

TelephonyManager提供对设备上telephony services信息的访问。 应用程序可以使用TelephonyManager中的方法来确定telephony服务和状态,以及访问某些类型的subscriber信息,应用程序还可以注册listener用来接收电话状态更改的通知

TelephonyManager中使用了4个核心服务,Telephony相关的一系列信息和操作都依赖自这4个核心服务,因此了解4个核心服务就可以灵活的使用TelephonyManager

TelephonyManager架构

ITelecomService

Service:packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java
Service Name:telecom (TELECOM_SERVICE)

Telecom是Android中的系统服务,主要作用是管理通话(来电显示、拨电话、接电话等),在Telephony模块与上层UI之间起到了一个桥接作用。比如,Telephony有接收到新的来电时,首先会告知Telecom,然后由Telecom服务通知上层应用来电信息,并显示来电界面。

Telecom服务对外提供了一个接口类TelecomManager,通过其提供的接口,客户端可以查询通话状态,发送通话请求以及添加通话链接等。

TelecomService

1
2
3
4
5
6
7
8
<service android:name=".components.TelecomService"
android:singleUser="true"
<!-- 在system进程中被启动 -->
android:process="system">
<intent-filter>
<action android:name="android.telecom.ITelecomService" />
</intent-filter>
</service>

TelecomService属于system进程的服务,在SystemService中启动TelecomLoaderService,onBootPhase()调用connectToTelecom()时绑定TelecomService,

方法中的判断条件PHASE_ACTIVITY_MANAGER_READY表示系统服务ActivityManagerService被成功启动后

如果Telecom服务连接中断时,则重新连接

具体启动流程,如下图所示:

telecom_start

当绑定服务时,调用TelecomService的onBind方法,initializeTelecomSystem()对整个Telecom系统进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static void initializeTelecomSystem(Context context) {
if (TelecomSystem.getInstance() == null) {
// 初始化通知引擎管理者
NotificationChannelManager notificationChannelManager =
new NotificationChannelManager();
notificationChannelManager.createChannels(context);
// 初始化TelecomSystem实例
TelecomSystem.setInstance(
new TelecomSystem(context,...));
}
if (BluetoothAdapter.getDefaultAdapter() != null) {
// 开启BluetoothPhoneService服务
context.startService(new Intent(context, BluetoothPhoneService.class));
}
}

最主要是初始化TelecomSystem,上面代码中省略了TelecomSystem构造方法中的其他参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

/**
* TelecomSystem的构造方法中的参数,主要负责1.创建一个PhoneAccount注册管理类 2.初始化CallsManager,正是它负责与上层UI的交互 3.注册Receiver以获取拨号密码,用于启用扩展记录
* @param context
* @param missedCallNotifierImplFactory 用户未接来电通知类(不包括已接或者拒绝的电话)
* @param callerInfoAsyncQueryFactory 查询来电信息
* @param headsetMediaButtonFactory 耳机接入状态监听
* @param proximitySensorManagerFactory 距离传感器管理
* @param inCallWakeLockControllerFactory 通话时电话管理
* @param audioServiceFactory 音频服务管理
* @param bluetoothPhoneServiceImplFactory 蓝牙设备管理
* @param connectionServiceFocusManagerFactory
* @param timeoutsAdapter 查询所有超时信息
* @param asyncRingtonePlayer 响铃播放
* @param phoneNumberUtilsAdapter 电话号码帮助类
* @param incomingCallNotifier 来电通知
* @param toneGeneratorFactory
* @param callAudioRouteStateMachineFactory
* @param clockProxy
*/

IPhoneSubInfo

Service:frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneSubInfoController.java
Service Name:iphonesubinfo

提供用户信息读取服务,通过这个服务可以得到软件版本、设备ID、SIM卡串号、语音信箱等信息,启动流程如下:

phone_subinfo

ITelephony

Service:packages/services/Telephony/src/com/android/phone/PhoneInterfaceManager.java
Service Name:phone (TELEPHONY_SERVICE)

在PhoneApp启动的时候开启ITelephony服务,主要启动过程如下,PhoneInterfaceManager在PhoneGlobals的onCreate方法中被创建,创建后在publish()方法中将自己添加到ServiceManager中

phone_subinfo

ITelephony接口主要定义了以下2类功能,详细信息可在源码中查看:

1.Telephony控制:dial、call、endCall、answerRingingCall等

2.Telephony查询:isOffhook、isRinging、isRadioOn、getCellLocation、getActivePhoneType等

MainThreadHandler运行在phone进程主线程上,主要负责处理通信相关的消息(CMD和Event),根据命令变量名可知道其操作的内容

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
private static final int CMD_HANDLE_PIN_MMI = 1;
private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
private static final int CMD_ANSWER_RINGING_CALL = 4;
private static final int CMD_END_CALL = 5; // not used yet
private static final int CMD_TRANSMIT_APDU_LOGICAL_CHANNEL = 7;
private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 8;
private static final int CMD_OPEN_CHANNEL = 9;
private static final int EVENT_OPEN_CHANNEL_DONE = 10;
private static final int CMD_CLOSE_CHANNEL = 11;
private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
private static final int CMD_NV_READ_ITEM = 13;
private static final int EVENT_NV_READ_ITEM_DONE = 14;
private static final int CMD_NV_WRITE_ITEM = 15;
private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
private static final int CMD_NV_WRITE_CDMA_PRL = 17;
private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
private static final int CMD_NV_RESET_CONFIG = 19;
private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
private static final int CMD_SEND_ENVELOPE = 25;
private static final int EVENT_SEND_ENVELOPE_DONE = 26;
private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 27;
private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 28;
private static final int CMD_TRANSMIT_APDU_BASIC_CHANNEL = 29;
private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 30;
private static final int CMD_EXCHANGE_SIM_IO = 31;
private static final int EVENT_EXCHANGE_SIM_IO_DONE = 32;
private static final int CMD_SET_VOICEMAIL_NUMBER = 33;
private static final int EVENT_SET_VOICEMAIL_NUMBER_DONE = 34;
private static final int CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC = 35;
private static final int EVENT_SET_NETWORK_SELECTION_MODE_AUTOMATIC_DONE = 36;
private static final int CMD_GET_MODEM_ACTIVITY_INFO = 37;
private static final int EVENT_GET_MODEM_ACTIVITY_INFO_DONE = 38;
private static final int CMD_PERFORM_NETWORK_SCAN = 39;
private static final int EVENT_PERFORM_NETWORK_SCAN_DONE = 40;
private static final int CMD_SET_NETWORK_SELECTION_MODE_MANUAL = 41;
private static final int EVENT_SET_NETWORK_SELECTION_MODE_MANUAL_DONE = 42;
private static final int CMD_SET_ALLOWED_CARRIERS = 43;
private static final int EVENT_SET_ALLOWED_CARRIERS_DONE = 44;
private static final int CMD_GET_ALLOWED_CARRIERS = 45;
private static final int EVENT_GET_ALLOWED_CARRIERS_DONE = 46;
private static final int CMD_HANDLE_USSD_REQUEST = 47;
private static final int CMD_GET_FORBIDDEN_PLMNS = 48;
private static final int EVENT_GET_FORBIDDEN_PLMNS_DONE = 49;
private static final int CMD_SWITCH_SLOTS = 50;
private static final int EVENT_SWITCH_SLOTS_DONE = 51;

ITelephonyRegistry

Service:frameworks/base/services/core/java/com/android/server/TelephonyRegistry.java
Service Name:telephony.registry

ITelephonyRegistry的主要作用就是对信号、呼叫转移、位置改变、数据连接状态等信息的监听,其监听原理主要体现在下面两个方面

1.注册通知

listen() 客户端在得到这个服务后,可以通过统一的listen方法将自己注册为状态的监听器

2.发送通知

如果Phone状态发生了改变,系统就会遍历所有的监听器,主动向他们发消息,调用相应的回调函数。

notifyxxx 类型的方法在PhoneStateListener的辅助下进行状态通知

broadcastxxx 类型的方法通过发送广播进行状态通知

ITelephonyRegistry服务和ITelecomService一样都属于System服务,运行在System进程中,TelephonyRegistry在SystemServer的startOtherServices()方法中被创建并添加的

1
2
3
4
private void startOtherServices() {
telephonyRegistry = new TelephonyRegistry(context);
ServiceManager.addService("telephony.registry", telephonyRegistry);
}