AOSP - 完善HAL绑定服务

文章目录[x]
  1. 1:添加rc文件
  2. 2:修改Android.bp
  3. 3:配置SeLinux
  4. 3.1:设置开机启动服务端
  5. 3.2:配置HAL
  6. 3.3:客户端测试
  7. 4:添加系统服务
  8. 4.1:创建AIDL文件和LedManager
  9. 4.2:创建LedService.java
  10. 4.3:修改Context文件
  11. 4.4:修改SystemServiceRegistry文件
  12. 4.5:修改SystemServer文件
  13. 4.6:添加SeLinux策略
  14. 4.7:给生成的jar包添加Boot白名单

上一篇文章中,介绍了HIDL绑定式服务的HAL层的开发与测试。在这篇文章中我们将让HAL服务开机启动,并打通HAL层和Android Framework层。本文将基于AOSP android-10.0.0_r41来进行开发。为了配置简单,已将之前HAL层注册的led-servicemanifest.xmlinstance该为了默认的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.tehal_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.cilsystem/sepolicy/private/compat/27.0/27.0.ignore.cilsystem/sepolicy/private/compat/28.0/28.0.ignore.cilnew_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.aidlrebuild

package android.melrose.led;

interface ILedService {

boolean open();

boolean close();

}

将该文件添加到frameworks/baseAndroid.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/baseAndroid.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包引入到项目中。

AndroidStudiojava目录下创建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.cilsystem/sepolicy/private/compat/27.0/27.0.ignore.cilsystem/sepolicy/private/compat/28.0/28.0.ignore.cilnew_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层的绑定服务了。

 

 

 

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像

Title - Artist
0:00