其实在之前我们介绍系统服务得实现过程得时候就已经将系统服务的实现流程总结出来了,那么今天我们就按照之前总结出来得流程去一步步实现一个属于自己得系统服务,为了把跟多得精力放到流程上来,我们得系统服务先以最简单得方式进行,我们的系统服务只提供一个保存String数据得Map集合,并向上层应用提供putString()以及getString()方法。
为了能更好的理解接下来得内容,建议先看看android系统服务实现原理详解
1、创建IHelloService.aidl文件
首先创建aidl文件之前我们,建议我们自己在framework层添加得所有文件都自己创建一个文件夹去放,这里我们在
framework/base/core/java/android下创建一个light文件夹,在light下创建IHelloService.aidl
// IHelloService.aidl
package android.light;
// Declare any non-default types here with import statements
interface IHelloService {
void putString(String key,String value);
String getString(String key);
}
这里我们定义了两个方法,putString()和getString()
2、创建HelloServiceImpl.java实现IHelloService.Stub,并在Contex中定义服务的唯一标识字符串。
同样的,创建HelloServiceImpl我们习惯将它放在framework/base/service目录下,我这里放在了
framework/base/service/java/com/light/server下,这些不强制,看个人喜好,不过包名得记住,后面输出jar包辅助上层应用开发时很关键。
package com.light.server;
import android.os.RemoteException;
import android.util.Log;
import java.util.HashMap;
import android.light.IHelloService;
/**
* Created by server on 18-6-20.
*/
public class HelloServiceImpl extends IHelloService.Stub {
public static final String TAG = "RWJ HelloService";
private final HashMap map = new HashMap<>();
@Override
public void putString(String key, String value) throws RemoteException {
if (key == null || key.length() == 0 || value == null || value.length == 0){
throw new RemoteException();
}
String put = map.put(key, value);
Log.d(TAG,"putString==============")
}
@Override
public String getString(String key) throws RemoteException {
if (key == null || key.length() == 0){
throw new RemoteException();
}
Log.d(TAG,"getString==============")
return map.get(key);
}
}
PS:这里一定要注意import android.light.IHelloService;这个包名得正确性
接着我们去Context中添加服务唯一标识:
/**
* M: comment @{ add LIGHT service
*/
public static final String LIGHT_TEST_SERVICE = "light-service";
/// @}
3、创建创建HelloManager.java内部维护了通过ServiceManager获取到的HelloServiceImpl实例
这里我们将HelloManager.java放在我们之前创建得light目录下
framework/base/core/java/android/light
package android.light;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
/**
* Created by server on 18-6-20.
*/
public class HelloManager {
public static final String TAG = "RWJ HelloManager";
private IHelloService mService;
public HelloManager(Context ctx) {
mService = IHelloService.Stub.asInterface(ServiceManager.getService("light-service"));
}
public void putString(String key,String value) throws RemoteException {
mService.putString(key,value);
}
public String getString(String key) throws RemoteException {
return mService.getString(key);
}
}
4、在SystemServiceRegistry.java中通过registerService()方法创建创建HelloManager实例
//注意包名正确性
import android.light.HelloManager;
static {
registerService(Context.LIGHT_TEST_SERVICE, HelloManager.class,
new CachedServiceFetcher() {
@Override
public HelloManager createService(ContextImpl ctx) {
return new HelloManager(ctx);
}});
//此处省略无数行代码
}
5、在SystemServer.java中将HelloServiceImpl添加到ServiceManager中
import com.light.server.HelloServiceImpl;
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored
* and organized.
*/
private void startOtherServices() {
try {
HelloServiceImpl helloService = new HelloServiceImpl();
Slog.e(TAG, "Create HelloService successfully .");
// Add this service to service manager
ServiceManager.addService(Context.LIGHT_TEST_SERVICE,helloService);
} catch (Throwable e) {
Slog.e(TAG, "Starting HelloService exception ", e);
}
//省略一万行代码
}
至此,我们的编码任务就完成了,那么接下来我们就需要进行编译了!!!!
对源码进行修改我们时需要重新编译,这里我不太确定是否可以只对framework进行模块编译,没试过,其实如果之前有编译过得话,再进行一次全编并不花很多时间,也是十分钟左右,所以我这里进行了全编的!
1、开始编译之前我们需要先配置aidl
framework/base/Android.mk
LOCAL_SRC_FILES += \
core/java/android/light/IHelloService.aidl\
core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
core/java/android/accounts/IAccountManager.aidl \
#此处省略一万行。。。
2、接着是配置权限的问题
由于SELinux安全策略的原因,理论上如果Service如果需要注册到ServiceManager中的话是需要为该服务配置对应得TE规则的,否则编译阶段就会报错了,但是由于我第一次的时候忘记配置了直接就编译了,但是没报错,能够访问到服务!这里为什么会成功原因还不清楚,为了安全起见,还是添加了吧,毕竟按规矩来会比较好:
首先在/device/mediatek/common/sepolicy/bsp/service.te 文件中进行类型声明:
type light_service, service_manager_type;
在/device/mediatek/common/sepolicy/bsp/service_contexts 文件中配置安全上下文:
HelloServiceImpl u:object_r:light_service:s0
这里HelloserviceImpl是我们的类名,而light_service自定义即可,相当于起了个别名!
接着分别在下列文件中添加如下配置:
/device/mediatek/common/sepolicy/bsp/system_app.te allow system_app light_service:service_manager { add find };
/device/mediatek/common/sepolicy/bsp/system_server.te allow system_server light_service:service_manager { add find };
/device/mediatek/common/sepolicy/bsp/untrusted_app.te allow untrusted_app light_service:service_manager find;
/device/mediatek/common/sepolicy/bsp/platform_app.te allow platform_app light_service:service_manager { add find };
这里可能会有很多朋友会问这些都是什么东西,说起来很复杂,整个TE了规则要细说起来还是有很多东西的!不太了解的朋友推荐篇文章给大家看看吧,看了这几篇文章基本可以知道TE规则怎么写、具体有什么用了,这里就不细说!
SEandroid浅谈
android的安全机制
SELinux策略语言--类型强制(编写TE规则)
至此,我们就可以正常的去编译,然后刷机了!
当然,我们在make之前记得先make update-api,因为framework更新了新得api,要执行该语句才会有效果的!!
小提示:当我们开发的时候,由于androidSDK中并不包含我们所需的HelloManager这样的类,所以我们的下面代码时会报错的
HelloManager manager = getSystemService("light-service");
这时候我们可以将我们在源码中添加的包打一个jar出来供开发阶段使用,打包时忽略掉即可!
好了,自定义服务到此就完成了!周末愉快!!^_^!