Merge "Add optimizations to keep TaskPersister queue small." into lmp-dev
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index b21af48..df1772a 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -51,6 +51,12 @@
      * task being launched a chance to load its resources without this occupying IO bandwidth. */
     private static final long PRE_TASK_DELAY_MS = 3000;
 
+    /** The maximum number of entries to keep in the queue before draining it automatically. */
+    private static final int MAX_WRITE_QUEUE_LENGTH = 6;
+
+    /** Special value for mWriteTime to mean don't wait, just write */
+    private static final long FLUSH_QUEUE = -1;
+
     private static final String RECENTS_FILENAME = "_task";
     private static final String TASKS_DIRNAME = "recent_tasks";
     private static final String TASK_EXTENSION = ".xml";
@@ -120,6 +126,31 @@
         mLazyTaskWriterThread.start();
     }
 
+    private void removeThumbnails(TaskRecord task) {
+        final String taskString = Integer.toString(task.taskId);
+        for (int queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
+            final WriteQueueItem item = mWriteQueue.get(queueNdx);
+            if (item instanceof ImageWriteQueueItem &&
+                    ((ImageWriteQueueItem) item).mFilename.startsWith(taskString)) {
+                if (DEBUG) Slog.d(TAG, "Removing " + ((ImageWriteQueueItem) item).mFilename +
+                        " from write queue");
+                mWriteQueue.remove(queueNdx);
+            }
+        }
+    }
+
+    private void yieldIfQueueTooDeep() {
+        boolean stall = false;
+        synchronized (this) {
+            if (mNextWriteTime == FLUSH_QUEUE) {
+                stall = true;
+            }
+        }
+        if (stall) {
+            Thread.yield();
+        }
+    }
+
     void wakeup(TaskRecord task, boolean flush) {
         synchronized (this) {
             if (task != null) {
@@ -128,6 +159,10 @@
                     final WriteQueueItem item = mWriteQueue.get(queueNdx);
                     if (item instanceof TaskWriteQueueItem &&
                             ((TaskWriteQueueItem) item).mTask == task) {
+                        if (!task.inRecents) {
+                            // This task is being removed.
+                            removeThumbnails(task);
+                        }
                         break;
                     }
                 }
@@ -138,15 +173,18 @@
                 // Dummy.
                 mWriteQueue.add(new WriteQueueItem());
             }
-            if (flush) {
-                mNextWriteTime = -1;
+            if (flush || mWriteQueue.size() > MAX_WRITE_QUEUE_LENGTH) {
+                mNextWriteTime = FLUSH_QUEUE;
             } else if (mNextWriteTime == 0) {
                 mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
             }
             if (DEBUG) Slog.d(TAG, "wakeup: task=" + task + " flush=" + flush + " mNextWriteTime="
-                    + mNextWriteTime + " Callers=" + Debug.getCallers(4));
+                    + mNextWriteTime + " mWriteQueue.size=" + mWriteQueue.size()
+                    + " Callers=" + Debug.getCallers(4));
             notifyAll();
         }
+
+        yieldIfQueueTooDeep();
     }
 
     void saveImage(Bitmap image, String filename) {
@@ -166,7 +204,9 @@
             if (queueNdx < 0) {
                 mWriteQueue.add(new ImageWriteQueueItem(filename, image));
             }
-            if (mNextWriteTime == 0) {
+            if (mWriteQueue.size() > MAX_WRITE_QUEUE_LENGTH) {
+                mNextWriteTime = FLUSH_QUEUE;
+            } else if (mNextWriteTime == 0) {
                 mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
             }
             if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename + " now=" +
@@ -174,6 +214,8 @@
                     mNextWriteTime + " Callers=" + Debug.getCallers(4));
             notifyAll();
         }
+
+        yieldIfQueueTooDeep();
     }
 
     Bitmap getThumbnail(String filename) {
@@ -425,7 +467,7 @@
                 // If mNextWriteTime, then don't delay between each call to saveToXml().
                 final WriteQueueItem item;
                 synchronized (TaskPersister.this) {
-                    if (mNextWriteTime >= 0) {
+                    if (mNextWriteTime != FLUSH_QUEUE) {
                         // The next write we don't have to wait so long.
                         mNextWriteTime = SystemClock.uptimeMillis() + INTER_WRITE_DELAY_MS;
                         if (DEBUG) Slog.d(TAG, "Next write time may be in " +
@@ -439,13 +481,14 @@
                             TaskPersister.this.wait();
                         } catch (InterruptedException e) {
                         }
-                        // Invariant: mNextWriteTime is either -1 or PRE_WRITE_DELAY_MS from now.
+                        // Invariant: mNextWriteTime is either FLUSH_QUEUE or PRE_WRITE_DELAY_MS
+                        // from now.
                     }
                     item = mWriteQueue.remove(0);
 
                     long now = SystemClock.uptimeMillis();
                     if (DEBUG) Slog.d(TAG, "LazyTaskWriter: now=" + now + " mNextWriteTime=" +
-                            mNextWriteTime);
+                            mNextWriteTime + " mWriteQueue.size=" + mWriteQueue.size());
                     while (now < mNextWriteTime) {
                         try {
                             if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting " +
@@ -484,7 +527,7 @@
                     TaskRecord task = ((TaskWriteQueueItem) item).mTask;
                     if (DEBUG) Slog.d(TAG, "Writing task=" + task);
                     synchronized (mService) {
-                        if (mService.mRecentTasks.contains(task)) {
+                        if (task.inRecents) {
                             // Still there.
                             try {
                                 if (DEBUG) Slog.d(TAG, "Saving task=" + task);