Add 5s timeout to wakelock

Also filed a b/15110168 to anr the app if it doesn't finish with the
button event in 5s.

Change-Id: I23906b4c7f17d3d3a29eef92b523d8653c87017e
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index d9e45f5ba..9a1c6d5 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -61,6 +61,8 @@
     private static final String TAG = "MediaSessionService";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
+    private static final int WAKELOCK_TIMEOUT = 5000;
+
     private final SessionManagerImpl mSessionManagerImpl;
     // private final MediaRouteProviderWatcher mRouteProviderWatcher;
     private final MediaSessionStack mPriorityStack;
@@ -676,9 +678,6 @@
             final long token = Binder.clearCallingIdentity();
 
             try {
-                if (needWakeLock) {
-                    mMediaEventWakeLock.acquire();
-                }
                 synchronized (mLock) {
                     MediaSessionRecord mbSession = mPriorityStack
                             .getDefaultMediaButtonSession(mCurrentUserId);
@@ -686,9 +685,18 @@
                         if (DEBUG) {
                             Log.d(TAG, "Sending media key to " + mbSession.getSessionInfo());
                         }
+                        if (needWakeLock) {
+                            mKeyEventReceiver.aquireWakeLockLocked();
+                        }
+                        // If we don't need a wakelock use -1 as the id so we
+                        // won't release it later
                         mbSession.sendMediaButton(keyEvent,
-                                needWakeLock ? mKeyEventDoneReceiver : null);
+                                needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+                                mKeyEventReceiver);
                     } else {
+                        if (needWakeLock) {
+                            mMediaEventWakeLock.acquire();
+                        }
                         if (DEBUG) {
                             Log.d(TAG, "Sending media key ordered broadcast");
                         }
@@ -743,15 +751,67 @@
             }
         }
 
-        ResultReceiver mKeyEventDoneReceiver = new ResultReceiver(mHandler) {
+        private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
+
+        class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable {
+            private final Handler mHandler;
+            private int mRefCount = 0;
+            private int mLastTimeoutId = 0;
+
+            public KeyEventWakeLockReceiver(Handler handler) {
+                super(handler);
+                mHandler = handler;
+            }
+
+            public void onTimeout() {
+                synchronized (mLock) {
+                    if (mRefCount == 0) {
+                        // We've already released it, so just return
+                        return;
+                    }
+                    mLastTimeoutId++;
+                    mRefCount = 0;
+                    releaseWakeLockLocked();
+                }
+            }
+
+            public void aquireWakeLockLocked() {
+                if (mRefCount == 0) {
+                    mMediaEventWakeLock.acquire();
+                }
+                mRefCount++;
+                mHandler.removeCallbacks(this);
+                mHandler.postDelayed(this, WAKELOCK_TIMEOUT);
+
+            }
+
+            @Override
+            public void run() {
+                onTimeout();
+            }
+
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
-                synchronized (mLock) {
-                    if (mMediaEventWakeLock.isHeld()) {
-                        mMediaEventWakeLock.release();
+                if (resultCode < mLastTimeoutId) {
+                    // Ignore results from calls that were before the last
+                    // timeout, just in case.
+                    return;
+                } else {
+                    synchronized (mLock) {
+                        if (mRefCount > 0) {
+                            mRefCount--;
+                            if (mRefCount == 0) {
+                                releaseWakeLockLocked();
+                            }
+                        }
                     }
                 }
             }
+
+            private void releaseWakeLockLocked() {
+                mMediaEventWakeLock.release();
+                mHandler.removeCallbacks(this);
+            }
         };
 
         BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {