1. Telecom所处位置
由下图,Telecom的作用是起到交互桥梁,与IncallUI 和 Telephony【Phone进程、TeleService】交互
路径 | 统称 | 进程 |
packages/app/Dialer | Dialer | com.android.dialer |
packages/service/telecomm | telecom | system_service |
packages/service/telephony | TeleService | com.android.phone |
framework/base/telecomm | framework | 无进程只是提供调用framwork |
framework/opt/Telephony | telephony | system_service或com.android.phone |
2. 什么是Telecom 服务
telecom所处的代码路径:
代码路径:
- /packages/services/Telecomm
- /frameworks/base/telecomm/java/android/telecom/
Telecom是Android的一个系统服务,其主要作用是管理Android系统当前的通话,如来电显示,接听电话,挂断电话等功能,在Telephony模块与上层UI之间起到了一个桥梁的作用。比如,Telephony有接收到新的来电时,首先会告知Telecom,然后由Telecom服务通知上层应用来电信息,并显示来电界面。
Telecom服务对外提供了一个接口类TelecomManager
,通过其提供的接口,客户端可以查询通话状态,发送通话请求以及添加通话链接等。
从Telecom
进程对应的AndroidManifest.xml
文件来看,Telecom进程的用户ID跟系统进程用户ID相同,是系统的核心服务。那么,其中android:process="system"
这个属性值表示什么意思了?查看官方文档,这个表示Telecom
将启动在进程system
中,这样可以跟其他进程进行资源共享了(对于Android这个全局进程,就是SystemServer
所在的进程)。
AndroidManifest.xml 在
/packages/services/Telecomm,包含了 ITelecomService
/packages/services/Telecomm/AndroidManifest.xml
17 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
18 xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
19 package="com.android.server.telecom"
20 coreApp="true"
21 android:sharedUserId="android.uid.system">
22
23 <protected-broadcast android:name="android.intent.action.SHOW_MISSED_CALLS_NOTIFICATION" />
24 <protected-broadcast android:name="com.android.server.telecom.MESSAGE_SENT" />
330 <service android:name=".components.BluetoothPhoneService"
331 android:singleUser="true"
332 android:process="system">
333 <intent-filter>
334 <action android:name="android.bluetooth.IBluetoothHeadsetPhone" />
335 </intent-filter>
336 </service>
337
338 <service android:name=".components.TelecomService"
339 android:singleUser="true"
340 android:process="system">
341 <intent-filter>
342 <action android:name="android.telecom.ITelecomService" />
343 </intent-filter>
344 </service>
345
346 </application>
347 </manifest>
3. Telecom代码路径
1) /packages/services/Telecomm 代码路径
action: android.intent.action.CALL
141 <!-- Activity that starts the outgoing call process by listening to CALL intent which
142 contain contact information in the intent's data. CallActivity handles any data
143 URL with the schemes "tel", "sip", and "voicemail". It also handles URLs linked to
144 contacts provider entries. Any data not fitting the schema described is ignored. -->
145 <activity android:name=".components.UserCallActivity"
146 android:label="@string/userCallActivityLabel"
147 android:theme="@style/Theme.Telecomm.Transparent"
148 android:permission="android.permission.CALL_PHONE"
149 android:excludeFromRecents="true"
150 android:process=":ui">
151 <!-- CALL action intent filters for the various ways of initiating an outgoing call. -->
152 <intent-filter>
153 <action android:name="android.intent.action.CALL" />
154 <category android:name="android.intent.category.DEFAULT" />
155 <data android:scheme="tel" />
-------------
184 <activity-alias android:name="PrivilegedCallActivity"
185 android:targetActivity=".components.UserCallActivity"
186 android:permission="android.permission.CALL_PRIVILEGED"
187 android:process=":ui">
188 <intent-filter android:priority="1000">
189 <action android:name="android.intent.action.CALL_PRIVILEGED" />
190 <category android:name="android.intent.category.DEFAULT" />
191 <data android:scheme="tel" />
192 </intent-filter>
action:android.intent.action.CALL_EMERGENCY
212 <!-- Works like CallActivity with CALL_EMERGENCY instead of CALL intent.
213 CALL_EMERGENCY allows calls *only* to emergency numbers. Intent-sender must have the
214 CALL_PRIVILEGED permission or the broadcast will not be processed. High priority of
215 1000 is used in all intent filters to prevent anything but the system from processing
216 this intent (b/8871505). -->
217 <!-- TODO: Is there really a notion of an emergency SIP number? If not, can
218 that scheme be removed from this activity? -->
219 <activity-alias android:name="EmergencyCallActivity"
220 android:targetActivity=".components.UserCallActivity"
221 android:permission="android.permission.CALL_PRIVILEGED"
222 android:process=":ui">
223 <intent-filter android:priority="1000">
224 <action android:name="android.intent.action.CALL_EMERGENCY" />
225 <category android:name="android.intent.category.DEFAULT" />
226 <data android:scheme="tel" />
227 </intent-filter>
2) /frameworks/base/telecomm/java/android/telecom/ 框架层路径
4. Telecom进程的启动和初始化
首先会走到 main 方法中,然后在调用 run 方法:在SystemServer
进程初始化完成启动完系统的核心服务如ActivityManagerService
后,就会加载系统其它服务,这其中就包含了一个与Telecom
服务启动相关的系统服务专门用于加载Telecom
:
917 private void startOtherServices() {
1004 traceBeginAndSlog("StartTelecomLoaderService");
1005 mSystemServiceManager.startService(TelecomLoaderService.class);
1006 traceEnd();
1007
1008 traceBeginAndSlog("StartTelephonyRegistry");
1009 telephonyRegistry = new TelephonyRegistry(context);
1010 ServiceManager.addService("telephony.registry", telephonyRegistry);
1011 traceEnd();
调用系统服务管家SystemServiceManager
的接口startService
创建新的服务,并注册到系统中,最后调用onStart()
启动服务。
public class SystemServiceManager {
@SuppressWarnings("unchecked")
public SystemService startService(String className) {
final Class<SystemService> serviceClass;
try {
serviceClass = (Class<SystemService>)Class.forName(className);
} catch (ClassNotFoundException ex) {
....
}
return startService(serviceClass);
}
// 服务的class文件来创建新的服务对象(服务必须继承SystemService)
@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
}
....
// Register it.
mServices.add(service);
// Start it.
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + name
+ ": onStart threw an exception", ex);
}
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
}
创建TelecomLoaderService
系统服务,将系统默认的SMS应用,拨号应用以及SIM通话管理应用告知PackageManagerService
(PMS),以便在适当的时候可以找到应用。
public class TelecomLoaderService extends SystemService {
...
public TelecomLoaderService(Context context) {
super(context);
mContext = context;
registerDefaultAppProviders();
}
@Override
public void onStart() {
}
private void registerDefaultAppProviders() {
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
// Set a callback for the package manager to query the default sms app.
packageManagerInternal.setSmsAppPackagesProvider(
new PackageManagerInternal.PackagesProvider() {
@Override
public String[] getPackages(int userId) {
synchronized (mLock) {
....
ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
mContext, true);
if (smsComponent != null) {
return new String[]{smsComponent.getPackageName()};
}
return null;
}
});
// Set a callback for the package manager to query the default dialer app.
packageManagerInternal.setDialerAppPackagesProvider(
new PackageManagerInternal.PackagesProvider() {
@Override
public String[] getPackages(int userId) {
synchronized (mLock) {
....
String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext);
if (packageName != null) {
return new String[]{packageName};
}
return null;
}
});
// Set a callback for the package manager to query the default sim call manager.
packageManagerInternal.setSimCallManagerPackagesProvider(
new PackageManagerInternal.PackagesProvider() {
@Override
public String[] getPackages(int userId) {
synchronized (mLock) {
....
TelecomManager telecomManager =
(TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
if (phoneAccount != null) {
return new String[]{phoneAccount.getComponentName().getPackageName()};
}
return null;
}
});
}
}
telecom 服务的启动:
有一个onBootPhase
的函数,用于SystemServer
告知系统服务目前系统启动所处的阶段。这里可以看到,等(ActivityManagerService
)AMS启动完成以后,就可以开始连接Telecom服务了:
- 首先,注册默认应用(SMS/Dialer etc)通知对象,以便这些应用发送变更(如下载了一个第三方的SMS应用时,可以通知系统这一变化);
- 接着,注册运营商配置变化的广播接收器,如果配置有变化时,系统会收到通知;
- 绑定TelecomService,并将其注册到系统中。
public class TelecomLoaderService extends SystemService {
private static final ComponentName SERVICE_COMPONENT = new ComponentName(
"com.android.server.telecom",
"com.android.server.telecom.components.TelecomService");
private static final String SERVICE_ACTION = "com.android.ITelecomService";
// 当前系统启动的阶段
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_ACTIVITY_MANAGER_READY) {
registerDefaultAppNotifier();
registerCarrierConfigChangedReceiver();
connectToTelecom();
}
}
//绑定Telecom服务
private void connectToTelecom() {
synchronized (mLock) {
if (mServiceConnection != null) {
// TODO: Is unbinding worth doing or wait for system to rebind?
mContext.unbindService(mServiceConnection);
mServiceConnection = null;
}
TelecomServiceConnection serviceConnection = new TelecomServiceConnection();
Intent intent = new Intent(SERVICE_ACTION);
intent.setComponent(SERVICE_COMPONENT);
int flags = Context.BIND_IMPORTANT | Context.BIND_FOREGROUND_SERVICE
| Context.BIND_AUTO_CREATE;
// Bind to Telecom and register the service
if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.SYSTEM)) {
mServiceConnection = serviceConnection;
}
}
}
}
绑定服务时,调用TelecomService
的onBind
接口,对整个Telecom系统进行初始化,并返回一个IBinder
接口:
/**
* Implementation of the ITelecom interface.
*/
public class TelecomService extends Service implements TelecomSystem.Component {
@Override
public IBinder onBind(Intent intent) {
// 初始化整个Telecom系统
initializeTelecomSystem(this);
//返回IBinder接口
synchronized (getTelecomSystem().getLock()) {
return getTelecomSystem().getTelecomServiceImpl().getBinder();
}
}
}
Telecom系统初始化,主要工作是新建一个TelecomSystem
的类,在这个类中,会对整个Telecom服务的相关类都初始化
static void initializeTelecomSystem(Context context) {
if (TelecomSystem.getInstance() == null) {
final NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// 用于获取联系人
contactInfoHelper = new ContactInfoHelper(context);
// 新建一个单例模式的对象
TelecomSystem.setInstance(new TelecomSystem(....));
}
....
}
}
构造一个单例TelecomSystem对象,会创建许多和通话有关的类
public TelecomSystem(
Context context,
/* 用户未接来电通知类(不包括已接或者拒绝的电话) */
MissedCallNotifierImplFactory missedCallNotifierImplFactory,
/* 查询来电信息 */
CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,
/* 耳机接入状态监听 */
HeadsetMediaButtonFactory headsetMediaButtonFactory,
/* 距离传感器管理 */
ProximitySensorManagerFactory proximitySensorManagerFactory,
/* 通话时电话管理 */
InCallWakeLockControllerFactory inCallWakeLockControllerFactory,
/* 音频服务管理 */
AudioServiceFactory audioServiceFactory,
/* 蓝牙设备管理 */
BluetoothPhoneServiceImplFactory bluetoothPhoneServiceImplFactory,
BluetoothVoIPServiceImplFactory bluetoothVoIPServiceImplFactory,
/* 查询所有超时信息 */
Timeouts.Adapter timeoutsAdapter,
/* 响铃播放 */
AsyncRingtonePlayer asyncRingtonePlayer,
/* 电话号码帮助类 */
PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
/* 通话时阻断通知 */
InterruptionFilterProxy interruptionFilterProxy) {
mContext = context.getApplicationContext();
// 初始化telecom相关的feature
TelecomFeature.makeFeature(mContext);
// 初始化telecom的数据库
TelecomSystemDB.initialize(mContext);
// 创建一个PhoneAccount注册管理类
mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext);
....
// 初始化通话管家,正是它负责与上层UI的交互
mCallsManager = new CallsManager(
mContext, mLock, mContactsAsyncHelper,
callerInfoAsyncQueryFactory, mMissedCallNotifier,
mPhoneAccountRegistrar, headsetMediaButtonFactory,
proximitySensorManagerFactory, inCallWakeLockControllerFactory,
audioServiceFactory, bluetoothManager,
wiredHeadsetManager, systemStateProvider,
defaultDialerAdapter, timeoutsAdapter,AsyncRingtonePlayer,
phoneNumberUtilsAdapter, interruptionFilterProxy);
CallsManager.initialize(mCallsManager);
// 注册需要接收的广播
mContext.registerReceiver(mUserSwitchedReceiver, USER_SWITCHED_FILTER);
mContext.registerReceiver(mUserStartingReceiver, USER_STARTING_FILTER);
mContext.registerReceiver(mFeatureChangedReceiver, FEATURE_CHANGED_FILTER);
mContext.registerReceiver(mEmergencyReceiver, EMERGENCY_STATE_CHANGED);
....
// 所有来电与去电的处理中转站
mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager);
// 创建一个TelecomServiceImpl用于调用TelecomService的接口
mTelecomServiceImpl = new TelecomServiceImpl(
mContext, mCallsManager, mPhoneAccountRegistrar,
new CallIntentProcessor.AdapterImpl(),
new UserCallIntentProcessorFactory() {
@Override
public UserCallIntentProcessor create(Context context, UserHandle userHandle) {
return new UserCallIntentProcessor(context, userHandle);
}
},
defaultDialerAdapter,
new TelecomServiceImpl.SubscriptionManagerAdapterImpl(),
mLock);
// 执行特定的初始化操作
initialize(mContext);
}
}
5. 核心 Listener 的回调机制【核心类:CallsManager】
在解析拨号流程和来电流程的过程中,遇见了各式各样的Listener 消息回调。本节将重点解析 Telecom 中的 Listener 消息处理机制
/packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
1) CallsManagerListener 接口:
在TelecomSystem 初始化过程中创建CallsManager 对象时,将同步创建C llsManagerlistener 对象,并注册Listener 消息通知,查看CallsManager 类的构造方法
监听通话的一系列状态
public interface CallsManagerListener {
void onCallAdded(Call call);
void onCallRemoved(Call call);
void onCallStateChanged(Call call, int oldState, int newState);
void onConnectionServiceChanged(
Call call,
ConnectionServiceWrapper oldService,
ConnectionServiceWrapper newService);
void onIncomingCallAnswered(Call call);
void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage);
void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState);
void onRingbackRequested(Call call, boolean ringback);
void onIsConferencedChanged(Call call);
void onIsVoipAudioModeChanged(Call call);
void onVideoStateChanged(Call call, int previousVideoState, int newVideoState);
void onCanAddCallChanged(boolean canAddCall);
void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
void onHoldToneRequested(Call call);
void onExternalCallChanged(Call call, boolean isExternalCall);
void onDisconnectedTonePlaying(boolean isTonePlaying);
void onConnectionTimeChanged(Call call);
void onConferenceStateChanged(Call call, boolean isConference);
}
在Telecom 应用加载的初始化过程中,将创建CallsManagerListener 对象,并增加到CallsManager 对象的 mlisteners 列表中;而通话的相关状态或属性发生改变时, CallsManager 将遍历mlisteners 列表,进行on XXX的消息回调,其代码逻辑总结如下:
Ca llsManagerlistener 接口定义在Ca ll sManager 类中, CallsManagerListenerBase 类实现了此接口的所有方法,而且这些方法都没有任何的业务逻辑代码。在面向对象编程中,使用多态的一种典型方式是子类可根据业务需要选择父类中的方法进行重写。
CallsManagerlistenerBase 所有子类的作用及重写的方法, 总结如表4-1 所示。
2) Call.Listener
拨号流程或是来电流程中,都会创建com.android.server.telecom. Call 对象,此类中定义了Listener 接口,主要有以下几个方法:
-------Call 类
106 * Listener for events on the call.
107 */
108 @VisibleForTesting
109 public interface Listener {
110 void onSuccessfulOutgoingCall(Call call, int callState);
111 void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause);
112 void onSuccessfulIncomingCall(Call call);
---------
151 public abstract static class ListenerBase implements Listener {
152 @Override
153 public void onSuccessfulOutgoingCall(Call call, int callState) {}
154 @Override
155 public void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause) {}
-------CallsManager类
------------
151 @VisibleForTesting
152 public class CallsManager extends Call.ListenerBase
CallsManager 作为Call.Listener 接口的子类,由Call 对象触发mlistenersCall 对象变化的消息回调, CallsManager 对象将通过自己的 mlisteners ,继续发出Call 对象变化的消息回调,而这一次的消息回调将接收并处理12 个对象;因此,可以将CallsManager 看作Call 对象变化 Listener 消息回调的消息中转站,将Call. Listener 和CallsManagerlistener 这两个Listener 紧密联系在一起。
3) CallsManager 工作机制
上图大致包含了CallsManager、Call、CallsManagerListener的工作机制:
Telecom启动之时就创建了CallsManager,而CallsManager在构造器内就将通话相关功能类注册到了监听列表中。在发生通话时(MT或MO),CallsManager首先创建出Call并回调所有观察者的对应方法,在Call状态更新时,会回调CallsManager相关方法,然后CallsManager会对Call进行相关处理,并会回调所有观察者的对应方法。
4) CreateConnectionResponse
CreateConnectionResponse 接口定义了两个方法: handleCreateConnectionSuccess 和handleCreateConnectionFailure ,
它总共有两个子类: Call 和CreateConnectionProcessor ,
Call 和CreateConnectionProcessor 都是 CreateConnectionResponse 接口对象。
不论拨号流程还是来电流程, Telecom 在Call 对象创建完成后, 都调用其 startCreateConnection 方法最终完成绑定 IConnectionService 服务相关的操作;在此过程中将涉及CreateConnectionResponse 接口对象的创建和传递过程,代码框架总结如下。
5)总结 Listener 消息
在Telecom 应用中主要处理两种消息类型:顺时针方向下发的通话控制消息 和 逆时针方向上报的通话状态变化消息。
而Listener 消息回调承载着上报消息的业务处理逻辑,其应用场景是ConnectionServiceWrapper 的Adapter 服务对象接收到TeleService 应用的接口调用,
通知当前Connection 和Call 的状态或属性发生的变化,再经过一系列的Listener 消息回调处理,最终由lnCallController 创建ParcelableCall 对象,使用 llnCallService 服务接口调用发送给Dialer 应用。
可见这些Listener 消息处理在Telecom 应用中的重要性,继续对CallsManager.Listener、Call.Listener 和 CreateConnectionResponse 三个核心消息回调的分析结果进行汇总和总结,形成Telecom 应用中消息回调的全貌
两条消息回调通道的调用过程,都会调用CallsManager 对象的setCallState 方法更新Telecom应用中的Call 属性
调用过程如下:
//第-条消息回调通道的调用过程【Telephony上报】
ConnectionServiceWrapper . mAdapter.handleCreateConnectionComplete
-> mPendingResponses(CreateConnectionProcessor) . handleCreateConnectionSuccess
- > mCallResponse (Call). handleCreateConnectionSuccess- > mListeners(CallsManager) . onSuccessfulXXXCall->setCallState
//第二条消息回调通道的调用过程【与InCallui交互】
ConnectionServiceWrapper . mAdapter.setActive
- > mCallsManager . markCallAsActive >setCallState
//CallsManager 对象的调用过程
CallsManager.setCallState
- > InCallController.onCallStateChanged - > updateCall- >inCallService.updateCall
6)耳机事件
关注 MediaSession 类