某些情况下,在系统研发时,需要加入自定义的SystemServer服务,以便为应用提供自定义的功能。
下面介绍如果添加自定义的SystemServer系统服务。
本示例基于Android 5.1版本,如果是其他的android版本,可参考。
以自定义DDTS服务为例,步骤如下:
1、创建自定义服务的aidl文件
创建aidl文件目录:frameworks/base/core/java/android/app
在上面的目录下,创建IDDTSManager.aidl文件,aidl文件中定义需要服务实现的接口
package android.app;
interface IDDTSManager {
boolean setValue(boolean val);
boolean getValue();
}
2、把aidl文件添加到Android.mk中参与编译
打开文件:frameworks/base/Android.mk
在“LOCAL_SRC_FILES”变量中添加aidl的文件。建议找到“app”目录对应的分类,并在后面添加,这样代码工整点。
LOCAL_SRC_FILES += \
......
core/java/android/app/backup/IRestoreSession.aidl \
core/java/android/app/usage/IUsageStatsManager.aidl \
core/java/android/app/IDDTSManager.aidl \
core/java/android/wipower/IWipower.aidl \
3、创建DDTSManagerService.java文件实现IDDTSManager.aidl中定义的接口
创建目录:frameworks/base/services/core/java/com/android/server
PS:如果服务端文件比较多,或者想把服务器文件放在同一个文件夹下,可以创建个文件夹存放
如:frameworks/base/services/core/java/com/android/server/DDTS,如果定义了自定义目录,注意DDTSManagerService.java的包名
package com.android.server.DDTS
import android.content.Context;
pulic class DDTSManagerService extends IDDTSManager.stub {
private final Context mContext;
private boolean mVal;
public DDTSManagerService(Context context) {
mContext = context;
}
@Override
public boolean setValue(boolean val) {
mVal = val;
return true;
}
@Override
public boolean getValue() {
return mVal;
}
}
4、在SystemServer中注册自定义的Service
打开文件:frameworks/base/services/java/com/android/server/SystemServer.java
在private void startOtherServices()函数中添加自定义的Service
try {
Slog.i(TAG,"DDTS Service");
ServiceManager.addService(Context.DDTS_SERVICE, new DDTSManagerService(context));
} catch (Throwable e) {
reportWtf("starting DDTS Service fail:",e);
}
在addService中的Context.DDTS_SERVICE为服务端的名称。
DDTS_SERVICE要在Context.java中添加
打开文件:frameworks/base/core/java/android/content/Context.java
添加
public static final String DDTS_SERVICE = "ddts";
5、创建DDTSManager.java文件
DDTSManager.java主要是给应用调用的类,DDTSManager通过binder调用到DDTSManagerService实现的aidl接口。完成最终的服务。
创建目录:frameworks/base/core/java/android/app
package android.app;
import android.content.Context;
public class DDTSManager
{
private static IDDTSManager mService;
private final Context mContext;
DDTSManager(Context context) {
mContext = context;
mService = IDDTSManager.Stub.asInterface(ServiceManager.getService(Context.DDTS_SERVICE));
}
public boolean setValue(boolean val) {
try {
return mService.setValue(val);
} catch (RemoteException e){
return false;
}
}
public boolean getValue() {
try {
return mService.getValue();
} catch (RemoteException e){
return false;
}
}
}
6、把DDTSManager注册到ContextImpl中
在ContextImpl.java中的static{}代码中,添加注册代码,DDTSManager通过registerService函数注册服务,这样应用可以调用getSystemService获取到DDTSManager,从而调用DDTSManager中的接口,最终调用到DDTSManagerService
registerService(DDTS_SERVICE,new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new DDTSManager(ctx.getOuterContext());
}});
7、添加SELinux Policy权限
打开文件:external/sepolicy/service_contexts
在文件中添加:
ddts u:object_r:system_server_service:s0
其中:ddts为SystemServer注册服务时ServiceManager.addService函数中的Context.DDTS_SERVICE,也就是服务的名称。
8、编译framework.jar和Service.jar,并替换手机中的相应jar包。
写一个apk测试服务是否能用。
1、在Android studio中新建一个android library的项目。
包名命名为:android.app(这个包名必须和DDTSManager.java的包名一致)
并在android/app目录下创建一个java文件,文件名称和内容与DDTSManager.java一致。
创建这个工程主要是因为要得到一个DDTSManager文件对应的jar,把这个jar包放在apk工程中,这样编译apk时不会报错。
2、新建一个apk工程,并把DDTSManager文件对应的jar包放入到apk工程的libs目录下。
把apk工程中的build.gradle文件的dependecies中增加provided依赖
dependencies {
provided fileTree(include: ['*.jar'], dir: 'libs')
//compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile files('libs/DDTSManager.jar')
}
编译好apk后,就可以在手机上验证了。