一、整体架构:两层服务,两套查找机制
你的服务分为两个层次,分别用不同的“服务管理器”管理:
系统服务层(
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
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
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
核心代码:
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(示例)
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或修改其参数 |
如何冻结(兼容性修改)
m android.hardware.testtld-freeze-api # 更新 V1 冻结记录 m android.hardware.testtld-V1-java # 重新编译 java 绑定Android.bp中versions_with_info无需改动,保持"1"。
如何升级版本(不兼容修改)
修改
Android.bp,新增 V2 版本信息(保留 V1)修改
.aidlm android.hardware.testtld-freeze-api在依赖处改用
android.hardware.testtld-V2-java
四、SELinux 配置(设备专用目录)
所有规则文件放在device/<vendor>/<board>/sepolicy/下,并在BoardConfig.mk中添加:
BOARD_SEPOLICY_DIRS += device/<vendor>/<board>/sepolicy需要创建/修改的文件
1.service.te— 定义系统服务类型
type testtld_service, service_manager_type;2.service_contexts— 系统服务名称与安全类型映射
testtld u:object_r:testtld_service:s0安全上下文格式:用户:角色:类型:级别
u= SELinux 用户(固定)object_r= 角色(被动实体,固定)testtld_service= 自定义类型(需提前在service.te中定义)s0= 安全级别(最低敏感度,固定)
3.hwservice_contexts— HAL 服务映射(当前 HAL 直接注册在servicemanager时可省略,规范做法应通过hwservicemanager)
android.hardware.testtld.IHelloTest::default u:object_r:hal_testtld_default:s04.hal_hellotest.te— 允许 HAL 进程注册服务
allow hal_hellotest default_android_service:service_manager add;5.system_server.te— 允许 system_server 注册和查找
allow system_server default_android_service:service_manager find; allow system_server testtld_service:service_manager add;6.priv_app.te— 允许 Launcher 查找和调用
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中添加:
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):
logcat -c # 清空缓冲区 # 触发相关操作 logcat -d | grep "avc: denied"或过滤特定服务:
logcat -d | grep -E "testtld|avc.*denied"根据拒绝日志补写规则
例如日志:
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需要添加:
allow priv_app testtld_service:service_manager find;切换 SELinux 模式
查看当前模式:
getenforce设为宽容模式(不阻断):
setenforce 0设为强制模式(阻断并记录):
setenforce 1
八、快速检查清单
AIDL 文件定义清晰,方法与 Java 调用一致
HAL
aidl_interface的Android.bp中 Java 后端已启用enabled: trueservices.core的Android.bp中已依赖android.hardware.testtld-V1-java系统服务
publishBinderService的名称与service_contexts中的名称完全一致HAL 服务描述符和实例名与 Java 代码中
waitForDeclaredService的参数完全一致设备 sepolicy 目录已正确配置并包含在
BoardConfig.mk中所有
avc: denied日志已通过添加明确规则解决Launcher 所用域(
priv_app)的规则已单独添加