自定义系统服务
常见的AMS、PWS、WMS等等都是系统服务,运行于system_server进程,并且向servicemanager进程注册其Binder以便其他进程获取binder与对应的服务进行通信。为了新增自定义系统服务,我们可以参考AMS等原生系统服务编写如下文件:
1、AIDL文件:生成Binder类,其中Stub即为Binder的服务端;
2、XXManagerService:系统服务类,继承自Stub;
3、XXManager:封装了AIDL接口方法的类,相当于Binder客户端(Proxy),其他进程通过此类完成与系统服务的通信。
增加系统服务
1、AIDL
在frameworks/base/core/java/com/enjoy/service中编写IEnjoyManager.aidl
// IEnjoyManager.aidl
package com.enjoy.service;// Declare any non-default types here with import statementsinterface IEnjoyManager {void sendMessage(String msg);
}
在frameworks/base/Android.mk中声明AIDL文件:
LOCAL_SRC_FILES += ....core/java/android/app/IActivityManager.aidl \core/java/com/enjoy/service/IEnjoyManager.aidl \....
2、系统服务
在frameworks/base/services/core/java/com/enjoy/service中编写EnjoyManagerService.java
package com.enjoy.service;import android.os.RemoteException;
import android.util.Log;public class EnjoyManagerService extends IEnjoyManager.Stub {private static final String TAG = "Enjoy";@Overridepublic void sendMessage(String msg) throws RemoteException {Log.i(TAG, "sendMessage: " + msg);}
}
3、客户端代理
在frameworks/base/core/java/com/enjoy/service下编写EnjoyManager.java
package com.enjoy.service;import android.os.RemoteException;
import android.util.Log;public class EnjoyManager {private static final String TAG = "Enjoy";private IEnjoyManager service;public EnjoyManager(IEnjoyManager service) {this.service = service;}public void sendMessage(String msg) {try {service.sendMessage(msg);} catch (RemoteException e) {e.printStackTrace();}}
}
framework/base/Android.mk:
packages_to_document := \android \javax/microedition/khronos \org/apache/http/conn \org/apache/http/params \com/enjoy/service
4、修改Context
在frameworks/base/core/java/android/content/Context.java中加入常量:
public static final String ENJOY_SERVICE="enjoy";
5、注册系统服务
在frameworks/base/services/java/com/android/server/SystemServer.java中 注册系统服务
import com.enjoy.service.EnjoyManagerService;
private void startOtherServices(){//......ServiceManager.addService(Context.ENJOY_SERVICE,new EnjoyManagerService());//......
}
6、注册应用系统服务获取器
在frameworks/base/core/java/android/app/SystemServiceRegistry.java注册服务获取器:
import com.enjoy.service.IEnjoyManager;
import com.enjoy.service.EnjoyManager;
static{registerService(Context.ENJOY_SERVICE, EnjoyManager.class,new CachedServiceFetcher<EnjoyManager>() {@Overridepublic EnjoyManager createService(ContextImpl ctx) throws ServiceNotFoundException {// 获取服务IBinder b = ServiceManager.getServiceOrThrow(Context.ENJOY_SERVICE);IEnjoyManager service = IEnjoyManager.Stub.asInterface(b);return new EnjoyManager(service);}});
}
7、配置SELinux权限
system/sepolicy/private/service_contexts
activity u:object_r:activity_service:s0
enjoy u:object_r:enjoy_service:s0
system/sepolicy/public/service.te:
type activity_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;
type enjoy_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;
system/sepolicy/private/untrusted_app_all.te :
allow untrusted_app enjoy_service:service_manager find;
*8、配置白名单
如果以当前案例的方式新增自定义系统服务,因为SystemServiceRegistry 中需要使用到com.enjoy
下的类,为了让其获取此包下类的引用,需要配置:build/core/tasks/check_boot_jars/package_whitelist.txt ,加入:com\.enjoy\..*
。否则会因为无法获取类引用而编译报错!
dalvik\..*
libcore\..*
android\..*
com\.android\..*
com\.enjoy\..*
若新增的服务像AMS等原有系统服务的IActivityManager.aidl与ActivityManager一样放在
android.app
包下即可不用进行此步处理!
9、编译并刷机
#编译
make update-api
make –j4
#刷机
adb reboot bootloader
reboot flashall -w
10、使用自定义服务
10.1 利用双亲委托机制
在需要使用自定义服务的app中编写EnjoyManager(包名与framework中一致):
package com.enjoy.service;import android.os.RemoteException;
import android.util.Log;public class EnjoyManager {public void sendMessage(String msg) {}
}
此时由于类加载的双亲委托机制,app在运行时实际使用的是framework中的EnjoyManager。app中的EnjoyManager仅仅只是为了编译成功编写的空壳。
10.2 修改SDK
修改app使用的sdk,可以通过make sdk
将SDK完成编译出来。也可以直接在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates中找到EnjoyManager类将其加入原生SDK中的android.jar
SystemService
系统服务需要通过ServiceManager.addService("xx", new XXManagerService);
将自己(Binder Stub)注册进入SM才能够让其他进程利用Binder与之通信。而自定义系统服务如果需要根据系统启动的不同阶段进行不同的处理则需要注册生命周期回调。以AMS为例:
/frameworks/base/services/java/com/android/server/SystemService中启动AMS:
private void startBootstrapServices() {//...// Activity manager runs the show.traceBeginAndSlog("StartActivityManager");mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();mActivityManagerService.setSystemServiceManager(mSystemServiceManager);mActivityManagerService.setInstaller(installer);traceEnd(); //...mActivityManagerService.setSystemProcess();//...
}
AMS中的setSystemProcess方法的实现为:
public void setSystemProcess() {//...ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);//...
}
setSystemProcess中会完成向SM注册AMS的实现。而在setSystemProcess之前有一段代码:
mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();
则为注册生命周期监听,ActivityManagerService.Lifecycle就相当于生命周期的回调接口对象,它继承自:
/frameworks/base/services/core/java/com/android/server/SystemService。这个SystemService中主要需要实现两个方法:
-
onStart() :mSystemServiceManager.startService第一时间回调该函数。
-
onBootPhase(int phase) : 系统启动的各个阶段会回调该函数
- SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY:这是一个依赖项,只有DisplayManagerService中进行了对应处理;
- SystemService.PHASE_LOCK_SETTINGS_READY:经过这个引导阶段后,服务才可以接收到wakelock相关设置数据;
- SystemService.PHASE_SYSTEM_SERVICES_READY:经过这个引导阶段 后,服务才可以安全地使用核心系统服务
- SystemService.PHASE_ACTIVITY_MANAGER_READY:经过这个引导阶 段后,服务可以发送广播
- SystemService.PHASE_THIRD_PARTY_APPS_CAN_START:经过这个引导阶段后,服务可以启动第三方应用,第三方应用也可以通过Binder来调用服务。
- SystemService.PHASE_BOOT_COMPLETED:经过这个引导阶段后,说明服务启动完成,这时用户就可以和设备进行交互。
比如AMS中的Lifecycle:
public static final class Lifecycle extends SystemService {@Overridepublic void onBootPhase(int phase) {mService.mBootPhase = phase;if (phase == PHASE_SYSTEM_SERVICES_READY) {mService.mBatteryStatsService.systemServicesReady();mService.mServices.systemServicesReady();} else if (phase == PHASE_ACTIVITY_MANAGER_READY) {// 准备广播处理mService.startBroadcastObservers();} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {mService.mPackageWatchdog.onPackagesReady();}}
}
在AMS中会处理PHASE_ACTIVITY_MANAGER_READY
,经过这个阶段后,也就是需要在下一个阶段PHASE_THIRD_PARTY_APPS_CAN_START
才可以发送广播。
同步问题
在修改了SDK之后,可能出现同步错误:
此时我们需要去修改AGP插件中的一个类:MockableJarGenerator
在我的工程当中当前使用的AGP版本为:7.2.1,从C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\com.android.tools.build\builder\7.2.1
目录下找到builder-7.2.1-sources.jar 并将其解压,找到com.android.builder.testing
中的MockableJarGenerator。
将此类放入Android Studio工程app模块的单元测试中,并在app的gradle中加入:
dependencies { testImplementation 'org.ow2.asm:asm:7.1'testImplementation 'org.ow2.asm:asm-commons:7.1'// testImplementation 'com.google.guava:guava:23.6-jre'testImplementation group:'com.google.guava', name:'guava', version:'23.6-jre'
}
操作步骤为:
最后将C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\com.android.tools.build\builder\7.2.1
中builder-7.2.1.jar的MockableJarGenerator.class
替换成刚刚编译的class文件。