您的位置:首页 > 移动开发 > Android开发

Android O(8.0)后台service限制

2017-11-02 10:46 836 查看
        Android的每次平台更新,都一直在努力收紧应用权限。8.0也不例外,这次是限制应用后台启动service的权限。相关的问题现象,可参考http://blog.csdn.net/chenshengfa/article/details/71407704。

        不过本文除了吐槽下新的后台限制对8.0平台适配带来的影响外,主要是说说本人在开发中发现的一些可规避的方法。先声明一下,由于应用权限问题,本文并不适合普通应用开发,仅做研究参考。

        虽然Android官方在限制了后台service启动的同时,也给出了替代方案。但毕竟有些功能,是其他方案无法替代或即便替代了也无法达到以往的效果的。比如监听网络变化、监听亮灭屏等这些需求。真是一去不复返的坑,对于一些习惯了耍流氓的我们,真真是不方便了啊。以下,是方案正文。

1.      对于所有应用可以使用的解决方法。

1). 平台区分,8.0以下,爱咋咋地,以前怎样还怎样。

2). 8.0以上,统一一个常驻service,转为前台。方法为:将startService改成startForegroundService,并在对应的service创建的时候,使用startForeground注册自己的notification。

3). 对,这个方法是带notification的,也就是说,如果想用常驻service,就得让用户知道。

2.      对于系统应用,可以使用的方法(需要有system权限)。

可能有人说,我都系统应用了,哪儿要这么麻烦,我已经是特殊员工啦,Android禁止我干嘛。对哦,你要是有7大姑8大姨的也想享受权限怎么搞?我所负责的应用,就有这么一款,处在灰色地带的,一部分有system权限,另一部分小弟却在局子外边混。

首先,我们看一下源码中的启动部分

ActiveServices.java -> startServiceLocked(),里边有这么一段

if(!r.startRequested && !fgRequired) {
// Before going further -- if this app isnot allowed to start services in the
// background, then at this point we aren'tgoing to let it period.
final int allowed =mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion,callingPid, false, false);
if (allowed !=ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start notallowed: service "
+ service + " to " +r.name.flattenToShortString()
+ " from pid=" +callingPid + " uid=" + callingUid
+ " pkg=" +callingPackage);
if (allowed ==ActivityManager.APP_START_MODE_DELAYED) {
// In this case we are silentlydisabling the app, to disrupt as
// little as possible existing apps.
return null;
}
// This app knows it is in the newmodel where this operation is not
// allowed, so tell it what hashappened.
UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
return new ComponentName("?","app is in background uid " + uidRec);
}
}


不难发现,如果service不是fgRequired前台唤醒,那就得走这段了,获取service所持有的应用MODE是否为APP_START_MODE_NORMAL。也就是说,一旦应用为APP_START_MODE_NORMAL,就可以开开心心的启动后台service了。进入ActivityManagerService.java ->getAppStartModeLocked()查看定义,核心基本上就是这个了

final intstartMode = (alwaysRestrict)
? appRestrictedInBackgroundLocked(uid,packageName, packageTargetSdk)
:appServicesRestrictedInBackgroundLocked(uid, packageName,
packageTargetSdk);


直接看appServicesRestrictedInBackgroundLocked()

intappServicesRestrictedInBackgroundLocked(int uid, String packageName, intpackageTargetSdk) {
// Persistent app?
if (mPackageManagerInt.isPackagePersistent(packageName)){
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid+ "/" + packageName
+ " is persistent; notrestricted in background");
}
return ActivityManager.APP_START_MODE_NORMAL;
}

// Non-persistent but backgroundwhitelisted?
if (uidOnBackgroundWhitelist(uid)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid+ "/" + packageName
+ " on backgroundwhitelist; not restricted in background");
}
returnActivityManager.APP_START_MODE_NORMAL;
}

// Is this app on the battery whitelist?
if (isOnDeviceIdleWhitelistLocked(uid)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid+ "/" + packageName
+ " on idle whitelist;not restricted in background");
}
returnActivityManager.APP_START_MODE_NORMAL;
}

// None of the service-policy criteriaapply, so we apply the common criteria
return appRestrictedInBackgroundLocked(uid,packageName, packageTargetSdk);
}


然后就是各种判断了,作为有system权限的应用,就可以给其他应用开后门啦。

 

其中的isOnDeviceIdleWhitelistLocked,用户可用通过进入设置->应用详情->管理电池应用,此处可以通过开关进行改变这个值,或者设置->电池->右上方的菜单,电池优化中,修改应用列表即可。

 

如上,收尾。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: