Android System Server大纲之TelecomLoaderService
Telecom:通话逻辑控制
前言
在Android 5.0版本中,Android大幅地修改了Call(通话)模块,把Call的逻辑处理从Telephony抽出来,独立成Telecom模块。从此Call的流程中就多了Telecom,分工越来越明细,耦合度进一步降低,给维护带来了良好的改进。但是逻辑上也稍微变得复杂了那么一些。从Android 5.0开始到现在的最新的Android 7.0,Call的架构如下:
从Android 4.4开始,Android出于对Android安全方面的考虑,创立了默认APP的机制,当然这个默认APP的机制值限制于浏览器、通话、短彩信三个模块,只有用户设置了对应模块功能的默认APP,这个APP才能完成这些模块的功能,读者可以参考文章《Android default phone mechanism 》。
TelecomLoaderService在开机时会加载Call架构中Telecom的模块,把Telecom模块的服务添加在系统服务当中。对默认短信、通话模块的默认APP进行相应的授权,当然,这个是Android 6.0运行时权限处理时才需要添加的。运行时权限读者可以参考文章《Android M App Permissions 》。
TelecomLoaderService的启动
参考文章《Android系统之System Server大纲 》可知,启动过程如下:
mSystemServiceManager.startService(TelecomLoaderService.class);
这条语句定义在文件frameworks/base/services/java/com/android/server/SystemServer.java中。
参考文章《Android系统之System Server大纲 》中系统服务的启动方式,TelecomLoaderService启动之后会回调方法onStart(),以及system_process启动完毕后会回调所有SystemService的onBootPhase()方法。
@Override
public void onStart() {
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_ACTIVITY_MANAGER_READY) {
registerDefaultAppNotifier();
registerCarrierConfigChangedReceiver();
connectToTelecom();
}
}
这些方法定义在文件frameworks/base/services/core/java/com/android/server/telecom/TelecomLoaderService.java中。
上面的代码中,onStart()方法什么事情也没有做,onBootPhase()中分别调用了registerDefaultAppNotifier()、registerCarrierConfigChangedReceiver()、connectToTelecom(),前两个方法会监听一些数据的变化,如默认短彩信APP的变化等,本文不再往下阐述它们。最后一个方法connectToTelecom()就是便是连接到Telecom。如下:
private static final String SERVICE_ACTION = "com.android.ITelecomService";
private static final ComponentName SERVICE_COMPONENT = new ComponentName(
"com.android.server.telecom",
"com.android.server.telecom.components.TelecomService");
private void connectToTelecom() {
synchronized (mLock) {
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.OWNER)) {
mServiceConnection = serviceConnection;
}
}
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/telecom/TelecomLoaderService.java中。
实例化一个Intent,action是SERVICE_ACTION,以及指定Component为SERVICE_COMPONENT,随后调用bindServiceAsUser绑定远程服务,在Android四大组件的Service架构中,启动/绑定一个Service,需要传递一个ServiceConnection的子类,上面的代码传的是TelecomServiceConnection。被绑定的这个服务定义在文件packages/services/Telecomm/src/com/android/server/telecom/components/TelecomService.java中。当成功绑定应用com.android.server.telecom/.components.TelecomService中的Service后,便会回调TelecomServiceConnection中的onServiceConnected()方法:
public void onServiceConnected(ComponentName name, IBinder service) {
// Normally, we would listen for death here, but since telecom runs in the same process
// as this loader (process="system") thats redundant here.
try {
SmsApplication.getDefaultMmsApplication(mContext, false);
ServiceManager.addService(Context.TELECOM_SERVICE, service);
synchronized (mLock) {
......
if (smsComponent != null) {
......
packageManagerInternal.grantDefaultPermissionsToDefaultSmsApp(
smsComponent.getPackageName(), userid);
}
}
}
if (mDefaultDialerAppRequests != null) {
......
packageManagerInternal.grantDefaultPermissionsToDefaultDialerApp(
packageName, userId);
}
}
}
if (mDefaultSimCallManagerRequests != null) {
......
packageManagerInternal
.grantDefaultPermissionsToDefaultSimCallManager(
packageName, userId);
......
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/telecom/TelecomLoaderService.java中。
为了看起来简洁,这里省略了很多代码,但是不会影响对功能的理解。在onServiceConnected()方法中,主要完成4个事情。
第一:
把Context.TELECOM_SERVICE添加到系统的服务中,这里的IBinder是绑定service返回的远程句柄,这个句柄的实现定义在文件packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java中,在以后的文章中再阐述这个服务。
第二:
给默认的短彩信(SMS)应用授予运行时权限。
第三:
给默认的通话(Dialer)应用授予运行时权限。
第四:
给默认的SimCallManager应用授予运行时权限。
由于授权的过程是一样的,本文就以通话的授权为例,阐述这个过程:
public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
synchronized (mPackages) {
mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultDialerAppLPr(
packageName, userId);
}
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java中。
这里直接调用了grantDefaultPermissionsToDefaultDialerAppLPr()方法,如下:
public void grantDefaultPermissionsToDefaultDialerAppLPr(String packageName, int userId) {
PackageParser.Package dialerPackage = getPackageLPr(packageName);
if (dialerPackage != null
&& doesPackageSupportRuntimePermissions(dialerPackage)) {
grantRuntimePermissionsLPw(dialerPackage, PHONE_PERMISSIONS, false, true, userId);
grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, false, true, userId);
grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, false, true, userId);
grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, false, true, userId);
}
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java中。
通过getPackageLPr()把Dialer抽象成PackageParser.Package对象,调用grantRuntimePermissionsLPw()分别给Dialer应用授予PHONE_PERMISSIONS、CONTACTS_PERMISSIONS、SMS_PERMISSIONS、MICROPHONE_PERMISSIONS权限,这几个权限的明细如下:
private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
static {
PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
PHONE_PERMISSIONS.add(Manifest.permission.CALL_PHONE);
PHONE_PERMISSIONS.add(Manifest.permission.READ_CALL_LOG);
PHONE_PERMISSIONS.add(Manifest.permission.WRITE_CALL_LOG);
PHONE_PERMISSIONS.add(Manifest.permission.ADD_VOICEMAIL);
PHONE_PERMISSIONS.add(Manifest.permission.USE_SIP);
PHONE_PERMISSIONS.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
}
private static final Set<String> CONTACTS_PERMISSIONS = new ArraySet<>();
static {
CONTACTS_PERMISSIONS.add(Manifest.permission.READ_CONTACTS);
CONTACTS_PERMISSIONS.add(Manifest.permission.WRITE_CONTACTS);
CONTACTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS);
}
private static final Set<String> SMS_PERMISSIONS = new ArraySet<>();
static {
SMS_PERMISSIONS.add(Manifest.permission.SEND_SMS);
SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_SMS);
SMS_PERMISSIONS.add(Manifest.permission.READ_SMS);
SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_WAP_PUSH);
SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_MMS);
SMS_PERMISSIONS.add(Manifest.permission.READ_CELL_BROADCASTS);
}
private static final Set<String> MICROPHONE_PERMISSIONS = new ArraySet<>();
static {
MICROPHONE_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO);
}
所以,在手机启动后,会给默认的通话应用Dialer授予以上运行时的危险权限。
到这里,TelecomLoaderService的工作基本上就完成了。TelecomLoaderService所负责的事情并不多,由于Android系统用于很多设备,在某些设备上,会没有Telecom模块,所以,独立一个TelecomLoaderService来加载Telecom模块,也是非常美好的一个业务分配。
总结
TelecomLoaderService的名字非常完美的总结了TelecomLoaderService所需要完成的业务,虽然TelecomLoaderService的业务并不多,也不是很难理解,但是涉及到其它模块却不是很少,有TelecomService、默认应用、运行时权限等等。最后附一张时序图: