Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4555)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java

Issue 1711063002: Avoid disk reads in TabPersistentStore for max tab_id. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add refactoring to this CL. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
index fd870da029d87051ff1206444a8f04a97e6bb582..d2cb3f19ec5517ffc52df3d41af671eb2517f9e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -5,9 +5,11 @@
package org.chromium.chrome.browser.tabmodel;
import android.content.Context;
+import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.StrictMode;
import android.os.SystemClock;
+import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.util.AtomicFile;
import android.text.TextUtils;
@@ -24,6 +26,7 @@ import org.chromium.chrome.browser.TabState;
import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabIdManager;
import org.chromium.content_public.browser.LoadUrlParams;
import java.io.BufferedInputStream;
@@ -60,6 +63,9 @@ public class TabPersistentStore extends TabPersister {
@VisibleForTesting
public static final String SAVED_STATE_FILE = "tab_state";
+ private static final String PREF_HAS_COMPUTED_MAX_ID =
+ "org.chromium.chrome.browser.tabmodel.TabPersistentStore.HAS_COMPUTED_MAX_ID";
+
/** Prevents two copies of the Migration task from being created. */
private static final Object MIGRATION_LOCK = new Object();
@@ -157,6 +163,8 @@ public class TabPersistentStore extends TabPersister {
private SparseIntArray mNormalTabsRestored;
private SparseIntArray mIncognitoTabsRestored;
+ private SharedPreferences mPreferences;
+
/**
* Creates an instance of a TabPersistentStore.
@@ -176,6 +184,7 @@ public class TabPersistentStore extends TabPersister {
mTabsToRestore = new ArrayDeque<TabRestoreDetails>();
mSelectorIndex = selectorIndex;
mObserver = observer;
+ mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
createMigrationTask();
}
@@ -189,7 +198,7 @@ public class TabPersistentStore extends TabPersister {
}
@Override
- public File getStateDirectory() {
+ protected File getStateDirectory() {
if (mStateDirectory == null) {
mStateDirectory = getStateDirectory(mContext, mSelectorIndex);
}
@@ -197,8 +206,8 @@ public class TabPersistentStore extends TabPersister {
}
/**
- * Sets where the base state directory is. If overridding this value, set it before the
- * instance's mStateDirectory field is initialized.
+ * Sets where the base state directory is. If overriding this value, set it before
+ * instantiating TabPersistentStore.
*/
@VisibleForTesting
public static void setBaseStateDirectory(File directory) {
@@ -209,7 +218,7 @@ public class TabPersistentStore extends TabPersister {
* @return Folder that all metadata for the ChromeTabbedActivity TabModels should be located.
* Each subdirectory stores info about different instances of ChromeTabbedActivity.
*/
- public static File getBaseStateDirectory(Context context) {
+ private static File getBaseStateDirectory(Context context) {
if (sBaseStateDirectory == null) {
setBaseStateDirectory(context.getDir(BASE_STATE_FOLDER, Context.MODE_PRIVATE));
}
@@ -232,9 +241,13 @@ public class TabPersistentStore extends TabPersister {
* Waits for the task that migrates all state files to their new location to finish.
*/
@VisibleForTesting
- public static void waitForMigrationToFinish() throws InterruptedException, ExecutionException {
+ public static void waitForMigrationToFinish() {
assert sMigrationTask != null : "The migration should be initialized by now.";
- sMigrationTask.get();
+ try {
+ sMigrationTask.get();
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ }
}
private static void logSaveException(Exception e) {
@@ -330,41 +343,30 @@ public class TabPersistentStore extends TabPersister {
/**
* Restore saved state. Must be called before any tabs are added to the list.
- *
- * @return The next tab ID to use for new tabs.
*/
- public int loadState() {
- try {
- long time = SystemClock.elapsedRealtime();
- waitForMigrationToFinish();
- logExecutionTime("LoadStateTime", time);
- } catch (InterruptedException e) {
- // Ignore these exceptions, we'll do the best we can.
- } catch (ExecutionException e) {
- // Ignore these exceptions, we'll do the best we can.
- }
+ public void loadState() {
+ long time = SystemClock.elapsedRealtime();
+ waitForMigrationToFinish();
+ logExecutionTime("LoadStateTime", time);
mCancelNormalTabLoads = false;
mCancelIncognitoTabLoads = false;
mNormalTabsRestored = new SparseIntArray();
mIncognitoTabsRestored = new SparseIntArray();
- int nextId = 0;
try {
- nextId = loadStateInternal();
+ time = SystemClock.elapsedRealtime();
+ assert mTabModelSelector.getModel(true).getCount() == 0;
+ assert mTabModelSelector.getModel(false).getCount() == 0;
+ checkAndUpdateMaxTabId();
+ readSavedStateFile(getStateDirectory(),
+ createOnTabStateReadCallback(mTabModelSelector.isIncognitoSelected()));
+ logExecutionTime("LoadStateInternalTime", time);
} catch (Exception e) {
- // Catch generic exception to prevent a corrupted state from crashing the app
- // at startup.
+ // Catch generic exception to prevent a corrupted state from crashing app on startup.
Log.d(TAG, "loadState exception: " + e.toString(), e);
}
- // As everything is loaded asynchronously user actions can create a tab that has ids
- // pointing to old files and not deleted fast enough. This makes sure to delete everything
- // that we are sure not to use.
- // This assumes that the app will only create tab with id at and above nextId.
- cleanupPersistentDataAtAndAboveId(nextId);
-
if (mObserver != null) mObserver.onInitialized(mTabsToRestore.size());
- return nextId;
}
/**
@@ -728,70 +730,62 @@ public class TabPersistentStore extends TabPersister {
}
/**
- * Load the saved state of the tab model. No tabs will be restored until you call
- * {@link #restoreTabs(boolean)}. Must be called before any tabs are added to the list.
+ * @param isIncognitoSelected Whether the tab model is incognito.
+ * @return A callback for reading data from tab models.
+ */
+ private OnTabStateReadCallback createOnTabStateReadCallback(final boolean isIncognitoSelected) {
+ return new OnTabStateReadCallback() {
+ @Override
+ public void onDetailsRead(int index, int id, String url, Boolean isIncognito,
+ boolean isStandardActiveIndex, boolean isIncognitoActiveIndex) {
+ // Note that incognito tab may not load properly so we may need to use
+ // the current tab from the standard model.
+ // This logic only works because we store the incognito indices first.
+ TabRestoreDetails details =
+ new TabRestoreDetails(id, index, isIncognito, url);
+
+ if ((isIncognitoActiveIndex && isIncognitoSelected)
+ || (isStandardActiveIndex && !isIncognitoSelected)) {
+ // Active tab gets loaded first
+ mTabsToRestore.addFirst(details);
+ } else {
+ mTabsToRestore.addLast(details);
+ }
+
+ if (mObserver != null) {
+ mObserver.onDetailsRead(
+ index, id, url, isStandardActiveIndex, isIncognitoActiveIndex);
+ }
+ }
+ };
+ }
+
+ /**
+ * If a global max tab ID has not been computed and stored before, then check all the state
+ * folders and calculate a new global max tab ID to be used. Must be called before any new tabs
+ * are created.
*
* @throws IOException
*/
- @VisibleForTesting
- public int loadStateInternal() throws IOException {
+ private void checkAndUpdateMaxTabId() throws IOException {
+ if (mPreferences.getBoolean(PREF_HAS_COMPUTED_MAX_ID, false)) {
+ return;
+ }
+ int maxId = 0;
// Temporarily allowing disk access. TODO: Fix. See http://crbug.com/473357
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
- long time = SystemClock.elapsedRealtime();
- assert mTabModelSelector.getModel(true).getCount() == 0;
- assert mTabModelSelector.getModel(false).getCount() == 0;
- int maxId = 0;
-
File[] folders = getBaseStateDirectory(mContext).listFiles();
- if (folders == null) return maxId;
-
- File stateFolder = getStateDirectory();
+ if (folders == null) return;
for (File folder : folders) {
- assert folder.isDirectory();
if (!folder.isDirectory()) continue;
- boolean readDir = folder.equals(stateFolder);
- final Deque<TabRestoreDetails> restoreList = readDir ? mTabsToRestore : null;
- final boolean isIncognitoSelected = mTabModelSelector.isIncognitoSelected();
-
- // TODO(dfalcantara): Store the max tab ID in a shared preference so that it can be
- // shared with all of the other modes that Chrome runs in and to
- // avoid reading in all of the possible app_tabs subdirectories.
- int curId = readSavedStateFile(folder, new OnTabStateReadCallback() {
- @Override
- public void onDetailsRead(int index, int id, String url, Boolean isIncognito,
- boolean isStandardActiveIndex, boolean isIncognitoActiveIndex) {
- // If we're not trying to build the restore list skip the build part.
- // We've already read all the state for this entry from the input stream.
- if (restoreList == null) return;
-
- // Note that incognito tab may not load properly so we may need to use
- // the current tab from the standard model.
- // This logic only works because we store the incognito indices first.
- TabRestoreDetails details =
- new TabRestoreDetails(id, index, isIncognito, url);
-
- if ((isIncognitoActiveIndex && isIncognitoSelected)
- || (isStandardActiveIndex && !isIncognitoSelected)) {
- // Active tab gets loaded first
- restoreList.addFirst(details);
- } else {
- restoreList.addLast(details);
- }
-
- if (mObserver != null) {
- mObserver.onDetailsRead(
- index, id, url, isStandardActiveIndex, isIncognitoActiveIndex);
- }
- }
- });
- maxId = Math.max(maxId, curId);
+ maxId = Math.max(maxId, readSavedStateFile(folder, null));
}
- logExecutionTime("LoadStateInternalTime", time);
- return maxId;
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
+ TabIdManager.getInstance().incrementIdCounterTo(maxId);
+ mPreferences.edit().putBoolean(PREF_HAS_COMPUTED_MAX_ID, true).apply();
}
public static int readSavedStateFile(File folder, OnTabStateReadCallback callback)
@@ -836,8 +830,10 @@ public class TabPersistentStore extends TabPersister {
if (id >= nextId) nextId = id + 1;
Boolean isIncognito = (incognitoCount < 0) ? null : i < incognitoCount;
- callback.onDetailsRead(i, id, tabUrl, isIncognito,
- i == standardActiveIndex, i == incognitoActiveIndex);
+ if (callback != null) {
+ callback.onDetailsRead(i, id, tabUrl, isIncognito,
+ i == standardActiveIndex, i == incognitoActiveIndex);
+ }
}
logExecutionTime("ReadSavedStateTime", time);
return nextId;

Powered by Google App Engine
This is Rietveld 408576698