Google Play重签名后AIDL跨应用signature权限绑定报错解决
问题现象
应用运行时抛出异常:
java.lang.RuntimeException: Unable to create application XXX: java.lang.SecurityException: Not allowed to bind to service Intent
故障场景为两个应用通过AIDL实现跨进程通信:服务端应用提供AIDL接口实现,自定义应用权限,对外服务设置为可导出、配置意图过滤器并绑定上述自定义权限;客户端应用声明使用该权限,主动绑定服务端服务。
相关配置
服务端应用Manifest配置
<manifest package="com.my.server"> ... <permission android:name="com.my.app_permission" android:protectionLevel="signature" /> <application ... <service android:name="com.my.MyService" android:exported="true" android:permission="com.my.app_permission"> <intent-filter> <action android:name="my_aidl" /> </intent-filter> </service> </application> </manifest>
客户端应用Manifest配置
<manifest package="com.my.client"> ... <queries> <package android:name="com.my.server" /> </queries> <uses-permission android:name="com.my.app_permission"/> <application android:name=".App" ... </application> </manifest>
客户端Application绑定逻辑
class App: Application() { override fun onCreate() { super.onCreate() if (serverAppInstalled()) { bindService( Intent().apply { action = "my_aidl" package = "com.my.server" }, serviceConnection, Context.BIND_AUTO_CREATE ) } } ... }
注:示例代码中onCreate缺少override修饰符和super调用,属于笔误,实际运行需补全。
测试验证结果
- 每次测试前完全卸载设备上的两个相关应用,安装顺序固定为先装服务端、再装客户端
- 本地Debug构建包、使用同一签名密钥签署的本地Release APK均可正常运行
- 两个应用的AAB包上传至Google Play内部测试渠道后,运行时固定抛出上述SecurityException异常
- 移除自定义权限的
protectionLevel配置后,跨进程绑定功能可正常运行 - 根因确认:Google Play基于上传的AAB包针对不同设备配置拆分生成对应APK时,会执行重签名操作;若两个应用未配置共享签名密钥,重签名后两个应用签名不一致,无法通过
signature级别的系统权限校验。
可行解决方案
按改造成本从低到高排序:
配置Play应用签名密钥共享
两个应用归属同一Google Play开发者账号时,可在Play管理中心将两个应用加入同一签名组,共享同一个应用签名密钥,保证Play重签名后两个应用签名一致,原有signature级别权限逻辑无需任何修改即可正常运行,是改造成本最低的方案。替换系统权限校验为自定义签名校验
放弃Manifest中配置的signature级别权限控制,在服务端的Service生命周期中自行做调用方合法性校验:- 移除服务端Manifest中service节点的
android:permission属性,移除自定义的signature级别权限声明,移除客户端Manifest中对应的uses-permission声明 - 服务端重写Service的
onBind方法,通过Binder.getCallingUid()获取调用方uid,再通过PackageManager.getPackagesForUid()、PackageManager.getPackageInfo()获取调用方包名和签名信息 - 校验调用方包名是否为约定的客户端包名,同时比对调用方签名哈希是否和预先内置的、客户端在Play渠道发布后的正式签名哈希完全一致,校验通过再返回IBinder实例,否则直接返回null拒绝绑定
该方案完全不依赖系统的signature权限机制,不受任何应用商店重签名逻辑影响,兼容性最强,注意内置的签名哈希需要做代码混淆和字符串加密,避免被反编译篡改。
- 移除服务端Manifest中service节点的
适配Android 11+的签名权限已知签署者配置
如果应用仅需适配Android 11(API 30)及以上版本,可在服务端自定义权限声明时增加knownCertificates属性,直接写入客户端正式签名的证书摘要,系统在做权限校验时会直接匹配证书摘要,不再要求两个应用必须由同一个密钥签名,不过该方案对低版本Android不兼容,适用场景有限。
注意:不要为了临时解决问题直接移除权限校验、或者将权限protectionLevel设为normal,会导致服务被任意第三方应用随意绑定,存在严重的安全风险。
内容的提问来源于stack exchange,提问作者Dmytro Batyuk
相关产品推荐
相关产品推荐

