Add bulletproofing to state recovery

 Bug: 5166335

Change-Id: Ife9ef2da7664f8de6b0ff9655611efa78d84df05
diff --git a/src/com/android/browser/Browser.java b/src/com/android/browser/Browser.java
index 76aaa0b..add8bdd 100644
--- a/src/com/android/browser/Browser.java
+++ b/src/com/android/browser/Browser.java
@@ -23,12 +23,9 @@
 public class Browser extends Application { 
 
     private final static String LOGTAG = "browser";
-
-    // Set to true to enable extra debugging.
-    final static boolean DEBUG = false;
     
     // Set to true to enable verbose logging.
-    final static boolean LOGV_ENABLED = DEBUG;
+    final static boolean LOGV_ENABLED = false;
 
     // Set to true to enable extra debug logging.
     final static boolean LOGD_ENABLED = true;
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 690e29f..b86759a 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -31,8 +31,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.Window;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
 
 import com.google.common.annotations.VisibleForTesting;
 
@@ -45,8 +43,7 @@
 
     private final static String LOGTAG = "browser";
 
-    private final static boolean LOGV_ENABLED =
-            com.android.browser.Browser.LOGV_ENABLED;
+    private final static boolean LOGV_ENABLED = Browser.LOGV_ENABLED;
 
     private Controller mController;
     private UI mUi;
@@ -54,7 +51,8 @@
     @Override
     public void onCreate(Bundle icicle) {
         if (LOGV_ENABLED) {
-            Log.v(LOGTAG, this + " onStart");
+            Log.v(LOGTAG, this + " onStart, has state: "
+                    + (icicle == null ? "false" : "true"));
         }
         super.onCreate(icicle);
 
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 84d7e36..3093085 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -635,8 +635,6 @@
         mNfcHandler.onPause();
 
         WebView.disablePlatformNotifications();
-        mCrashRecoveryHandler.backupState();
-
     }
 
     void onSaveInstanceState(Bundle outState) {
@@ -852,6 +850,7 @@
 
     @Override
     public void onProgressChanged(Tab tab) {
+        mCrashRecoveryHandler.backupState();
         int newProgress = tab.getLoadProgress();
 
         if (newProgress == 100) {
@@ -942,11 +941,7 @@
             return;
         }
         DataController.getInstance(mActivity).updateVisitedHistory(url);
-        if (!mActivityPaused) {
-            // Since we clear the state in onPause, don't backup the current
-            // state if we are already paused
-            mCrashRecoveryHandler.backupState();
-        }
+        mCrashRecoveryHandler.backupState();
     }
 
     @Override
diff --git a/src/com/android/browser/CrashRecoveryHandler.java b/src/com/android/browser/CrashRecoveryHandler.java
index 8cb5929..c2fbbd2 100644
--- a/src/com/android/browser/CrashRecoveryHandler.java
+++ b/src/com/android/browser/CrashRecoveryHandler.java
@@ -34,6 +34,7 @@
 
 public class CrashRecoveryHandler {
 
+    private static final boolean LOGV_ENABLED = Browser.LOGV_ENABLED;
     private static final String LOGTAG = "BrowserCrashRecovery";
     private static final String STATE_FILE = "browser_state.parcel";
     private static final String RECOVERY_PREFERENCES = "browser_recovery_prefs";
@@ -84,14 +85,26 @@
             public void handleMessage(Message msg) {
                 switch (msg.what) {
                 case MSG_WRITE_STATE:
+                    if (LOGV_ENABLED) {
+                        Log.v(LOGTAG, "Saving crash recovery state");
+                    }
                     Parcel p = Parcel.obtain();
                     try {
                         Bundle state = (Bundle) msg.obj;
                         state.writeToParcel(p, 0);
-                        File stateFile = new File(mContext.getCacheDir(), STATE_FILE);
-                        FileOutputStream fout = new FileOutputStream(stateFile);
+                        File stateJournal = new File(mContext.getCacheDir(),
+                                STATE_FILE + ".journal");
+                        FileOutputStream fout = new FileOutputStream(stateJournal);
                         fout.write(p.marshall());
                         fout.close();
+                        File stateFile = new File(mContext.getCacheDir(),
+                                STATE_FILE);
+                        if (!stateJournal.renameTo(stateFile)) {
+                            // Failed to rename, try deleting the existing
+                            // file and try again
+                            stateFile.delete();
+                            stateJournal.renameTo(stateFile);
+                        }
                     } catch (Throwable e) {
                         Log.i(LOGTAG, "Failed to save persistent state", e);
                     } finally {
@@ -99,6 +112,9 @@
                     }
                     break;
                 case MSG_CLEAR_STATE:
+                    if (LOGV_ENABLED) {
+                        Log.v(LOGTAG, "Clearing crash recovery state");
+                    }
                     File state = new File(mContext.getCacheDir(), STATE_FILE);
                     if (state.exists()) {
                         state.delete();
diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java
index c76197d..cc6b57c 100644
--- a/src/com/android/browser/IntentHandler.java
+++ b/src/com/android/browser/IntentHandler.java
@@ -65,6 +65,7 @@
     }
 
     void onNewIntent(Intent intent) {
+        mActivity.setIntent(null);
         Tab current = mTabControl.getCurrentTab();
         // When a tab is closed on exit, the current tab index is set to -1.
         // Reset before proceed as Browser requires the current tab to be set.
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index d7ce29b..d6106a5 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -56,6 +56,7 @@
 import android.webkit.SslErrorHandler;
 import android.webkit.URLUtil;
 import android.webkit.ValueCallback;
+import android.webkit.WebBackForwardList;
 import android.webkit.WebBackForwardListClient;
 import android.webkit.WebChromeClient;
 import android.webkit.WebHistoryItem;
@@ -1529,7 +1530,12 @@
                 mMainView.setPictureListener(this);
             }
             if (mSavedState != null) {
-                mMainView.restoreState(mSavedState);
+                WebBackForwardList restoredState
+                        = mMainView.restoreState(mSavedState);
+                if (restoredState == null || restoredState.getSize() == 0) {
+                    Log.w(LOGTAG, "Failed to restore WebView state!");
+                    loadUrl(mCurrentState.mOriginalUrl, null);
+                }
                 mSavedState = null;
             }
         }
@@ -1913,15 +1919,17 @@
         if (mMainView == null) {
             return mSavedState;
         }
-        // If the tab is the homepage or has no URL, don't save it
-        String homepage = BrowserSettings.getInstance().getHomePage();
-        if (TextUtils.equals(homepage, mCurrentState.mUrl)
-                || TextUtils.isEmpty(mCurrentState.mUrl)) {
+
+        if (TextUtils.isEmpty(mCurrentState.mUrl)) {
             return null;
         }
 
         mSavedState = new Bundle();
-        mMainView.saveState(mSavedState);
+        WebBackForwardList savedList = mMainView.saveState(mSavedState);
+        if (savedList == null || savedList.getSize() == 0) {
+            Log.w(LOGTAG, "Failed to save back/forward list for "
+                    + mCurrentState.mUrl);
+        }
 
         mSavedState.putLong(ID, mId);
         mSavedState.putString(CURRURL, mCurrentState.mUrl);