- 1:添加rc文件
- 2:修改Android.bp
- 3:配置SeLinux
- 3.1:设置开机启动服务端
- 3.2:配置HAL
- 3.3:客户端测试
- 4:添加系统服务
- 4.1:创建AIDL文件和LedManager
- 4.2:创建LedService.java
- 4.3:修改Context文件
- 4.4:修改SystemServiceRegistry文件
- 4.5:修改SystemServer文件
- 4.6:添加SeLinux策略
- 4.7:给生成的jar包添加Boot白名单
在上一篇文章中,介绍了HIDL绑定式服务的HAL层的开发与测试。在这篇文章中我们将让HAL服务开机启动,并打通HAL层和Android Framework层。本文将基于AOSP android-10.0.0_r41来进行开发。为了配置简单,已将之前HAL层注册的led-service和manifest.xml的instance该为了默认的default。
HAL服务开机启动
在上一篇文章中,我们创建了绑定式服务,但是却需要我们手动去启动该服务。要想让该服务被init进程进行开机启动就需要rc启动脚本。关于init语言编写请参考官方文档。
添加rc文件
在之前生成的service.cpp目录下添加vendor.melrose.hardware.led@1.0-service.rc文件来让该服务开机启动。
service led /vendor/bin/hw/vendor.melrose.hardware.led@1.0-service
class hal
user system
group system
rc文件会被拷贝到/vendor/etc/init中开机启动。
修改Android.bp
然后修改同目录下的Android.bp,添加init_rc指定启动service的名称:
cc_binary {
name: "vendor.melrose.hardware.led@1.0-service",
relative_install_path: "hw",
init_rc: ["vendor.melrose.hardware.led@1.0-service.rc"],
proprietary: true,
srcs: [
"Led.cpp",
"service.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"liblog",
"vendor.melrose.hardware.led@1.0",
],
}
配置SeLinux
通过init启动的服务需要在各自的 SELinux 域中运行。为了让service能在开机运行:
设置开机启动服务端
创建一个新域
在system/sepolicy/vendor下创建hal_led_default.te
type hal_led_default, domain;
#hal_server_domain(hal_led_default, hal_led)
type hal_led_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_led_default)
hal_server_domain允许域通过HwBinder提供指定类型的HAL实现的域所需的基本权限,为了方便测试服务端是否开机启动暂时屏蔽。
为/vendor/bin/hw/vendor.melrose.hardware.led@1.0-service添加标签
在下system/sepolicy/vendor/file_contexts添加:
/(vendor|system/vendor)/bin/hw/vendor\.melrose\.hardware\.led@1\.0-service u:object_r:hal_led_default_exec:s0
这可确保为该可执行文件添加适当的标签,以便 SELinux在适当的域中运行相应服务。在添加完这些文件重新编译后,在开机时就可以启动该服务,但是不会注册成功。
配置HAL
为了使服务能够注册成功,还需要配置HAL相关的SeLinux,先将之前hal_server_domain的注释放开。
定义HAL名字
在system/sepolicy/public/attributes文件中,需要定义HAL的名称:
hal_attribute(led);
为HAL创建需要的规则
在文件system/sepolicy/public/hwservice.te中添加:
type hal_led_hwservice, hwservice_manager_type;
定义详细规则
在目录system/sepolicy/public目录下创建hal_led.te:
# HwBinder IPC from client to server, and callbacks
binder_call(hal_led_client, hal_led_server)
binder_call(hal_led_server, hal_led_client)
add_hwservice(hal_led_server, hal_led_hwservice)
allow hal_led_client hal_led_hwservice:hwservice_manager find;
然后将system/sepolicy/public目录下的attributes、hwservice.te和hal_led.te覆盖拷贝到system/sepolicy/prebuilts/api/29.0/public目录下。
在system/sepolicy/private/hwservice_contexts文件中添加:
vendor.melrose.hardware.led::ILed u:object_r:hal_led_hwservice:s0
在system/sepolicy/private/compat/26.0/26.0.ignore.cil、system/sepolicy/private/compat/27.0/27.0.ignore.cil和system/sepolicy/private/compat/28.0/28.0.ignore.cil的new_objects中加入:
hal_led_hwservice
并将这3个文件夹下刚刚修改的文件同步到system/sepolicy/prebuilts/api/29.0/private/compat下面的3个文件夹中。并将system/sepolicy/private/hwservice_contexts拷贝到system/sepolicy/prebuilts/api/29.0/private下。
客户端测试
在完成以上配置后,需要重新编译AOSP:
make clean
m
在重新编译完成后,启动模拟器,可以看到运行的进程,并运行之前的客户端就可以看到Logcat打印的信息。
HAL层和应用框架层进行交互
现在,服务可以在开机时自动启动,就可以编写客户段代码与应用进行交互了,有两种方式来编写:
- 编写JNI或者用HIDL生成的JAVA文件和Framework层直接进行交互。
- 首先创建系统服务,在SystemServer进程调用HIDL生成的JAVA文件,然后SystemServer通过AIDL来与App进程进行交互。
Android的应用进程不应该直接访问设备的底层资源,而应该通过SystemServer中的服务代理访问,这样做的目的是为了防止应用进程对系统造成破坏。因此我们采取第二种方法来进行开发。
添加系统服务
创建AIDL文件和LedManager
为了开发效率和代码健壮性,我们使用AndroidStudio进行开发,假设我们需要把AIDL文件和LedManager放在android.melrose.led包中,直接使用AndroidStudio来创建不包含Activity的空项目。
创建AIDL文件
使用AndroidStudio编辑ILedService.aidl并rebuild:
package android.melrose.led;
interface ILedService {
boolean open();
boolean close();
}
将该文件添加到frameworks/base的Android.bp文件的srcs中:
"core/java/android/melrose/led/ILedService.aidl",
创建并编辑LedManager.java
package android.melrose.led;
import android.os.RemoteException;
public class LedManager {
private ILedService mILedService;
public LedManager(ILedService ledService){
mILedService = ledService;
}
public boolean openLed(){
try {
return mILedService.open();
}catch (RemoteException e){
e.printStackTrace();
}
return false;
}
public boolean closeLed(){
try {
return mILedService.close();
}catch (RemoteException e){
e.printStackTrace();
}
return false;
}
}
然后将这两个文件拷贝到frameworks/base/core/java/android/melrose/led文件夹中。
创建LedService.java
将vendor.melrose.hardware.led-V1.0-java库添加到frameworks/base的Android.bp文件的static_libs中:
"vendor.melrose.hardware.led-V1.0-java",
然后make update-api就在out/soong/.intermediates/vendor/melrose/hardware/interfaces/led/1.0生成Java库。
将out/soong/.intermediates/vendor/melrose/hardware/interfaces/led/1.0/vendor.melrose.hardware.led-V1.0-java/android_common/turbine下的jar包引入到项目中。
在AndroidStudio中java目录下创建com.android.server.led包并创建LedService:
package com.android.server.led;
import android.melrose.led.ILedService;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import vendor.melrose.hardware.led.V1_0.ILed;
import vendor.melrose.hardware.led.V1_0.LedStatus;
public class LedService extends ILedService.Stub {
private static final String TAG = "LedService";
private ILed mILed;
public LedService(){
try {
mILed = ILed.getService();
} catch (RemoteException e) {
Log.d(TAG, "LedService: getService Failed !");
}
}
@Override
public boolean open() throws RemoteException {
if (mILed != null){
return mILed.open() == LedStatus.ON;
}
return false;
}
@Override
public boolean close() throws RemoteException {
if (mILed != null){
return mILed.close() == LedStatus.OFF;
}
return false;
}
}
然后将编辑完成的LedService拷贝到frameworks/base/services/core/java/com/android/server/led中。
修改Context文件
将frameworks/base/core/java/android/content/Context.java拖入AndroidStudio中修改@StringDef(suffix = { "_SERVICE" })的value中添加LED_SERVICE。并在下面定义成员变量:
/**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.melrose.led.LedManager} for controlling led.
*/
public static final String LED_SERVICE = "led";
修改SystemServiceRegistry文件
将frameworks/base/core/java/android/app/SystemServiceRegistry.java拖入AndroidStudio中修改。在其static代码块中添加代码来注册服务:
import android.melrose.led.LedManager;
import android.melrose.led.ILedService;
registerService(Context.LED_SERVICE, LedManager.class,
new CachedServiceFetcher<LedManager>() {
@Override
public LedManager createService(ContextImpl ctx) {
IBinder iBinder = ServiceManager.getService(Context.LED_SERVICE);
ILedService service = ILedService.Stub.asInterface(iBinder);
return new LedManager(service);
}});
修改SystemServer文件
将frameworks/base/services/java/com/android/server/SystemServer.java拖入AndroidStudio中修改。在startOtherServices方法中添加如下代码来将服务添加:
traceBeginAndSlog("start Led");
try {
ServiceManager.addService(Context.LED_SERVICE,new LedService());
} catch (Throwable e) {
reportWtf("starting led Service", e);
}
traceEnd();
添加SeLinux策略
修改system/sepolicy/public/service.te
在system/sepolicy/public/service.te末尾添加
type led_service, system_api_service, system_server_service, service_manager_type;
将其拷贝到system/sepolicy/prebuilts/api/29.0/public/中。
修改system/sepolicy/private/service_contexts
在其末尾添加如下代码,前面的led必须和Context中定义的常量一致。
led u:object_r:led_service:s0
将其拷贝到system/sepolicy/prebuilts/api/29.0/private/中。
修改system/sepolicy/private/system_server.te
在hal_client_domain部分添加(hal_led为之前定义过的hal_led.te):
hal_client_domain(system_server, hal_led)
将其拷贝到system/sepolicy/prebuilts/api/29.0/private/中。
修改ignore.cil
在system/sepolicy/private/compat/26.0/26.0.ignore.cil、system/sepolicy/private/compat/27.0/27.0.ignore.cil和system/sepolicy/private/compat/28.0/28.0.ignore.cil的new_objects中加入:
led_service
并将这3个文件夹下刚刚修改的文件同步到system/sepolicy/prebuilts/api/29.0/private/compat下面的3个文件夹中。
给生成的jar包添加Boot白名单
在build/make/core/tasks/check_boot_jars/package_whitelist.txt末尾添加:
# led
vendor\.melrose\.hardware\.led\.V1_0
编译framework.jar并导入AndroidStudio
在修改修改完成后就就可以重新编译:
make update-api
m
如何导入到AndroidStudio请参考之前的文章。
开发Android App来控制
这边用了两个按钮来控制:
findViewById<Button>(R.id.btnOpen).setOnClickListener {
val manager = getSystemService(Context.LED_SERVICE) as? LedManager
manager?.openLed()
}
findViewById<Button>(R.id.btnClose).setOnClickListener {
val manager = getSystemService(Context.LED_SERVICE) as? LedManager
manager?.closeLed()
}
注意事项:在开发完成后需要对应用进行签名再安装,否则SeLinux会报如下错误:
selinux: avc: denied { find } for service=led pid=4051 uid=10101 scontext=u:r:untrusted_app:s0:c101,c256,c512,c768 tcontext=u:object_r:led_service:s0 tclass=service_manager permissive=0
要想兼容debug未签名的app可按照该文章修改untrusted_app.te的规则。在安装后就可以点击按钮来调用HAL层的绑定服务了。