Switch to a background thread pool

 Bug: 5019676
 Use a shared thread pool
 Eliminate some unnecessary use of AsyncTask (which has extra
 overhead compared to using a thread pool)

Change-Id: I01d6c84816a9c9705216c8fdb8ed8c990265626a
diff --git a/src/com/android/browser/BackgroundHandler.java b/src/com/android/browser/BackgroundHandler.java
new file mode 100644
index 0000000..a0d9243
--- /dev/null
+++ b/src/com/android/browser/BackgroundHandler.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.browser;
+
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class BackgroundHandler {
+
+    static HandlerThread sLooperThread;
+    static ExecutorService mThreadPool;
+
+    static {
+        sLooperThread = new HandlerThread("BackgroundHandler", HandlerThread.MIN_PRIORITY);
+        sLooperThread.start();
+        mThreadPool = Executors.newCachedThreadPool();
+    }
+
+    public static void execute(Runnable runnable) {
+        mThreadPool.execute(runnable);
+    }
+
+    public static Looper getLooper() {
+        return sLooperThread.getLooper();
+    }
+
+    private BackgroundHandler() {}
+}
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 2023ee6..8461d30 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -22,7 +22,6 @@
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.os.Build;
-import android.os.Looper;
 import android.os.Message;
 import android.preference.PreferenceManager;
 import android.provider.Browser;
@@ -104,10 +103,6 @@
     private AutofillHandler mAutofillHandler;
     private WeakHashMap<WebSettings, String> mCustomUserAgents;
     private static boolean sInitialized = false;
-    // Looper shared between some lightweight background operations
-    // Specifically, this is created on the thread that initializes browser settings
-    // and is then reused by CrashRecoveryHandler
-    private Looper mBackgroundLooper;
 
     // Cached values
     private int mPageCacheCapacity = 1;
@@ -134,7 +129,7 @@
         mCustomUserAgents = new WeakHashMap<WebSettings, String>();
         mPrefs.registerOnSharedPreferenceChangeListener(this);
         mAutofillHandler.asyncLoadFromDb();
-        new Thread(mSetupAndLoop, "BackgroundLooper").start();
+        BackgroundHandler.execute(mSetup);
     }
 
     public void setController(Controller controller) {
@@ -146,11 +141,6 @@
         }
     }
 
-    public Looper getBackgroundLooper() {
-        requireInitialization();
-        return mBackgroundLooper;
-    }
-
     public void startManagingSettings(WebSettings settings) {
         synchronized (mManagedSettings) {
             syncStaticSettings(settings);
@@ -159,7 +149,7 @@
         }
     }
 
-    private Runnable mSetupAndLoop = new Runnable() {
+    private Runnable mSetup = new Runnable() {
 
         @Override
         public void run() {
@@ -208,13 +198,10 @@
                     BrowserProvider.getClientId(mContext.getContentResolver()));
             }
 
-            Looper.prepare();
-            mBackgroundLooper = Looper.myLooper();
             synchronized (BrowserSettings.class) {
                 sInitialized = true;
                 BrowserSettings.class.notifyAll();
             }
-            Looper.loop();
         }
     };
 
@@ -525,6 +512,10 @@
         return (percent - 100) / TEXT_ZOOM_STEP + TEXT_ZOOM_START_VAL;
     }
 
+    public SharedPreferences getPreferences() {
+        return mPrefs;
+    }
+
     // -----------------------------
     // getter/setters for accessibility_preferences.xml
     // -----------------------------
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index cf5df9e..4c05688 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -424,36 +424,36 @@
         // WebIconDatabase needs to be retrieved on the UI thread so that if
         // it has not been created successfully yet the Handler is started on the
         // UI thread.
-        new RetainIconsOnStartupTask(WebIconDatabase.getInstance()).execute();
+        Runnable task = new RetainIconsOnStartupTask(
+                mActivity, WebIconDatabase.getInstance());
+        BackgroundHandler.execute(task);
     }
 
