定制ROM中系统应用启动Service的问题排查
问题描述
我是定制ROM开发新手,想创建一个系统应用来启动Service。已经在AndroidManifest.xml的<application>标签中添加了android:sharedUserId="android.uid.system",当前使用的是Android 8(API 26)的官方rooted模拟器。
启动Service的代码如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(service); else context.startService(service);
但Service始终无法启动,出现以下错误:
Calling a method in the system process without a qualified user: android.app.ContextImpl.startForegroundService:1466 android.content.ContextWrapper.startForegroundService:649
进一步排查后发现根源错误是SELinux权限拒绝:
type=1400 audit(0.0:31): avc: denied { create } for name="mgmtsocket" scontext=u:r:system_app:s0 tcontext=u:object_r:system_app_data_file:s0 tclass=sock_file permissive=0
补充信息:
- 已使用AOSP平台密钥对APK签名,命令为:
apksigner sign --key platform.pk8 --cert platform.x509.pem filename.apk - 应用权限与Service配置:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <service android:name=".MyService" android:permission="android.permission.BIND_VPN_SERVICE" android:exported="false"> <intent-filter> <action android:name="android.net.VpnService" /> </intent-filter> </service>
解决方案
1. 修复SELinux权限问题
SELinux阻止你的系统应用在system_app_data_file上下文创建套接字,需要添加SEPolicy规则:
- 进入AOSP源码的
device/[厂商]/[设备型号]/sepolicy目录,编辑system_app.te文件,添加:allow system_app system_app_data_file:sock_file create; - 重新编译SEPolicy并刷入模拟器,或者临时执行
adb shell setenforce 0关闭SELinux,验证问题是否解决。
2. 修正用户上下文问题
错误提示启动Service时未指定合格用户,系统应用启动服务必须关联到当前用户上下文:
- 如果是在系统服务中启动,需指定用户ID:
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); UserHandle userHandle = UserHandle.of(userManager.getUserSerialNumber()); Context userContext = context.createPackageContextAsUser(context.getPackageName(), 0, userHandle); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { userContext.startForegroundService(service); } else { userContext.startService(service); } - 如果是在Activity中启动,直接用Activity的
this作为Context,不要用getApplicationContext()。
3. 满足VPN Service的特殊要求
你的Service声明为VpnService,这类服务有强制权限要求:
- 启动前必须调用
VpnService.prepare()获取授权:Intent prepareIntent = VpnService.prepare(context); if (prepareIntent != null) { // Activity中需启动此Intent让用户授权 startActivityForResult(prepareIntent, 1001); } else { // 已授权,启动服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(service); } else { context.startService(service); } } - 若要在ROM中跳过用户授权,可在系统权限配置中预设应用的
android.permission.BIND_VPN_SERVICE权限。
4. 验证系统应用安装与签名
- 确认
android:sharedUserId="android.uid.system"正确放在<application>标签内。 - 签名后的APK必须安装到系统分区(
/system/app或/system/priv-app),执行以下命令:adb root adb remount adb push filename.apk /system/priv-app/MyVpnApp/ adb chmod 644 /system/priv-app/MyVpnApp/filename.apk adb reboot
内容的提问来源于stack exchange,提问作者Biscuit
相关产品推荐
相关产品推荐

