Fix deadlock by making DropBoxManager call async.

Created a Handler and used it to make sendBroadcast call asynchronously.
Deadlock was caused by WindowManagerService Log.wtf call requiring
ActivityManagerService lock while holding its own lock. At the same time
ActivityManagerService was holding its lock while waiting for
WindowManagerService lock.

Tested by forcing a Log.wtf in
WindowManagerServices.updateWindowsAppsAndRotationAnimationsLocked
inside mAppTokens loop. Then ran 'adb shell monkey -v -v 500000'.
Without this fix it would lock up and reboot within a couple of minutes.
With this fix it runs until the Camera app crashes. But that's a
different bug...

Fixes bug 6112676.

Change-Id: I5b360aa08412d117b1765f01bacd931020509db7
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java
index d37c9ab..932cba1 100644
--- a/services/java/com/android/server/DropBoxManagerService.java
+++ b/services/java/com/android/server/DropBoxManagerService.java
@@ -28,6 +28,7 @@
 import android.os.DropBoxManager;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.Message;
 import android.os.StatFs;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -64,6 +65,9 @@
     private static final int DEFAULT_RESERVE_PERCENT = 10;
     private static final int QUOTA_RESCAN_MILLIS = 5000;
 
+    // mHandler 'what' value.
+    private static final int MSG_SEND_BROADCAST = 1;
+
     private static final boolean PROFILE_DUMP = false;
 
     // TODO: This implementation currently uses one file per entry, which is
@@ -88,11 +92,11 @@
     private int mCachedQuotaBlocks = 0;  // Space we can use: computed from free space, etc.
     private long mCachedQuotaUptimeMillis = 0;
 
-    // Ensure that all log entries have a unique timestamp
-    private long mLastTimestamp = 0;
-
     private volatile boolean mBooted = false;
 
+    // Provide a way to perform sendBroadcast asynchronously to avoid deadlocks.
+    private final Handler mHandler;
+
     /** Receives events that might indicate a need to clean up files. */
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
@@ -143,11 +147,21 @@
         mContentResolver.registerContentObserver(
             Settings.Secure.CONTENT_URI, true,
             new ContentObserver(new Handler()) {
+                @Override
                 public void onChange(boolean selfChange) {
                     mReceiver.onReceive(context, (Intent) null);
                 }
             });
 
+        mHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == MSG_SEND_BROADCAST) {
+                    mContext.sendBroadcast((Intent)msg.obj, android.Manifest.permission.READ_LOGS);
+                }
+            }
+        };
+
         // The real work gets done lazily in init() -- that way service creation always
         // succeeds, and things like disk problems cause individual method failures.
     }
@@ -157,6 +171,7 @@
         mContext.unregisterReceiver(mReceiver);
     }
 
+    @Override
     public void add(DropBoxManager.Entry entry) {
         File temp = null;
         OutputStream output = null;
@@ -227,14 +242,17 @@
             long time = createEntry(temp, tag, flags);
             temp = null;
 
-            Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
+            final Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
             dropboxIntent.putExtra(DropBoxManager.EXTRA_TAG, tag);
             dropboxIntent.putExtra(DropBoxManager.EXTRA_TIME, time);
             if (!mBooted) {
                 dropboxIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
             }
-            mContext.sendBroadcast(dropboxIntent, android.Manifest.permission.READ_LOGS);
-
+            // Call sendBroadcast after returning from this call to avoid deadlock. In particular
+            // the caller may be holding the WindowManagerService lock but sendBroadcast requires a
+            // lock in ActivityManagerService. ActivityManagerService has been caught holding that
+            // very lock while waiting for the WindowManagerService lock.
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_SEND_BROADCAST, dropboxIntent));
         } catch (IOException e) {
             Slog.e(TAG, "Can't write: " + tag, e);
         } finally {