Startup optimization

 Bug: 5019676
 Save one thread by letting CrashRecoveryHandler re-use the BrowserSettings
 startup thread

 Lazy initialize the wake lock only if we need it (avoids IPC overhead at startup)

 Slight ordering shuffle in BrowserActivity to maximize the usefulness of the
 BrowserSettings startup thread

Change-Id: I1fc7412d492f93e0630008fa6030da9e0d726ebb
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index b2a83e1..3ab45f7 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -57,6 +57,13 @@
         }
         super.onCreate(icicle);
 
+        // If this was a web search request, pass it on to the default web
+        // search provider and finish this activity.
+        if (IntentHandler.handleWebSearchIntent(this, null, getIntent())) {
+            finish();
+            return;
+        }
+
         BrowserSettings settings = BrowserSettings.getInstance();
 
         // render the browser in OpenGL
@@ -69,13 +76,6 @@
             this.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
         }
 
-        // If this was a web search request, pass it on to the default web
-        // search provider and finish this activity.
-        if (IntentHandler.handleWebSearchIntent(this, null, getIntent())) {
-            finish();
-            return;
-        }
-
         AccessibilityManager accessibilityManager = (AccessibilityManager)
                 getSystemService(ACCESSIBILITY_SERVICE);
         if (accessibilityManager != null && accessibilityManager.isEnabled()) {
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 97769fc..a4f0f04 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -22,6 +22,7 @@
 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;
@@ -103,6 +104,10 @@
     private AutofillHandler mAutofillHandler;
     private WeakHashMap<WebSettings, String> mCustomUserAgents;
     private boolean mInitialized = 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;
@@ -127,7 +132,7 @@
         mCustomUserAgents = new WeakHashMap<WebSettings, String>();
         mPrefs.registerOnSharedPreferenceChangeListener(this);
         mAutofillHandler.asyncLoadFromDb();
-        new Thread(mInitialization, "BrowserSettingsInitialization").start();
+        new Thread(mSetupAndLoop, "BackgroundLooper").start();
     }
 
     public void setController(Controller controller) {
@@ -139,6 +144,11 @@
         }
     }
 
+    public Looper getBackgroundLooper() {
+        requireInitialization();
+        return mBackgroundLooper;
+    }
+
     public void startManagingSettings(WebSettings settings) {
         synchronized (mManagedSettings) {
             syncStaticSettings(settings);
@@ -147,7 +157,7 @@
         }
     }
 
-    private Runnable mInitialization = new Runnable() {
+    private Runnable mSetupAndLoop = new Runnable() {
 
         @Override
         public void run() {
@@ -189,10 +199,13 @@
                 }
                 mPrefs.edit().remove(PREF_TEXT_SIZE).apply();
             }
+            Looper.prepare();
+            mBackgroundLooper = Looper.myLooper();
             synchronized (BrowserSettings.this) {
                 mInitialized = true;
                 BrowserSettings.this.notifyAll();
             }
+            Looper.loop();
         }
     };
 
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 03e2d8b..731da18 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -206,7 +206,6 @@
     // Checks to see when the bookmarks database has changed, and updates the
     // Tabs' notion of whether they represent bookmarked sites.
     private ContentObserver mBookmarksObserver;
-    private DataController mDataController;
     private CrashRecoveryHandler mCrashRecoveryHandler;
 
     private boolean mSimulateActionBarOverlayMode;
