OSDN Git Service

AppOps: Fix yet another deadlock
authorGabriele M <moto.falcon.git@gmail.com>
Thu, 27 Jul 2017 18:18:53 +0000 (20:18 +0200)
committerGabriele M <moto.falcon.git@gmail.com>
Fri, 4 Aug 2017 21:09:35 +0000 (21:09 +0000)
A = AppOpsService.this
B = PowerManagerService.mLock

Thread 1:
  AppOpsService.noteOperation() (lock A) ->
  PowerManagerService.isInteractive() (lock B)

Thread 2:
  PowerManagerService.acquireWakeLockInternal() (lock B) ->
  AppOpsService.startOperation() (lock A)

Move PowerManagerService.isInteractive() so that 'Thread 1' becomes:
  PowerManagerService.isInteractive() (lock and release B) ->
  AppOpsService.noteOperation() (lock A)

Change-Id: I6b2050bf6deaf6db94b9243c1a81c37e25ad55a2

services/core/java/com/android/server/AppOpsService.java

index 015582c..293bd23 100644 (file)
@@ -1120,6 +1120,7 @@ public class AppOpsService extends IAppOpsService.Stub {
     private int noteOperationUnchecked(int code, int uid, String packageName,
             int proxyUid, String proxyPackageName) {
         PermissionDialogReq req = null;
+        final boolean isInteractive = mPowerManager != null ? mPowerManager.isInteractive() : false;
         synchronized (this) {
             Ops ops = getOpsRawLocked(uid, packageName, true);
             if (ops == null) {
@@ -1195,7 +1196,6 @@ public class AppOpsService extends IAppOpsService.Stub {
                     // we move them to the back of the line. NOTE: these values are magic, and may need
                     // tuning. Ideally we'd want a ringbuffer or token bucket here to do proper rate
                     // limiting.
-                    final boolean isInteractive = mPowerManager.isInteractive();
                     if (isInteractive &&
                             (ops.uidState.pkgOps.size() < AppOpsPolicy.RATE_LIMIT_OPS_TOTAL_PKG_COUNT
                             && op.noteOpCount < AppOpsPolicy.RATE_LIMIT_OP_COUNT