diff options
| author | 2014-09-16 23:57:21 -0700 | |
|---|---|---|
| committer | 2014-09-16 23:57:21 -0700 | |
| commit | 63f10904a17db79cc8da08ff904d45d6d1cf0862 (patch) | |
| tree | 8a3929669ae456dfa7f20bbe0f61b8baa6a9cf8d | |
| parent | c1e1550bf489b5fafff70154232c24bc5026b7df (diff) | |
Add optimizations to keep TaskPersister queue small.
CTS tests cause the TaskPersister queue to fill faster than it can
drain. Since it contains screenshots this can consume massive
memory. Monkey may also cause the queue to back up.
Several optimizations are added to drain the queue when it gets
large:
- High water mark to recognize when queue gets too deep. Queue is
completely drained at this point so that obsolete files can be
removed from storage.
- Use Thread.yield() to give the TaskPersister write thread some cpu
cycles.
- Remove images from write queue when TaskRecord is removed from
recents.
May fix bug 17177273.
May fix bug 17381033.
Change-Id: If21c03c8f380e5f6816cf4701a40fcfe34ace3f1
| -rw-r--r-- | services/core/java/com/android/server/am/TaskPersister.java | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index b21af48c4d3b..df1772a56550 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 @@ public class TaskPersister { * 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 @@ public class TaskPersister { 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 @@ public class TaskPersister { 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 @@ public class TaskPersister { // 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 @@ public class TaskPersister { 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 @@ public class TaskPersister { mNextWriteTime + " Callers=" + Debug.getCallers(4)); notifyAll(); } + + yieldIfQueueTooDeep(); } Bitmap getThumbnail(String filename) { @@ -425,7 +467,7 @@ public class TaskPersister { // 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 @@ public class TaskPersister { 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 @@ public class TaskPersister { 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); |