一、整体架构:两层服务,两套查找机制
你的服务分为两个层次,分别用不同的"服务管理器"管理:
-
系统服务层 (
TestService)-
运行在
system_server进程中 -
通过
ServiceManager(servicemanager)发布,名为"testtld" -
上层 App 通过
ServiceManager.getService("testtld")获取 -
对应接口:
ITestHalManager
-
-
HAL 层(C++ 编译的独立进程)
-
运行在独立进程
android.hardware.testtld-service中 -
通过
hwservicemanager(或直接注册到servicemanager,当前暂时如此)发布 -
描述符为
"android.hardware.testtld.IHelloTest",实例名为"default" -
系统服务通过
IHelloTest.DESCRIPTOR + "/default"找到它 -
对应接口:
IHelloTest(由 AIDL 生成)
-
交互链路:
应用层 → ServiceManager.getService("testtld") → ITestHalManager → TestService → IHelloTest.Stub.asInterface() → HAL 服务
二、代码组件一览
1. AIDL 接口定义
HAL 接口: hardware/interfaces/testtld/aidl/android/hardware/testtld/IHelloTest.aidl
java
package android.hardware.testtld;
@VintfStability
interface IHelloTest {
int getTestOne(in int event, in String name);
void test_write(String str);
String test_read();
}
由此生成 Java 绑定 android.hardware.testtld-V1-java。
系统内部接口: frameworks/base/core/java/android/hardware/testtld/ITestHalManager.aidl
java
package android.hardware.testtld;
/**
* {@hide}
*/
interface ITestHalManager {
void testhal_write(String str);
String testhal_read();
}
由此生成 ITestHalManager.Stub,供 TestService 发布。
2. Java 系统服务 TestService.java
路径:frameworks/base/services/core/java/com/android/server/testtld/TestService.java
核心代码:
java
import android.hardware.testtld.IHelloTest;
import android.hardware.testtld.ITestHalManager;
public class TestService extends SystemService {
private IHelloTest mVintfTestHal = null;
private ITestHalManager mTestHalManager = null;
private final class TestHalManagerServiceImpl extends ITestHalManager.Stub {
@Override
public void testhal_write(String str) throws RemoteException {
if (mVintfTestHal != null) {
mVintfTestHal.test_write(str); // 调用 HAL
}
}
@Override
public String testhal_read() throws RemoteException {
if (mVintfTestHal != null) {
return mVintfTestHal.test_read();
}
return "";
}
}
public TestService(Context context) {
super(context);
IBinder binder = Binder.allowBlocking(
ServiceManager.waitForDeclaredService(IHelloTest.DESCRIPTOR + "/default"));
if (binder != null) {
mVintfTestHal = IHelloTest.Stub.asInterface(binder);
}
mTestHalManager = new TestHalManagerServiceImpl();
}
@Override
public void onStart() {
publishBinderService("testtld", (IBinder) mTestHalManager);
}
}
关键字符串映射:
IHelloTest.DESCRIPTOR="android.hardware.testtld.IHelloTest"HAL 服务全名 =
"android.hardware.testtld.IHelloTest/default"系统服务发布名 =
"testtld"
3. C++ HAL 服务实现
路径:hardware/interfaces/testtld/service.cpp(示例)
java
using namespace aidl::android::hardware::testtld;
ndk::ScopedAStatus HelloTest::test_write(const std::string& str) {
ALOGD("test_write: %s", str.c_str());
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus HelloTest::test_read(std::string* _aidl_return) {
*_aidl_return = "hello from HAL";
return ndk::ScopedAStatus::ok();
}
// 注册服务
int main() {
...
std::shared_ptr<HelloTest> service = ndk::SharedRefBase::make<HelloTest>();
binder_status_t status = AServiceManager_addService(service->asBinder().get(), "android.hardware.testtld.IHelloTest/default");
...
}
三、AIDL 接口冻结与版本控制(重点概念)
为什么需要冻结?
-
保证硬件接口的兼容性,防止签名被意外修改。
-
冻结后,系统会生成哈希记录,如果 AIDL 改动,编译时会报错强制升版本。
冻结的时机
修改接口之后 ,确认内容不再变化时执行 freeze-api。
正确顺序:先改 .aidl → 再冻结 → 最后编译绑定。
兼容 vs 不兼容修改
| 改动类型 | 是否需要升级版本 | 举例 |
|---|---|---|
| 新增方法 | 不需要(兼容) | 增加 test_write,保留 getTestOne |
| 删除方法、改方法名、改参数 | 必须升版本(例如 V2) | 删除 getTestOne 或修改其参数 |
如何冻结(兼容性修改)
bash
m android.hardware.testtld-freeze-api # 更新 V1 冻结记录
m android.hardware.testtld-V1-java # 重新编译 java 绑定
Android.bp 中 versions_with_info 无需改动,保持 "1"。
如何升级版本(不兼容修改)
-
修改
Android.bp,新增 V2 版本信息(保留 V1) -
修改
.aidl -
m android.hardware.testtld-freeze-api -
在依赖处改用
android.hardware.testtld-V2-java
四、SELinux 配置(设备专用目录)
所有规则文件放在 device/<vendor>/<board>/sepolicy/ 下,并在 BoardConfig.mk 中添加:
bash
BOARD_SEPOLICY_DIRS += device/<vendor>/<board>/sepolicy
需要创建/修改的文件
1. service.te --- 定义系统服务类型
bash
type testtld_service, service_manager_type;
2. service_contexts --- 系统服务名称与安全类型映射
bash
testtld u:object_r:testtld_service:s0
安全上下文格式:用户:角色:类型:级别
-
u= SELinux 用户(固定) -
object_r= 角色(被动实体,固定) -
testtld_service= 自定义类型(需提前在service.te中定义) -
s0= 安全级别(最低敏感度,固定)
3. hwservice_contexts --- HAL 服务映射(当前 HAL 直接注册在 servicemanager 时可省略,规范做法应通过 hwservicemanager)
bash
android.hardware.testtld.IHelloTest::default u:object_r:hal_testtld_default:s0
4. hal_hellotest.te --- 允许 HAL 进程注册服务
bash
allow hal_hellotest default_android_service:service_manager add;
system_server.te--- 允许 system_server 注册和查找
bash
allow system_server default_android_service:service_manager find;
allow system_server testtld_service:service_manager add;
6. priv_app.te --- 允许 Launcher 查找和调用
bash
allow priv_app testtld_service:service_manager find;
allow priv_app testtld_service:binder { call transfer };
注意 :Launcher 运行在
priv_app域(因为装在/system/priv-app),不是system_app。规则中的源域必须精确匹配进程的实际域。
调试查看拒绝
dmesg | grep avc
五、SELinux 域(Domain)盲区解析
-
域 = 进程的安全标签中的"类型"部分,类似"工作制服"。
-
Android 根据应用安装位置自动分配域:
-
/system/priv-app/→priv_app(黑色制服,高特权,如 Launcher、Settings) -
/system/app/→system_app(蓝色制服,普通系统应用) -
系统服务进程 →
system_server(白色制服)
-
-
权限规则必须源域完全匹配才生效 。给
system_app的权限不会作用于priv_app。 -
如何确认进程域:
ps -Z | grep <进程名>或查看 SELinux 拒绝日志中的scontext=u:r:XXX:s0。
六、Launcher 调用示例
在 Launcher.java 已有的 onCreate 中添加:
java
import android.os.IBinder;
import android.os.ServiceManager;
import android.os.RemoteException;
import android.hardware.testtld.ITestHalManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 原有代码 ...
IBinder binder = ServiceManager.getService("testtld");
if (binder != null) {
ITestHalManager manager = ITestHalManager.Stub.asInterface(binder);
try {
manager.testhal_write("nihao");
} catch (RemoteException e) {
Log.e("Launcher", "write failed", e);
}
}
}
七、调试与排错
查看 SELinux 拒绝日志
在设备终端(adb shell 后 su 获取 root):
bash
logcat -c # 清空缓冲区
# 触发相关操作
logcat -d | grep "avc: denied"
或过滤特定服务:
bash
logcat -d | grep -E "testtld|avc.*denied"
根据拒绝日志补写规则
例如日志:
bash
avc: denied { find } for pid=1134 name=testtld scontext=u:r:priv_app:s0 tcontext=u:object_r:testtld_service:s0 tclass=service_manager permissive=1
需要添加:
bash
allow priv_app testtld_service:service_manager find;
切换 SELinux 模式
-
查看当前模式:
getenforce -
设为宽容模式(不阻断):
setenforce 0 -
设为强制模式(阻断并记录):
setenforce 1
八、快速检查清单
-
AIDL 文件定义清晰,方法与 Java 调用一致
-
HAL
aidl_interface的Android.bp中 Java 后端已启用enabled: true -
services.core的Android.bp中已依赖android.hardware.testtld-V1-java -
系统服务
publishBinderService的名称与service_contexts中的名称完全一致 -
HAL 服务描述符和实例名与 Java 代码中
waitForDeclaredService的参数完全一致 -
设备 sepolicy 目录已正确配置并包含在
BoardConfig.mk中 -
所有
avc: denied日志已通过添加明确规则解决 -
Launcher 所用域(
priv_app)的规则已单独添加