system/sepolicy/service_contexts
wifiscanner u:object_r:wifiscanner_service:s0wifi u:object_r:wifi_service:s0window u:object_r:window_service:s0# 部分代码省略...test_systemevent u:object_r:test_systemevent_service:s0* u:object_r:default_android_service:s0system/sepolicy/service.te
# 加入刚刚定义好的 test_systemevent_service 类型, 表明它是系统服务type test_systemevent_service, system_api_service, system_server_service, service_manager_type;加入上面代码后, 编译刷机开机后, 服务就能正常运行了.
六、注册Manager系统服务运行好了, 接下来就是App怎么获取的问题了, App获取系统服务, 我们也用通用接口:
context.getSystemService()
在调用 getSystemService() 之前, 需要先注册, 代码如下:
frameworks/base/core/java/android/app/SystemServiceRegistry.java
import com.example.utils.ISystemEvent;import com.example.utils.SystemEventManager;static {// 部分代码省略, 参考其他代码, 注册Manger registerService(SystemEventManager.SERVICE, SystemEventManager.class, new CachedServiceFetcher<SystemEventManager>() { @Override public SystemEventManager createService(ContextImpl ctx) { // 获取服务 IBinder b = ServiceManager.getService(SystemEventManager.SERVICE); // 转为 ISystemEvent ISystemEvent service = ISystemEvent.Stub.asInterface(b); return new SystemEventManager(ctx.getOuterContext(), service); }});}注册后, 如果你在App里面通过 getSystemService(SystemEventManager.SERVICE); 获取Manager并调用接口, 会发现又会出错, 又是Selinux权限问题:
E SELinux : avc: denied { find } for service=test_systemevent pid=4123 uid=10035 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:test_systemevent_service:s0 tclass=service_manager permissive=0说是没有 find 权限, 因此又要加权限, 修改代码如下:
system/sepolicy/untrusted_app.te
# 允许 untrusted_app 查找 test_systemevent_serviceallow untrusted_app test_systemevent_service:service_manager find;这个 Selinux 的知识有兴趣自己去学一下, 报了什么权限, 就按照错误信息去对应文件添加权限.
至此, 系统代码修改完成了, 编译系统刷机, 下面通过App调用.
七、App调用文件拷贝和准备:
我们需要复制三个文件到App中, 两个AIDL文件, 一个Manager文件:
IEventCallback.aidlISystemEvent.aidlSystemEventManager.java所有AIDL文件和java文件, 在App工程中的包名和路径都需要和系统保持一致, 这三个文件App不能做任何修改, 除非系统源码中也做对应修改, 总的来说, 这三个文件App和系统中要完全保持一致, 类名包名和包路径都需一致, 复制这三个文件到工程中后, 编译后, 调用方式如下.
获取服务:
SystemEventManager eventManager = (SystemEventManager)context.getSystemService(SystemEventManager.SERVICE);这里Android Studio可能会报 getSystemService() 参数不是Context里面的某个服务的错误, 可以直接忽略, 不影响编译.
注册/取消注册:
eventManager.register(eventCallback);eventManager.unregister(eventCallback);private IEventCallback.Stub eventCallback = new IEventCallback.Stub() { @Override public void onSystemEvent(int type, String value) throws RemoteException { Log.d("SystemEvent", "type:" + type + " value:" + value); }};调用:
eventManager.sendEvent(1, "test string");测试Log如下:
D SystemEventManager: SystemEventManager initD SystemEventService: register pid:3944 uid:10035 result:trueD SystemEventService: remote callback count:1D SystemEvent: type:1 value:test string remoteD SystemEventService: unregister pid:3944 uid:10035 result:true可以看到调用了服务端并成功收到服务端拼接的字符串.
八、添加JNI部分代码我们一般添加系统服务, 可能是为了调用驱动里面的代码, 所有一般要用JNI部分代码, 这里不是讲怎么编写JNI代码, 而是说下系统服务中已有的JNI代码, 我们可以直接在这基础上增加我们的功能.
JNI部分代码位置为:
frameworks/base/services/core/jni/编译对应mk为:
frameworks/base/services/Android.mkframeworks/base/services/core/jni/Android.mk此部分代码直接编译为 libandroid_servers 动态库, 在SystemServer进行加载:
frameworks/base/services/java/com/android/server/SystemServer.java
// Initialize native services.System.loadLibrary("android_servers");如果需要添加JNI部分代码, 直接在 frameworks/base/services/core/jni/目录下增加对应文件,
在frameworks/base/services/core/jni/Android.mk中加入新增文件进行编译即可.
同时按照已有文件中JNI函数注册方式, 写好对应注册方法, 统一在
frameworks/base/services/core/jni/onload.cpp中动态注册函数.
关于JNI动态注册知识, 可参考之前写的一篇文章: 两种JNI注册方式
推荐阅读
- MySQL无锁化WAL系统那些事儿
- 湖北省首家茶博馆 全面系统展示茶文化
- 综合布线系统调试方案
- 大到阿里,小到三线公司,缓存在大型分布式系统中的最佳应用
- Win7系统硬盘分区怎么调整大小
- 日照绿茶“一码”溯源管理系统启动
- 聊聊 Android 的 GUI 系统
- WiFi系统的无线AP与AC之间的各种问题解析
- Web 攻击越发复杂,如何保证云上业务高可用性的同时系统不被入侵?| 专家谈
- 细品Linux系统中文件的三个时间属性