You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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设备无此问题。


问题原因

  1. 权限被库声明覆盖:WorkManager 2.8.x版本的库自身在Manifest中添加了带有android:maxSdkVersion="25"的WAKE_LOCK权限声明,与我们自己声明的权限合并后,最终权限仅对API≤25的设备生效。而WorkManager在处理Android 11(API 30)的加急任务时,仍然尝试获取唤醒锁,导致权限缺失抛出SecurityException。
  2. 系统版本差异: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 03:17:13