OSDN Git Service

Don't leak wakelock instances
authorChristopher Tate <ctate@google.com>
Mon, 26 Sep 2016 19:59:10 +0000 (12:59 -0700)
committerChristopher Tate <ctate@google.com>
Tue, 27 Sep 2016 22:00:48 +0000 (15:00 -0700)
Bug 31247436

Change-Id: I7c2ad956c43233b37e53856e9321cb87b01c35da

core/java/android/os/PowerManager.java
services/core/java/com/android/server/job/JobServiceContext.java

index 1aed9b3..8d4d0a5 100644 (file)
@@ -1340,6 +1340,11 @@ public final class PowerManager {
         }
 
         /** @hide */
+        public String getTag() {
+            return mTag;
+        }
+
+        /** @hide */
         public void setHistoryTag(String tag) {
             mHistoryTag = tag;
         }
index 31528e5..5989c38 100644 (file)
@@ -306,10 +306,24 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
         this.service = IJobService.Stub.asInterface(service);
         final PowerManager pm =
                 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag());
-        mWakeLock.setWorkSource(new WorkSource(runningJob.getSourceUid()));
-        mWakeLock.setReferenceCounted(false);
-        mWakeLock.acquire();
+        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                runningJob.getTag());
+        wl.setWorkSource(new WorkSource(runningJob.getSourceUid()));
+        wl.setReferenceCounted(false);
+        wl.acquire();
+        synchronized (mLock) {
+            // We use a new wakelock instance per job.  In rare cases there is a race between
+            // teardown following job completion/cancellation and new job service spin-up
+            // such that if we simply assign mWakeLock to be the new instance, we orphan
+            // the currently-live lock instead of cleanly replacing it.  Watch for this and
+            // explicitly fast-forward the release if we're in that situation.
+            if (mWakeLock != null) {
+                Slog.w(TAG, "Bound new job " + runningJob + " but live wakelock " + mWakeLock
+                        + " tag=" + mWakeLock.getTag());
+                mWakeLock.release();
+            }
+            mWakeLock = wl;
+        }
         mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
     }