Android 添加系统服务的方法( 二 )

代码很简单, 就封装了下AIDL接口, 定义了系统服务注册时用的名字.
public SystemEventManager(Context context, ISystemEvent service)构造函数中的 ISystemEvent 参数在后面注册Manager时候会通过Binder相关接口获取.
编译代码, 确保没有错误, 下面编写系统服务.
四、 编写系统服务路径以及代码如下:
frameworks/base/services/core/java/com/android/server/example/SystemEventService.java
package com.android.server.example;import android.content.Context;import android.os.Binder;import android.os.RemoteCallbackList;import android.os.RemoteException;import android.os.ServiceManager;import android.util.Log;import com.example.utils.ISystemEvent;import com.example.utils.IEventCallback;public class SystemEventService extends ISystemEvent.Stub { private static final String TAG = SystemEventService.class.getSimpleName(); private RemoteCallbackList<IEventCallback> mCallbackList = new RemoteCallbackList<>(); private Context mContext; public SystemEventService(Context context) { mContext = context; Log.d(TAG, "SystemEventService init"); } @Override public void registerCallback(IEventCallback callback) { boolean result = mCallbackList.register(callback); Log.d(TAG, "register pid:" + Binder.getCallingPid() + " uid:" + Binder.getCallingUid() + " result:" + result); } @Override public void unregisterCallback(IEventCallback callback) { boolean result = mCallbackList.unregister(callback); Log.d(TAG, "unregister pid:" + Binder.getCallingPid() + " uid:" + Binder.getCallingUid() + " result:" + result); } @Override public void sendEvent(int type, String value) { sendEventToRemote(type, value + " remote"); } public void sendEventToRemote(int type, String value) { int count = mCallbackList.getRegisteredCallbackCount(); Log.d(TAG, "remote callback count:" + count); if (count > 0) { final int size = mCallbackList.beginBroadcast(); for (int i = 0; i < size; i++) { IEventCallback cb = mCallbackList.getBroadcastItem(i); try { if (cb != null) { cb.onSystemEvent(type, value); } } catch (RemoteException e) { e.printStackTrace(); Log.d(TAG, "remote exception:" + e.getMessage()); } } mCallbackList.finishBroadcast(); } }}服务端继承自 ISystemEvent.Stub, 实现对应的三个方法即可, 需要注意的是, 由于有回调功能, 所以要把注册的 IEventCallback 加到链表里面, 这里使用了 RemoteCallbackList, 之所以不能使用普通的 List 或者 Map, 原因是, 跨进程调用, App调用 registerCallback 和 unregisterCallback 时, 即便每次传递的都是同一个 IEventCallback 对象, 但到服务端, 经过跨进程处理后, 就会生成不同的对象, 所以不能通过直接比较是否是同一个对象来判断是不是同一个客户端对象, Android中专门用来处理跨进程调用回调的类就是 RemoteCallbackList, RemoteCallbackList 还能自动处理App端异常死亡情况, 这种情况会自动移除已经注册的回调.
RemoteCallbackList 使用非常简单, 注册和移除分别调用 register() 和 unregister() 即可, 遍历所有Callback 稍微麻烦一点, 代码参考上面的 sendEventToRemote() 方法.
可以看到, 我们测试用的的系统服务逻辑很简单, 注册和移除 Callback 调用 RemoteCallbackList 对应方法即可, sendEvent() 方法在App端调用的基础上, 在字符串后面加上 " remote" 后回调给App, 每个方法也加了log方便理解流程, 服务端代码就完成了.
五、 注册系统服务代码写好后, 要注册到SystemServer中, 所有系统服务都运行在名为 system_server 的进程中, 我们要把编写好的服务加进去, SystemServer中有很多服务, 我们把我们的系统服务加到最后面, 对应路径和代码如下:
frameworks/base/services/java/com/android/server/SystemServer.java
import com.android.server.example.SystemEventService;import com.example.utils.SystemEventManager;/** * Starts a miscellaneous grab bag of stuff that has yet to be refactored * and organized. */private void startOtherServices() { // 部分代码省略... // start SystemEventService try { ServiceManager.addService(SystemEventManager.SERVICE, new SystemEventService(mSystemContext)); } catch (Throwable e) { reportWtf("starting SystemEventService", e); } // 部分代码省略...}通过 ServiceManager 将服务加到SystemServer中, 名字使用 SystemEventManager.SERVICE, 后面获取服务会通过名字来获取. 此时, 如果直接编译运行, 开机后会出现如下错误:
E SystemServer: java.lang.SecurityExceptionE SElinux : avc: denied { add } for service=test_systemevent pid=1940 uid=1000 scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=0这个是没有Selinux权限, 我们需要加上添加服务的权限, 代码如下:
首先定义类型, test_systemevent 要和添加服务用的名字保持一致


推荐阅读