@@ -228,7 +227,6 @@
     public Controller(Activity browser) {
         mActivity = browser;
         mSettings = BrowserSettings.getInstance();
-        mDataController = DataController.getInstance(mActivity);
         mTabControl = new TabControl(this);
         mSettings.setController(this);
         mCrashRecoveryHandler = CrashRecoveryHandler.initialize(this);
@@ -239,10 +237,6 @@
         mPageDialogsHandler = new PageDialogsHandler(mActivity, this);
         mNfcHandler = new NfcHandler(mActivity, this);
 
-        PowerManager pm = (PowerManager) mActivity
-                .getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Browser");
-
         startHandler();
         mBookmarksObserver = new ContentObserver(mHandler) {
             @Override
@@ -518,7 +512,7 @@
                         break;
 
                     case RELEASE_WAKELOCK:
-                        if (mWakeLock.isHeld()) {
+                        if (mWakeLock != null && mWakeLock.isHeld()) {
                             mWakeLock.release();
                             // if we reach here, Browser should be still in the
                             // background loading after WAKELOCK_TIMEOUT (5-min).
@@ -622,6 +616,11 @@
         if (tab != null) {
             tab.pause();
             if (!pauseWebViewTimers(tab)) {
+                if (mWakeLock == null) {
+                    PowerManager pm = (PowerManager) mActivity
+                            .getSystemService(Context.POWER_SERVICE);
+                    mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Browser");
+                }
                 mWakeLock.acquire();
                 mHandler.sendMessageDelayed(mHandler
                         .obtainMessage(RELEASE_WAKELOCK), WAKELOCK_TIMEOUT);
@@ -662,10 +661,7 @@
             current.resume();
             resumeWebViewTimers(current);
         }
-        if (mWakeLock.isHeld()) {
-            mHandler.removeMessages(RELEASE_WAKELOCK);
-            mWakeLock.release();
-        }
+        releaseWakeLock();
 
         mUi.onResume();
         mNetworkHandler.onResume();
@@ -673,6 +669,13 @@
         WebView.enablePlatformNotifications();
     }
 
+    private void releaseWakeLock() {
+        if (mWakeLock != null && mWakeLock.isHeld()) {
+            mHandler.removeMessages(RELEASE_WAKELOCK);
+            mWakeLock.release();
+        }
+    }
+
     /**
      * resume all WebView timers using the WebView instance of the given tab
      * @param tab guaranteed non-null
@@ -832,10 +835,7 @@
         // pause the WebView timer and release the wake lock if it is finished
         // while BrowserActivity is in pause state.
         if (mActivityPaused && pauseWebViewTimers(tab)) {
-            if (mWakeLock.isHeld()) {
-                mHandler.removeMessages(RELEASE_WAKELOCK);
-                mWakeLock.release();
-            }
+            releaseWakeLock();
         }
 
         // Performance probe
@@ -890,7 +890,7 @@
         }
         // Update the title in the history database if not in private browsing mode
         if (!tab.isPrivateBrowsingEnabled()) {
-            mDataController.updateHistoryTitle(pageUrl, title);
+            DataController.getInstance(mActivity).updateHistoryTitle(pageUrl, title);
         }
     }
 
@@ -937,7 +937,7 @@
                 || url.regionMatches(true, 0, "about:", 0, 6)) {
             return;
         }
-        mDataController.updateVisitedHistory(url);
+        DataController.getInstance(mActivity).updateVisitedHistory(url);
         WebIconDatabase.getInstance().retainIconForPageUrl(url);
         if (!mActivityPaused) {
             // Since we clear the state in onPause, don't backup the current
diff --git a/src/com/android/browser/CrashRecoveryHandler.java b/src/com/android/browser/CrashRecoveryHandler.java
index 8d7f243..6e40ffd 100644
--- a/src/com/android/browser/CrashRecoveryHandler.java
+++ b/src/com/android/browser/CrashRecoveryHandler.java
@@ -25,9 +25,8 @@
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.Parcel;
-import android.os.Process;
 import android.util.Log;
 
 import java.io.ByteArrayOutputStream;
@@ -73,10 +72,8 @@
     private CrashRecoveryHandler(Controller controller) {
         mController = controller;
         mForegroundHandler = new Handler();
-        HandlerThread thread = new HandlerThread(LOGTAG,
-                Process.THREAD_PRIORITY_BACKGROUND);
-        thread.start();
-        mBackgroundHandler = new Handler(thread.getLooper());
+        Looper looper = BrowserSettings.getInstance().getBackgroundLooper();
+        mBackgroundHandler = new Handler(looper);
     }
 
     public void backupState() {