Search code examples
androidandroid-workmanagerandroid-securityexceptioncoroutineworker

WorkManager on Android 11 causes SecurityException: Missing WAKE_LOCK permission


In our activity we use WorkManager to run a quick syncronization job through a coroutineworker:

WorkManager.getInstance(this@MainActivity)
           .enqueue(MySyncWorker.getWorkRequest())

The workrequest in 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()
        }
    }
}

This was working ok on compile/target v 31 and with work version 2.7.1.

We did some upgrades to after upgrade to compileVersion = 34 targetVersion = 33

implementation "androidx.work:work-runtime-ktx:2.8.1"`

After this, building on an Android11 gives the following when the sync is called:

 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

The manifest contains the line:

<uses-permission android:name="android.permission.WAKE_LOCK" />

However, the merged manifest file shows

<uses-permission
    android:maxSdkVersion = 25
    android:name="android.permission.WAKE_LOCK" />

Our minSdk is 26. Why are we seeing this missing permission error, and how can we get our sync to work? On an Android13 test device, this error is not seen.


Solution

  • As stated in question, the merged manifest had a maxSdkVersion set on the WAKE_LOCK permission. Turns out this had nothing to do with implementation of worker, a permission override was introduced from Chucker library:

    debugImplementation 'com.github.chuckerteam.chucker:library:4.0.0'
    releaseImplementation 'com.github.chuckerteam.chucker:library-no-op:4.0.0'
    

    Apparently, a maxSdkVersion for this permission set in Chucker manifest overrides the permission setting from app manifest. Solution is to add to app manifest:

       <uses-permission
            android:name="android.permission.WAKE_LOCK"
            tools:node="replace"/>
    

    See also this issue reported to Chucker repo.