Android 11上WorkManager触发SecurityException:缺失WAKE_LOCK权限
WorkManager升级后Android 11设备出现WAKE_LOCK权限缺失问题
我们在Activity中通过CoroutineWorker使用WorkManager执行快速同步任务,代码如下:
WorkManager.getInstance(this@MainActivity) .enqueue(MySyncWorker.getWorkRequest())
CoroutineWorker中的任务请求代码:
class MySyncWorker( private val context: Context, parameters: WorkerParameters, private val mySynchronizer: MySynchronizer, ) : CoroutineWorker(context, parameters) { override suspend fun doWork(): Result { try { // setforeground is not needed for expedited work. // Older SDKs cannot run jobs as expedited and needs the foreground call. setForeground(createForegroundInfo()) mySynchronizer.sync() } catch (e: Exception) { //log failure return Result.failure() } return Result.success() } //Required for expedited work override suspend fun getForegroundInfo(): ForegroundInfo { return createForegroundInfo() } private fun createForegroundInfo(): ForegroundInfo { // skipping details on notification stuff return ForegroundInfo(NOTIFICATION_ID, notification) } companion object { fun getWorkRequest() : OneTimeWorkRequest { return OneTimeWorkRequestBuilder<MySyncWorker>() .setExpedited(OutOfQuotaPolicy.DROP_WORK_REQUEST) .build() } } }
此前在compile/target版本31、WorkManager版本2.7.1时运行正常。升级至compileVersion=34、targetVersion=33,使用implementation "androidx.work:work-runtime-ktx:2.8.1"后,在Android11设备触发同步时出现以下错误:
WM-WorkerWrapper Work failed because it threw an exception/error java.util.concurrent.ExecutionException: java.util.concurrent.ExecutionException: java.lang.SecurityException: Neither user 10363 nor current process has android.permission.WAKE_LOCK. at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:516) at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475) at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:317) at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923) Caused by: java.util.concurrent.ExecutionException: java.lang.SecurityException: Neither user 10363 nor current process has android.permission.WAKE_LOCK. at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:516) at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475) at androidx.work.impl.WorkerWrapper$1.run(WorkerWrapper.java:298) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:246) at android.app.ActivityThread.main(ActivityThread.java:8653) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130) Caused by: java.lang.SecurityException: Neither user 10363 nor current process has android.permission.WAKE_LOCK. at android.os.Parcel.createExceptionOrNull(Parcel.java:2386) at android.os.Parcel.createException(Parcel.java:2370) at android.os.Parcel.readException(Parcel.java:2353) at android.os.Parcel.readException(Parcel.java:2295) at android.os.IPowerManager$Stub$Proxy.acquireWakeLock(IPowerManager.java:1354) at android.os.PowerManager$WakeLock.acquireLocked(PowerManager.java:3449) at android.os.PowerManager$WakeLock.acquire(PowerManager.java:3415) at androidx.work.impl.Processor.startForeground(Processor.java:199) at androidx.work.impl.utils.WorkForegroundUpdater$1.run(WorkForegroundUpdater.java:100) at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923) Caused by: android.os.RemoteException: Remote stack trace: at android.app.ContextImpl.enforce(ContextImpl.java:2115) at android.app.ContextImpl.enforceCallingOrSelfPermission(ContextImpl.java:2143) at com.android.server.power.PowerManagerService$BinderService.acquireWakeLock(PowerManagerService.java:8357) at android.os.IPowerManager$Stub.onTransact(IPowerManager.java:630) at android.os.Binder.execTransactInternal(Binder.java:119
我们的Manifest中已声明:
<uses-permission android:name="android.permission.WAKE_LOCK" />
但合并后的Manifest显示:
<uses-permission android:maxSdkVersion = 25 android:name="android.permission.WAKE_LOCK" />
我们的minSdk为26,为何Android11会出现权限缺失错误?如何修复同步功能?Android13设备无此问题。
问题原因
- 权限被库声明覆盖:WorkManager 2.8.x版本的库自身在Manifest中添加了带有
android:maxSdkVersion="25"的WAKE_LOCK权限声明,与我们自己声明的权限合并后,最终权限仅对API≤25的设备生效。而WorkManager在处理Android 11(API 30)的加急任务时,仍然尝试获取唤醒锁,导致权限缺失抛出SecurityException。 - 系统版本差异:Android 13(API 33)对唤醒锁权限的要求有所调整,或者WorkManager在该系统版本下已不再需要显式申请
WAKE_LOCK权限,因此未出现问题。
修复方案
方案1:强制覆盖权限声明(推荐)
在Manifest中使用tools:replace属性覆盖WorkManager库中的权限限制,确保WAKE_LOCK权限对所有API级别生效:
<!-- 确保Manifest根元素已添加tools命名空间 --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.WAKE_LOCK" tools:replace="android:maxSdkVersion" /> </manifest>
方案2:动态调整前台任务逻辑
根据系统API级别决定是否调用setForeground(),减少不必要的权限依赖:
override suspend fun doWork(): Result { try { // 仅在Android 11及以下设备调用setForeground if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { setForeground(createForegroundInfo()) } mySynchronizer.sync() } catch (e: Exception) { // 记录失败日志 return Result.failure() } return Result.success() }
注:此方案需配合方案1使用,因为WorkManager内部可能仍会尝试获取唤醒锁。
方案3:临时降级WorkManager版本
若暂时无法调整权限或代码,可降级回WorkManager 2.7.1版本,恢复原有行为,但不推荐长期使用,新版本包含重要修复和特性。
内容的提问来源于stack exchange,提问作者Leknesh
相关产品推荐
相关产品推荐

