Fix unbounded async task creation in ADS

Queue operations through a single ConcurrentLinkedQueue and
service the updates on a single async task to avoid spamming the
async thread task queue.

b/11336926

Change-Id: I8e5c526d61f70fbad0ccef80afd08fc26bb5acf0
This commit is contained in:
Tony Mantler 2014-02-18 13:51:43 -08:00
parent c165d9bd77
commit 426de73380
1 changed files with 42 additions and 15 deletions

View File

@ -27,6 +27,7 @@ import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SystemClock; import android.os.SystemClock;
@ -35,7 +36,6 @@ import android.text.format.DateUtils;
import com.android.email.AttachmentInfo; import com.android.email.AttachmentInfo;
import com.android.email.EmailConnectivityManager; import com.android.email.EmailConnectivityManager;
import com.android.email.NotificationController; import com.android.email.NotificationController;
import com.android.email2.ui.MailActivityEmail;
import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Attachment; import com.android.emailcommon.provider.EmailContent.Attachment;
@ -55,8 +55,10 @@ import java.io.PrintWriter;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Queue;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class AttachmentDownloadService extends Service implements Runnable { public class AttachmentDownloadService extends Service implements Runnable {
public static final String TAG = LogUtils.TAG; public static final String TAG = LogUtils.TAG;
@ -846,6 +848,12 @@ public class AttachmentDownloadService extends Service implements Runnable {
} }
} }
// The queue entries here are entries of the form {id, flags}, with the values passed in to
// attachmentChanged()
private static final Queue<long[]> sAttachmentChangedQueue =
new ConcurrentLinkedQueue<long[]>();
private static AsyncTask<Void, Void, Void> sAttachmentChangedTask;
/** /**
* Called directly by EmailProvider whenever an attachment is inserted or changed * Called directly by EmailProvider whenever an attachment is inserted or changed
* @param context the caller's context * @param context the caller's context
@ -853,20 +861,39 @@ public class AttachmentDownloadService extends Service implements Runnable {
* @param flags the new flags for the attachment * @param flags the new flags for the attachment
*/ */
public static void attachmentChanged(final Context context, final long id, final int flags) { public static void attachmentChanged(final Context context, final long id, final int flags) {
Utility.runAsync(new Runnable() { synchronized (sAttachmentChangedQueue) {
@Override sAttachmentChangedQueue.add(new long[]{id, flags});
public void run() {
Attachment attachment = Attachment.restoreAttachmentWithId(context, id); if (sAttachmentChangedTask == null) {
if (attachment != null) { sAttachmentChangedTask = new AsyncTask<Void, Void, Void>() {
// Store the flags we got from EmailProvider; given that all of this @Override
// activity is asynchronous, we need to use the newest data from protected Void doInBackground(Void... params) {
// EmailProvider while (true) {
attachment.mFlags = flags; final long[] change;
Intent intent = new Intent(context, AttachmentDownloadService.class); synchronized (sAttachmentChangedQueue) {
intent.putExtra(EXTRA_ATTACHMENT, attachment); change = sAttachmentChangedQueue.poll();
context.startService(intent); if (change == null) {
} sAttachmentChangedTask = null;
}}); return null;
}
}
final long id = change[0];
final long flags = change[1];
final Attachment attachment =
Attachment.restoreAttachmentWithId(context, id);
if (attachment == null) {
continue;
}
attachment.mFlags = (int) flags;
final Intent intent =
new Intent(context, AttachmentDownloadService.class);
intent.putExtra(EXTRA_ATTACHMENT, attachment);
context.startService(intent);
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
} }
/** /**