SharedPreferences$Editor.startCommit()

Adds a fire-and-forget save method (startCommit) to the
SharedPreferences.Editor, which is the way most people use it anyway.

This commit adds the implementation.  The previous commit added the
interface and docs:

   previous change: Idf9934b445da1fb72b79f0192218b47c0a7f5a34
        git commit: edf32d01316bd3432c023f17747461b08ae36375

In addition, this change:

-- adds a generic "runPendingWorkFinishers" mechanism to
   ActivityThread to wait on async operations that are still
   in flight and use it for this.

-- ties runPendingWorkFinishers into Activity.onPause,
   BroadcastReceiver, and Service.

-- makes sSharedPreferences keyed on name, not File, to avoid
   unnnecessary allocations

-- documents and guarantees what thread
   OnSharedPreferenceChangeListener callbacks run on

-- makes a few things in frameworks/base use startCommit(), notably
   Preference.java (which was ignoring the return value anyway)

Change-Id: I1c8db60ad45643226fe6d246d3e513eeb7bd0ebd
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c07e3d3..084f637 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -152,7 +152,7 @@
             = new ArrayList<Application>();
     // set of instantiated backup agents, keyed by package name
     final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>();
-    static final ThreadLocal sThreadLocal = new ThreadLocal();
+    static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal();
     Instrumentation mInstrumentation;
     String mInstrumentationAppDir = null;
     String mInstrumentationAppPackage = null;
@@ -186,6 +186,8 @@
     final GcIdler mGcIdler = new GcIdler();
     boolean mGcIdlerScheduled = false;
 
+    static Handler sMainThreadHandler;  // set once in main()
+
     private static final class ActivityClientRecord {
         IBinder token;
         int ident;
@@ -1111,7 +1113,7 @@
     }
 
     public static final ActivityThread currentActivityThread() {
-        return (ActivityThread)sThreadLocal.get();
+        return sThreadLocal.get();
     }
 
     public static final String currentPackageName() {
@@ -1780,6 +1782,8 @@
             }
         }
 
+        QueuedWork.waitToFinish();
+
         try {
             if (data.sync) {
                 if (DEBUG_BROADCAST) Slog.i(TAG,
@@ -2007,6 +2011,9 @@
                     data.args.setExtrasClassLoader(s.getClassLoader());
                 }
                 int res = s.onStartCommand(data.args, data.flags, data.startId);
+
+                QueuedWork.waitToFinish();
+
                 try {
                     ActivityManagerNative.getDefault().serviceDoneExecuting(
                             data.token, 1, data.startId, res);
@@ -2035,6 +2042,9 @@
                     final String who = s.getClassName();
                     ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
                 }
+
+                QueuedWork.waitToFinish();
+
                 try {
                     ActivityManagerNative.getDefault().serviceDoneExecuting(
                             token, 0, 0, 0);
@@ -3598,6 +3608,9 @@
         Process.setArgV0("<pre-initialized>");
 
         Looper.prepareMainLooper();
+        if (sMainThreadHandler == null) {
+            sMainThreadHandler = new Handler();
+        }
 
         ActivityThread thread = new ActivityThread();
         thread.attach(false);