在Android 11自定义系统中创建AIDL接口与SystemService通信报错
解决方案
针对Android 11自定义系统中公开AIDL接口的编译错误问题,需要严格遵循系统SDK接口的发布规范,以下是具体步骤:
1. 调整AIDL文件结构与构建配置
- 不要将AIDL直接放在
android.os包下,建议新建专属包(如android.test),将ITest.aidl放在frameworks/base/core/java/android/test/路径下,接口名统一加I前缀符合系统命名规范:package android.test; interface ITest { void test(); } - 在
frameworks/base/Android.bp中添加AIDL接口的构建配置,明确标记为公开SDK接口:
该配置会让构建系统生成符合公开SDK规范的Java代码,解决"RawAidl接口不能暴露"的错误。aidl_interface { name: "android.test.ITest", srcs: ["core/java/android/test/ITest.aidl"], stability: "vintf", sdk_version: "current", }
2. 修复注解与异常处理问题
- 空注解:为AIDL方法的参数、返回值添加
@Nullable或@NonNull注解,比如:package android.test; import android.annotation.Nullable; interface ITest { void test(@Nullable String input); } - RemoteException处理:系统公开接口不能直接抛出RemoteException,需通过Manager类封装调用,将其转为系统RuntimeException。
3. 实现Manager类封装服务调用
创建TestManager作为应用访问服务的入口,封装AIDL调用并处理异常,放在frameworks/base/core/java/android/test/TestManager.java:
package android.test; import android.os.RemoteException; public class TestManager { private final ITest mService; public TestManager(ITest service) { mService = service; } public void test() { try { mService.test(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }
4. 注册服务并暴露访问入口
- 在
SystemService启动TestService后,将其注册到ServiceManager:ServiceManager.addService(Context.TEST_SERVICE, new TestService()); - 在
Context类中添加服务常量:public static final String TEST_SERVICE = "test"; - 在
ContextImpl的getSystemService方法中添加分支,返回TestManager实例:case TEST_SERVICE: return new TestManager(ITest.Stub.asInterface(ServiceManager.getService(TEST_SERVICE)));
5. 配置公开SDK接口
- 确保
TestManager和ITest被加入公开SDK,编译时系统会自动更新frameworks/base/api/current.txt,若需手动补充,添加对应类和方法的声明。 - 若服务需要权限控制,在
TestManager的方法上添加@RequiresPermission注解,同时在系统AndroidManifest.xml中声明权限。
完成以上步骤后,重新编译系统镜像,即可生成符合规范的公开接口,外部应用可通过Context.getSystemService(TestManager.class)或getSystemService(Context.TEST_SERVICE)获取实例并调用方法。
内容的提问来源于stack exchange,提问作者tyczj




