summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Craig Mautner <cmautner@google.com> 2014-09-16 23:57:21 -0700
committer Craig Mautner <cmautner@google.com> 2014-09-16 23:57:21 -0700
commit63f10904a17db79cc8da08ff904d45d6d1cf0862 (patch)
tree8a3929669ae456dfa7f20bbe0f61b8baa6a9cf8d
parentc1e1550bf489b5fafff70154232c24bc5026b7df (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.java59
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);