-    private class RetainIconsOnStartupTask extends AsyncTask<Void, Void, Void> {
+    private static class RetainIconsOnStartupTask implements Runnable {
         private WebIconDatabase mDb;
+        private Context mContext;
 
-        public RetainIconsOnStartupTask(WebIconDatabase db) {
+        public RetainIconsOnStartupTask(Context context, WebIconDatabase db) {
             mDb = db;
+            mContext = context;
         }
 
         @Override
-        protected Void doInBackground(Void... unused) {
-            mDb.open(mActivity.getDir("icons", 0).getPath());
+        public void run() {
+            mDb.open(mContext.getDir("icons", 0).getPath());
             Cursor c = null;
             try {
-                c = Browser.getAllBookmarks(mActivity.getContentResolver());
-                if (c.moveToFirst()) {
-                    int urlIndex = c.getColumnIndex(Browser.BookmarkColumns.URL);
-                    do {
-                        String url = c.getString(urlIndex);
-                        mDb.retainIconForPageUrl(url);
-                    } while (c.moveToNext());
+                c = Browser.getAllBookmarks(mContext.getContentResolver());
+                int urlIndex = c.getColumnIndex(Browser.BookmarkColumns.URL);
+                while (c.moveToNext()) {
+                    String url = c.getString(urlIndex);
+                    mDb.retainIconForPageUrl(url);
                 }
-            } catch (IllegalStateException e) {
+            } catch (Throwable e) {
                 Log.e(LOGTAG, "retainIconsOnStartup", e);
             } finally {
                 if (c != null) c.close();
             }
-
-            return null;
         }
     }
 
diff --git a/src/com/android/browser/CrashRecoveryHandler.java b/src/com/android/browser/CrashRecoveryHandler.java
index 995d119..aa48aac 100644
--- a/src/com/android/browser/CrashRecoveryHandler.java
+++ b/src/com/android/browser/CrashRecoveryHandler.java
@@ -25,7 +25,6 @@
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
 import android.util.Log;
@@ -83,8 +82,7 @@
         mController = controller;
         mContext = mController.getActivity().getApplicationContext();
         mForegroundHandler = new Handler();
-        Looper looper = BrowserSettings.getInstance().getBackgroundLooper();
-        mBackgroundHandler = new Handler(looper) {
+        mBackgroundHandler = new Handler(BackgroundHandler.getLooper()) {
 
             @Override
             public void handleMessage(Message msg) {
diff --git a/src/com/android/browser/SystemAllowGeolocationOrigins.java b/src/com/android/browser/SystemAllowGeolocationOrigins.java
index b53611f..a01541f 100644
--- a/src/com/android/browser/SystemAllowGeolocationOrigins.java
+++ b/src/com/android/browser/SystemAllowGeolocationOrigins.java
@@ -73,49 +73,48 @@
     }
 
     void maybeApplySettingAsync() {
-        new AsyncTask<Void,Void,Void>() {
-            @Override
-            protected Void doInBackground(Void... params) {
-                maybeApplySetting();
-                return null;
-            }
-        }.execute();
+        BackgroundHandler.execute(mMaybeApplySetting);
     }
 
     /**
      * Checks to see if the system setting has changed and if so,
      * updates the Geolocation permissions accordingly.
      */
-    private void maybeApplySetting() {
-        // Get the new value
-        String newSetting = getSystemSetting();
+    private Runnable mMaybeApplySetting = new Runnable() {
 
-        // Get the last read value
-        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext);
-        String lastReadSetting =
-                preferences.getString(LAST_READ_ALLOW_GEOLOCATION_ORIGINS, "");
+        @Override
+        public void run() {
+         // Get the new value
+            String newSetting = getSystemSetting();
 
-        // If the new value is the same as the last one we read, we're done.
-        if (TextUtils.equals(lastReadSetting, newSetting)) {
-            return;
+            // Get the last read value
+            SharedPreferences preferences = BrowserSettings.getInstance()
+                    .getPreferences();
+            String lastReadSetting =
+                    preferences.getString(LAST_READ_ALLOW_GEOLOCATION_ORIGINS, "");
+
+            // If the new value is the same as the last one we read, we're done.
+            if (TextUtils.equals(lastReadSetting, newSetting)) {
+                return;
+            }
+
+            // Save the new value as the last read value
+            preferences.edit()
+                    .putString(LAST_READ_ALLOW_GEOLOCATION_ORIGINS, newSetting)
+                    .apply();
+
+            Set<String> oldOrigins = parseAllowGeolocationOrigins(lastReadSetting);
+            Set<String> newOrigins = parseAllowGeolocationOrigins(newSetting);
+            Set<String> addedOrigins = setMinus(newOrigins, oldOrigins);
+            Set<String> removedOrigins = setMinus(oldOrigins, newOrigins);
+
+            // Remove the origins in the last read value
+            removeOrigins(removedOrigins);
+
+            // Add the origins in the new value
+            addOrigins(addedOrigins);
         }
-
-        // Save the new value as the last read value
-        preferences.edit()
-                .putString(LAST_READ_ALLOW_GEOLOCATION_ORIGINS, newSetting)
-                .apply();
-
-        Set<String> oldOrigins = parseAllowGeolocationOrigins(lastReadSetting);
-        Set<String> newOrigins = parseAllowGeolocationOrigins(newSetting);
-        Set<String> addedOrigins = setMinus(newOrigins, oldOrigins);
-        Set<String> removedOrigins = setMinus(oldOrigins, newOrigins);
-
-        // Remove the origins in the last read value
-        removeOrigins(removedOrigins);
-
-        // Add the origins in the new value
-        addOrigins(addedOrigins);
-    }
+    };
 
     /**
      * Parses the value of the default geolocation permissions setting.