基于Android源码添加一个系统服务
服务(Service)是Android四大组件之一,而系统服务则是Android中非常重要的一部分, 像ActivityManagerService, PackageManagerService, WindowManagerService, 这些系统服务都是Framework层的关键服务。日常开发中都不可避免要使用到服务,部分需求无法在App应用层面实现,则需要通过添加自定义的系统服务才方便实现及管理。那么如何基于Android源码添加一个系统服务:
1、编写AIDL文件
添加服务首先是编写AIDL文件, AIDL文件一般添加到如下路径下:frameworks/base/core/java/com/android/led
1.1 ILedService.aidl 内容如下:
package android.led;
interface ILedService {
void systemReady();
void updatePowerLed();
......
}
1.2 将 ILedService.aidl 加入编译
修改 frameworks/base/Android.bp 文件,
在 LOCAL_SRC_FILES += \ 后参考core/java/android/os/IUserManager.aidl \ 的写法,
添加一行
core/java/android/led/ILedService.aidl \
2、编写Manager类
Android API 中有很多Manager类, 这些类一般都是某个系统服务的客户端代理类, 其实我们不写Manager类, 只通过AIDL文件自动生成的类, 也可以完成功能, 但封装一下AIDL接口使用起来更方便, 我们测试用的Manager类为 LedManager, 在 frameworks/base/core/java/android/led/ 目录创建LedManager.java
package android.led;
import android.led.ILedService;
import android.os.RemoteException;
import android.annotation.NonNull;
public class LedManager {
private final ILedService ledService;
public LedManager(@NonNull ILedService ledService) {
this.ledService = ledService;
}
public void systemReady(){
try {
ledService.systemReady();
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void updatePowerLed(){
try {
ledService.updatePowerLed();
} catch (RemoteException e) {
e.printStackTrace();
}
}
...
...
}
3、创建系统服务 LedService
在 frameworks/base/services/core/java/com/android/server/ 目录创建 ThunderService.java,
构造函数是否传入 Context 参数可按照需求来定,参考系统其他 Service 的写法,一般是会传入的。
package com.android.server;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
...
public class LedService extends ILedService.Stub {
private final String TAG = "LedService";
public LedService(@NonNull Context context){
super();
this.mContext = context;
}
@Override
public void systemReady() throws RemoteException {
}
@Override
public void updatePowerLed() throws RemoteException {
}
...
...
}
4、将自定义 LedService 加入到 SystemServer
4.1 修改 frameworks/base/core/java/android/content/Context.java ,添加如下:
+ /**
+ * Add for LedService
+ */
+ public static final String THUNDER_SERVICE = "led";
4.2 修改 frameworks/base/services/java/com/android/server/SystemServer.java ,在 startOtherServices() 方法中添加如下:
+ //add by chyb for led service
+ t.traceBegin("StartLedService");
+ ServiceManager.addService(Context.LED_SERVICE, new LedService(mSystemContext));
+ t.traceEnd();
+ //add by chyb end
可参考原生的系统服务添加,格式类似。
5、将 ThunderManager 注册到 SystemService
修改 frameworks/base/core/java/android/app/SystemServiceRegistry.java
文件,添加:
+ //add for led service
+ registerService(Context.LED_SERVICE, LedManager.class,
+ new CachedServiceFetcher<LedManager>() {
+ @Override
+ public LedManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.LED_SERVICE);
+ Log.i("add_service_led","SystemServiceRegistry registerService method");
+ return new LedManager(ILedService.Stub.asInterface(b));
+ //return new DisplayHashManager();
+ }});
+ //add end
6、添加 selinux 权限
修改system/sepolicy/private/service_contexts文件,添加:
+led u:object_r:led_service:s0
修改system/sepolicy/public/service.te文件,添加
+type led_service, system_api_service, system_server_service, service_manager_type;
7、重新编译系统api : make update-api
修改 framework 下的源码后,需要先执行 make update-api ,
此操作会更新如下文件:
frameworks/base/api/system-current.txt
frameworks/base/api/system-removed.txt
然后再执行 make 编译即可。
8、编写APP测试
两种方式进行调用
(1)在源码的 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/ 目录下会生成 classes.jar 文件,
这个就是编译生成的 framework 依赖包,将其导入 AndroidStudio 工程就使用 LedManager 了。
(2)通过拷贝LedManager 与aidl文件到工程中,注意包名要与ledManager与aidl一致,如图所示:
代码示例:
LedManager ledManager =(LedManager) getSystemService("led");
ledManager.updatePowerLed();
然后就可以愉快的进行调用调试了