Commit b14ef397 authored by David Maunder's avatar David Maunder Committed by Commit Bot

Use LevelDB storage for ShoppingPersistedTabData

We were previously using file storage until LevelDB storage was
available. LevelDB storage requires a profile so some tweaks were
made to PersistedTabDataConfiguration. One of which is the factory
pattern was used to ensure we acquire LevelDBPersistedTabDataStorage
based on the current profile and that we only have one
LevelDBPersistedTabDataStorage instance per profile.

Bug: 1129626
Change-Id: Ia1f14c9c2b6f2da02bac27ccd255152e45a4218c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2533843Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Commit-Queue: David Maunder <davidjm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827453}
parent 27c12c2e
...@@ -560,6 +560,7 @@ chrome_test_java_sources = [ ...@@ -560,6 +560,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/tab/WebContentsStateBridgeTest.java", "javatests/src/org/chromium/chrome/browser/tab/WebContentsStateBridgeTest.java",
"javatests/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabDataTest.java", "javatests/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabDataTest.java",
"javatests/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorageTest.java", "javatests/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorageTest.java",
"javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactoryTest.java",
"javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageTest.java", "javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageTest.java",
"javatests/src/org/chromium/chrome/browser/tab/state/PersistedTabDataTest.java", "javatests/src/org/chromium/chrome/browser/tab/state/PersistedTabDataTest.java",
"javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java", "javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java",
......
...@@ -6,6 +6,9 @@ package org.chromium.chrome.browser.tasks.tab_management; ...@@ -6,6 +6,9 @@ package org.chromium.chrome.browser.tasks.tab_management;
import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.chromium.base.GarbageCollectionTestUtils.canBeGarbageCollected; import static org.chromium.base.GarbageCollectionTestUtils.canBeGarbageCollected;
...@@ -24,18 +27,26 @@ import android.widget.TextView; ...@@ -24,18 +27,26 @@ import android.widget.TextView;
import androidx.test.filters.MediumTest; import androidx.test.filters.MediumTest;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.base.test.UiThreadTest; import org.chromium.base.test.UiThreadTest;
import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.MockTab; import org.chromium.chrome.browser.tab.MockTab;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.state.LevelDBPersistedTabDataStorage;
import org.chromium.chrome.browser.tab.state.LevelDBPersistedTabDataStorageJni;
import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabData; import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabData;
import org.chromium.chrome.tab_ui.R; import org.chromium.chrome.tab_ui.R;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate; import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate;
import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor; import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
...@@ -54,6 +65,9 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -54,6 +65,9 @@ import java.util.concurrent.atomic.AtomicInteger;
*/ */
@RunWith(ChromeJUnit4ClassRunner.class) @RunWith(ChromeJUnit4ClassRunner.class)
public class TabListViewHolderTest extends DummyUiActivityTestCase { public class TabListViewHolderTest extends DummyUiActivityTestCase {
@Rule
public JniMocker mMocker = new JniMocker();
private static final int TAB1_ID = 456; private static final int TAB1_ID = 456;
private static final int TAB2_ID = 789; private static final int TAB2_ID = 789;
private static final String EXPECTED_PRICE_STRING = "$287"; private static final String EXPECTED_PRICE_STRING = "$287";
...@@ -73,6 +87,12 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -73,6 +87,12 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
private ViewGroup mSelectableTabListView; private ViewGroup mSelectableTabListView;
@Mock
private Profile mProfile;
@Mock
private LevelDBPersistedTabDataStorage.Natives mLevelDBPersistedTabDataStorage;
private TabListMediator.ThumbnailFetcher mMockThumbnailProvider = private TabListMediator.ThumbnailFetcher mMockThumbnailProvider =
new TabListMediator.ThumbnailFetcher(new TabListMediator.ThumbnailProvider() { new TabListMediator.ThumbnailFetcher(new TabListMediator.ThumbnailProvider() {
@Override @Override
...@@ -124,6 +144,7 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -124,6 +144,7 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
@Override @Override
public void setUpTest() throws Exception { public void setUpTest() throws Exception {
super.setUpTest(); super.setUpTest();
MockitoAnnotations.initMocks(this);
ViewGroup view = new LinearLayout(getActivity()); ViewGroup view = new LinearLayout(getActivity());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
...@@ -178,6 +199,13 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -178,6 +199,13 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
PropertyModelChangeProcessor.create(mSelectableModel, mSelectableTabListView, PropertyModelChangeProcessor.create(mSelectableModel, mSelectableTabListView,
TabListViewBinder::bindSelectableListTab); TabListViewBinder::bindSelectableListTab);
}); });
mMocker.mock(LevelDBPersistedTabDataStorageJni.TEST_HOOKS, mLevelDBPersistedTabDataStorage);
doNothing()
.when(mLevelDBPersistedTabDataStorage)
.init(any(LevelDBPersistedTabDataStorage.class), any(BrowserContextHandle.class));
doReturn(false).when(mProfile).isOffTheRecord();
LevelDBPersistedTabDataStorage.setSkipNativeAssertionsForTesting(true);
Profile.setLastUsedProfileForTesting(mProfile);
} }
private void testGridSelected(ViewGroup holder, PropertyModel model) { private void testGridSelected(ViewGroup holder, PropertyModel model) {
......
...@@ -61,8 +61,8 @@ public class CriticalPersistedTabDataTest { ...@@ -61,8 +61,8 @@ public class CriticalPersistedTabDataTest {
public void setUp() throws Exception { public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
PersistedTabDataConfiguration.setUseTestConfig(true); PersistedTabDataConfiguration.setUseTestConfig(true);
mStorage = mStorage = (MockPersistedTabDataStorage) PersistedTabDataConfiguration.getTestConfig()
(MockPersistedTabDataStorage) PersistedTabDataConfiguration.getTestConfig().storage; .getStorage();
} }
@SmallTest @SmallTest
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tab.state;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import androidx.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.chromium.base.test.UiThreadTest;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.profiles.ProfileManager;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
/**
* Tests relating to {@link LevelDBPersistedTabDataStorageFactory}
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class LevelDBPersistedTabDataStorageFactoryTest {
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@Rule
public JniMocker mMocker = new JniMocker();
@Mock
private Profile mProfile1;
@Mock
private Profile mProfile2;
@Mock
private LevelDBPersistedTabDataStorage.Natives mLevelDBPersistedTabDataStorage;
@Before
public void setUp() throws Exception {
mActivityTestRule.startMainActivityOnBlankPage();
MockitoAnnotations.initMocks(this);
mMocker.mock(LevelDBPersistedTabDataStorageJni.TEST_HOOKS, mLevelDBPersistedTabDataStorage);
doNothing()
.when(mLevelDBPersistedTabDataStorage)
.init(any(LevelDBPersistedTabDataStorage.class), any(BrowserContextHandle.class));
doNothing().when(mLevelDBPersistedTabDataStorage).destroy(anyLong());
doReturn(false).when(mProfile1).isOffTheRecord();
doReturn(false).when(mProfile2).isOffTheRecord();
LevelDBPersistedTabDataStorage.setSkipNativeAssertionsForTesting(true);
}
@SmallTest
@Test
public void testFactoryMethod() {
LevelDBPersistedTabDataStorageFactory factory = new LevelDBPersistedTabDataStorageFactory();
Profile.setLastUsedProfileForTesting(mProfile1);
LevelDBPersistedTabDataStorage profile1Storage = factory.create();
Profile.setLastUsedProfileForTesting(mProfile2);
LevelDBPersistedTabDataStorage profile2Storage = factory.create();
Profile.setLastUsedProfileForTesting(mProfile1);
LevelDBPersistedTabDataStorage profile1StorageAgain = factory.create();
Assert.assertEquals(profile1Storage, profile1StorageAgain);
Assert.assertNotEquals(profile1Storage, profile2Storage);
}
@UiThreadTest
@SmallTest
@Test
public void testStorageDestroyedWhenProfileDestroyed() {
Profile.setLastUsedProfileForTesting(null);
Profile profile = Profile.getLastUsedRegularProfile();
LevelDBPersistedTabDataStorageFactory factory = new LevelDBPersistedTabDataStorageFactory();
LevelDBPersistedTabDataStorage storage = factory.create();
ProfileManager.onProfileDestroyed(profile);
Assert.assertTrue(storage.isDestroyed());
}
}
...@@ -81,6 +81,7 @@ public class ShoppingPersistedTabDataTest { ...@@ -81,6 +81,7 @@ public class ShoppingPersistedTabDataTest {
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mMocker.mock(EndpointFetcherJni.TEST_HOOKS, mEndpointFetcherJniMock); mMocker.mock(EndpointFetcherJni.TEST_HOOKS, mEndpointFetcherJniMock);
PersistedTabDataConfiguration.setUseTestConfig(true);
} }
@UiThreadTest @UiThreadTest
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.profiles; package org.chromium.chrome.browser.profiles;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.ObserverList; import org.chromium.base.ObserverList;
import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNative;
...@@ -59,7 +61,8 @@ public class ProfileManager { ...@@ -59,7 +61,8 @@ public class ProfileManager {
} }
} }
static void onProfileDestroyed(Profile profile) { @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public static void onProfileDestroyed(Profile profile) {
for (Observer observer : sObservers) { for (Observer observer : sObservers) {
observer.onProfileDestroyed(profile); observer.onProfileDestroyed(profile);
} }
......
...@@ -29,12 +29,14 @@ android_library("java") { ...@@ -29,12 +29,14 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java", "java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java",
"java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java", "java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java",
"java/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorage.java", "java/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorage.java",
"java/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactory.java",
"java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java", "java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java",
"java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabDataStorage.java", "java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabDataStorage.java",
"java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java", "java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java",
"java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java", "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java",
"java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java", "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java",
"java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataStorage.java", "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataStorage.java",
"java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataStorageFactory.java",
"java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java", "java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java",
] ]
......
...@@ -76,9 +76,9 @@ public class CriticalPersistedTabData extends PersistedTabData { ...@@ -76,9 +76,9 @@ public class CriticalPersistedTabData extends PersistedTabData {
private CriticalPersistedTabData(Tab tab) { private CriticalPersistedTabData(Tab tab) {
super(tab, super(tab,
PersistedTabDataConfiguration.get(CriticalPersistedTabData.class, tab.isIncognito()) PersistedTabDataConfiguration.get(CriticalPersistedTabData.class, tab.isIncognito())
.storage, .getStorage(),
PersistedTabDataConfiguration.get(CriticalPersistedTabData.class, tab.isIncognito()) PersistedTabDataConfiguration.get(CriticalPersistedTabData.class, tab.isIncognito())
.id); .getId());
} }
/** /**
...@@ -164,7 +164,7 @@ public class CriticalPersistedTabData extends PersistedTabData { ...@@ -164,7 +164,7 @@ public class CriticalPersistedTabData extends PersistedTabData {
public static byte[] restore(int tabId, boolean isIncognito) { public static byte[] restore(int tabId, boolean isIncognito) {
PersistedTabDataConfiguration config = PersistedTabDataConfiguration config =
PersistedTabDataConfiguration.get(CriticalPersistedTabData.class, isIncognito); PersistedTabDataConfiguration.get(CriticalPersistedTabData.class, isIncognito);
return config.storage.restore(tabId, config.id); return config.getStorage().restore(tabId, config.getId());
} }
/** /**
...@@ -176,7 +176,7 @@ public class CriticalPersistedTabData extends PersistedTabData { ...@@ -176,7 +176,7 @@ public class CriticalPersistedTabData extends PersistedTabData {
public static void restore(int tabId, boolean isIncognito, Callback<byte[]> callback) { public static void restore(int tabId, boolean isIncognito, Callback<byte[]> callback) {
PersistedTabDataConfiguration config = PersistedTabDataConfiguration config =
PersistedTabDataConfiguration.get(CriticalPersistedTabData.class, isIncognito); PersistedTabDataConfiguration.get(CriticalPersistedTabData.class, isIncognito);
config.storage.restore(tabId, config.id, callback); config.getStorage().restore(tabId, config.getId(), callback);
} }
/** /**
......
...@@ -20,24 +20,34 @@ import java.util.Locale; ...@@ -20,24 +20,34 @@ import java.util.Locale;
* of {@link PersistedTabDataStorage}. * of {@link PersistedTabDataStorage}.
*/ */
public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage { public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage {
// In a mock environment, the native code will not be running so we should not
// make assertions about mNativePersistedStateDB
private static boolean sSkipNativeAssertionsForTesting;
private long mNativePersistedStateDB; private long mNativePersistedStateDB;
// Callback is only used for synchronization of save and delete in testing. // Callback is only used for synchronization of save and delete in testing.
// Otherwise it is a no-op. // Otherwise it is a no-op.
private Runnable mOnCompleteForTesting; private Runnable mOnCompleteForTesting;
// TODO(crbug.com/1146799) Apply tricks like @CheckDiscard or @RemovableInRelease to improve // TODO(crbug.com/1146799) Apply tricks like @CheckDiscard or @RemovableInRelease to improve
// performance // performance
private boolean mIsDestroyed;
LevelDBPersistedTabDataStorage(Profile profile) { LevelDBPersistedTabDataStorage(Profile profile) {
assert !profile.isOffTheRecord() assert !profile.isOffTheRecord()
: "LevelDBPersistedTabDataStorage is not supported for incognito profiles"; : "LevelDBPersistedTabDataStorage is not supported for incognito profiles";
LevelDBPersistedTabDataStorageJni.get().init(this, profile); LevelDBPersistedTabDataStorageJni.get().init(this, profile);
assert mNativePersistedStateDB != 0; makeNativeAssertion();
}
private void makeNativeAssertion() {
if (!sSkipNativeAssertionsForTesting) {
assert mNativePersistedStateDB != 0;
}
} }
@MainThread @MainThread
@Override @Override
public void save(int tabId, String dataId, byte[] data) { public void save(int tabId, String dataId, byte[] data) {
assert mNativePersistedStateDB != 0; makeNativeAssertion();
LevelDBPersistedTabDataStorageJni.get().save( LevelDBPersistedTabDataStorageJni.get().save(
mNativePersistedStateDB, getKey(tabId, dataId), data, mOnCompleteForTesting); mNativePersistedStateDB, getKey(tabId, dataId), data, mOnCompleteForTesting);
} }
...@@ -45,7 +55,7 @@ public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage { ...@@ -45,7 +55,7 @@ public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage {
@MainThread @MainThread
@Override @Override
public void restore(int tabId, String dataId, Callback<byte[]> callback) { public void restore(int tabId, String dataId, Callback<byte[]> callback) {
assert mNativePersistedStateDB != 0; makeNativeAssertion();
LevelDBPersistedTabDataStorageJni.get().load( LevelDBPersistedTabDataStorageJni.get().load(
mNativePersistedStateDB, getKey(tabId, dataId), callback); mNativePersistedStateDB, getKey(tabId, dataId), callback);
} }
...@@ -65,7 +75,7 @@ public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage { ...@@ -65,7 +75,7 @@ public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage {
@MainThread @MainThread
@Override @Override
public void delete(int tabId, String dataId) { public void delete(int tabId, String dataId) {
assert mNativePersistedStateDB != 0; makeNativeAssertion();
LevelDBPersistedTabDataStorageJni.get().delete( LevelDBPersistedTabDataStorageJni.get().delete(
mNativePersistedStateDB, getKey(tabId, dataId), mOnCompleteForTesting); mNativePersistedStateDB, getKey(tabId, dataId), mOnCompleteForTesting);
} }
...@@ -86,15 +96,25 @@ public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage { ...@@ -86,15 +96,25 @@ public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage {
* Destroy native instance of persisted_tab_state * Destroy native instance of persisted_tab_state
*/ */
public void destroy() { public void destroy() {
assert mNativePersistedStateDB != 0; if (!sSkipNativeAssertionsForTesting) {
assert mNativePersistedStateDB != 0;
}
LevelDBPersistedTabDataStorageJni.get().destroy(mNativePersistedStateDB); LevelDBPersistedTabDataStorageJni.get().destroy(mNativePersistedStateDB);
mNativePersistedStateDB = 0; mNativePersistedStateDB = 0;
mIsDestroyed = true;
}
@VisibleForTesting
protected boolean isDestroyed() {
return mIsDestroyed;
} }
@CalledByNative @CalledByNative
private void setNativePtr(long nativePtr) { private void setNativePtr(long nativePtr) {
assert nativePtr != 0; if (!sSkipNativeAssertionsForTesting) {
assert mNativePersistedStateDB == 0; assert nativePtr != 0;
assert mNativePersistedStateDB == 0;
}
mNativePersistedStateDB = nativePtr; mNativePersistedStateDB = nativePtr;
} }
...@@ -103,8 +123,13 @@ public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage { ...@@ -103,8 +123,13 @@ public class LevelDBPersistedTabDataStorage implements PersistedTabDataStorage {
mOnCompleteForTesting = onComplete; mOnCompleteForTesting = onComplete;
} }
@VisibleForTesting
public static void setSkipNativeAssertionsForTesting(boolean skipNativeAssertionsForTesting) {
sSkipNativeAssertionsForTesting = skipNativeAssertionsForTesting;
}
@NativeMethods @NativeMethods
interface Natives { public interface Natives {
void init(LevelDBPersistedTabDataStorage caller, BrowserContextHandle handle); void init(LevelDBPersistedTabDataStorage caller, BrowserContextHandle handle);
void destroy(long nativePersistedStateDB); void destroy(long nativePersistedStateDB);
void save(long nativePersistedStateDB, String key, byte[] data, Runnable onComplete); void save(long nativePersistedStateDB, String key, byte[] data, Runnable onComplete);
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tab.state;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.profiles.ProfileManager;
import java.util.HashMap;
import java.util.Map;
/**
* Creates {@link LevelDBPersistedTabDataStorage} instances per profile
*/
public class LevelDBPersistedTabDataStorageFactory
implements PersistedTabDataStorageFactory<LevelDBPersistedTabDataStorage> {
public static final Map<Profile, LevelDBPersistedTabDataStorage> sProfileToLevelDBStorageMap =
new HashMap<>();
private static ProfileManager.Observer sProfileManagerObserver;
LevelDBPersistedTabDataStorageFactory() {
if (sProfileManagerObserver == null) {
sProfileManagerObserver = new ProfileManager.Observer() {
@Override
public void onProfileAdded(Profile profile) {}
@Override
public void onProfileDestroyed(Profile destroyedProfile) {
LevelDBPersistedTabDataStorage storageToDestroy =
sProfileToLevelDBStorageMap.get(destroyedProfile);
if (storageToDestroy != null) {
storageToDestroy.destroy();
sProfileToLevelDBStorageMap.remove(destroyedProfile);
}
if (sProfileToLevelDBStorageMap.isEmpty()) {
ProfileManager.removeObserver(sProfileManagerObserver);
sProfileManagerObserver = null;
}
}
};
ProfileManager.addObserver(sProfileManagerObserver);
}
}
@Override
public LevelDBPersistedTabDataStorage create() {
Profile profile = Profile.getLastUsedRegularProfile();
LevelDBPersistedTabDataStorage storage = sProfileToLevelDBStorageMap.get(profile);
if (storage == null) {
storage = new LevelDBPersistedTabDataStorage(profile);
sProfileToLevelDBStorageMap.put(profile, storage);
}
return storage;
}
}
...@@ -22,9 +22,9 @@ public class MockPersistedTabData extends PersistedTabData { ...@@ -22,9 +22,9 @@ public class MockPersistedTabData extends PersistedTabData {
public MockPersistedTabData(Tab tab, int field) { public MockPersistedTabData(Tab tab, int field) {
super(tab, super(tab,
PersistedTabDataConfiguration.get(MockPersistedTabData.class, tab.isIncognito()) PersistedTabDataConfiguration.get(MockPersistedTabData.class, tab.isIncognito())
.storage, .getStorage(),
PersistedTabDataConfiguration.get(MockPersistedTabData.class, tab.isIncognito()) PersistedTabDataConfiguration.get(MockPersistedTabData.class, tab.isIncognito())
.id); .getId());
mField = field; mField = field;
} }
......
...@@ -79,7 +79,7 @@ public abstract class PersistedTabData implements UserData { ...@@ -79,7 +79,7 @@ public abstract class PersistedTabData implements UserData {
Tab tab, PersistedTabDataFactory<T> factory, byte[] data, Class<T> clazz) { Tab tab, PersistedTabDataFactory<T> factory, byte[] data, Class<T> clazz) {
PersistedTabDataConfiguration config = PersistedTabDataConfiguration config =
PersistedTabDataConfiguration.get(clazz, tab.isIncognito()); PersistedTabDataConfiguration.get(clazz, tab.isIncognito());
T persistedTabData = factory.create(data, config.storage, config.id); T persistedTabData = factory.create(data, config.getStorage(), config.getId());
setUserData(tab, clazz, persistedTabData); setUserData(tab, clazz, persistedTabData);
return persistedTabData; return persistedTabData;
} }
...@@ -126,14 +126,15 @@ public abstract class PersistedTabData implements UserData { ...@@ -126,14 +126,15 @@ public abstract class PersistedTabData implements UserData {
if (sCachedCallbacks.get(key).size() > 1) return; if (sCachedCallbacks.get(key).size() > 1) return;
PersistedTabDataConfiguration config = PersistedTabDataConfiguration config =
PersistedTabDataConfiguration.get(clazz, tab.isIncognito()); PersistedTabDataConfiguration.get(clazz, tab.isIncognito());
config.storage.restore(tab.getId(), config.id, (data) -> { config.getStorage().restore(tab.getId(), config.getId(), (data) -> {
if (data == null) { if (data == null) {
tabDataCreator.onResult((tabData) -> { tabDataCreator.onResult((tabData) -> {
updateLastUpdatedMs(tabData); updateLastUpdatedMs(tabData);
onPersistedTabDataResult(tabData, tab, clazz, key); onPersistedTabDataResult(tabData, tab, clazz, key);
}); });
} else { } else {
T persistedTabDataFromStorage = factory.create(data, config.storage, config.id); T persistedTabDataFromStorage =
factory.create(data, config.getStorage(), config.getId());
if (persistedTabDataFromStorage.needsUpdate()) { if (persistedTabDataFromStorage.needsUpdate()) {
tabDataCreator.onResult((tabData) -> { tabDataCreator.onResult((tabData) -> {
updateLastUpdatedMs(tabData); updateLastUpdatedMs(tabData);
......
...@@ -16,20 +16,47 @@ import java.util.Map; ...@@ -16,20 +16,47 @@ import java.util.Map;
public enum PersistedTabDataConfiguration { public enum PersistedTabDataConfiguration {
// TODO(crbug.com/1059650) investigate should this go in the app code? // TODO(crbug.com/1059650) investigate should this go in the app code?
// Also investigate if the storage instance should be shared. // Also investigate if the storage instance should be shared.
CRITICAL_PERSISTED_TAB_DATA("CPTD", new FilePersistedTabDataStorage()), CRITICAL_PERSISTED_TAB_DATA("CPTD"),
ENCRYPTED_CRITICAL_PERSISTED_TAB_DATA("ECPTD", new EncryptedFilePersistedTabDataStorage()), ENCRYPTED_CRITICAL_PERSISTED_TAB_DATA("ECPTD"),
MOCK_PERSISTED_TAB_DATA("MPTD", new FilePersistedTabDataStorage()), MOCK_PERSISTED_TAB_DATA("MPTD"),
ENCRYPTED_MOCK_PERSISTED_TAB_DATA("EMPTD", new EncryptedFilePersistedTabDataStorage()), ENCRYPTED_MOCK_PERSISTED_TAB_DATA("EMPTD"),
// TODO(crbug.com/1129626) Move Shopping to Level DB based storage SHOPPING_PERSISTED_TAB_DATA("SPTD"),
SHOPPING_PERSISTED_TAB_DATA("SPTD", new FilePersistedTabDataStorage()),
// TODO(crbug.com/1113828) investigate separating test from prod test implementations // TODO(crbug.com/1113828) investigate separating test from prod test implementations
TEST_CONFIG("TC", new MockPersistedTabDataStorage()); TEST_CONFIG("TC");
private static final Map<Class<? extends PersistedTabData>, PersistedTabDataConfiguration> private static final Map<Class<? extends PersistedTabData>, PersistedTabDataConfiguration>
sLookup = new HashMap<>(); sLookup = new HashMap<>();
private static final Map<Class<? extends PersistedTabData>, PersistedTabDataConfiguration> private static final Map<Class<? extends PersistedTabData>, PersistedTabDataConfiguration>
sEncryptedLookup = new HashMap<>(); sEncryptedLookup = new HashMap<>();
/**
* Ensure lazy initialization of singleton storage
*/
private static FilePersistedTabDataStorage sFilePersistedTabDataStorage;
private static EncryptedFilePersistedTabDataStorage sEncrpytedFilePersistedTabDataStorage;
private static MockPersistedTabDataStorage sMockPersistedTabDataStorage;
private static FilePersistedTabDataStorage getFilePersistedTabDataStorage() {
if (sFilePersistedTabDataStorage == null) {
sFilePersistedTabDataStorage = new FilePersistedTabDataStorage();
}
return sFilePersistedTabDataStorage;
}
private static EncryptedFilePersistedTabDataStorage getEncryptedFilePersistedTabDataStorage() {
if (sEncrpytedFilePersistedTabDataStorage == null) {
sEncrpytedFilePersistedTabDataStorage = new EncryptedFilePersistedTabDataStorage();
}
return sEncrpytedFilePersistedTabDataStorage;
}
private static MockPersistedTabDataStorage getMockPersistedTabDataStorage() {
if (sMockPersistedTabDataStorage == null) {
sMockPersistedTabDataStorage = new MockPersistedTabDataStorage();
}
return sMockPersistedTabDataStorage;
}
private static boolean sUseTestConfig; private static boolean sUseTestConfig;
static { static {
...@@ -40,18 +67,48 @@ public enum PersistedTabDataConfiguration { ...@@ -40,18 +67,48 @@ public enum PersistedTabDataConfiguration {
sEncryptedLookup.put(MockPersistedTabData.class, ENCRYPTED_MOCK_PERSISTED_TAB_DATA); sEncryptedLookup.put(MockPersistedTabData.class, ENCRYPTED_MOCK_PERSISTED_TAB_DATA);
sLookup.put(ShoppingPersistedTabData.class, SHOPPING_PERSISTED_TAB_DATA); sLookup.put(ShoppingPersistedTabData.class, SHOPPING_PERSISTED_TAB_DATA);
sEncryptedLookup.put(ShoppingPersistedTabData.class, SHOPPING_PERSISTED_TAB_DATA); sEncryptedLookup.put(ShoppingPersistedTabData.class, SHOPPING_PERSISTED_TAB_DATA);
CRITICAL_PERSISTED_TAB_DATA.mStorageFactory = () -> {
return getFilePersistedTabDataStorage();
};
ENCRYPTED_CRITICAL_PERSISTED_TAB_DATA.mStorageFactory = () -> {
return getEncryptedFilePersistedTabDataStorage();
};
MOCK_PERSISTED_TAB_DATA.mStorageFactory = () -> {
return getFilePersistedTabDataStorage();
};
ENCRYPTED_MOCK_PERSISTED_TAB_DATA.mStorageFactory = () -> {
return getEncryptedFilePersistedTabDataStorage();
};
SHOPPING_PERSISTED_TAB_DATA.mStorageFactory = new LevelDBPersistedTabDataStorageFactory();
TEST_CONFIG.mStorageFactory = () -> {
return getMockPersistedTabDataStorage();
};
} }
public final String id; private final String mId;
public final PersistedTabDataStorage storage; private PersistedTabDataStorageFactory mStorageFactory;
/** /**
* @param id identifier for {@link PersistedTabData} * @param id identifier for {@link PersistedTabData}
* @param storage {@link PersistedTabDataStorage} associated with {@link PersistedTabData} * @param storageFactory {@link PersistedTabDataStorageFactory} associated with {@link
* PersistedTabData}
*/
PersistedTabDataConfiguration(String id) {
mId = id;
}
/**
* @return {@link PersistedTabDataStorage} for a given configuration
*/
public PersistedTabDataStorage getStorage() {
return mStorageFactory.create();
}
/**
* @return id for a given configuration
*/ */
PersistedTabDataConfiguration(String id, PersistedTabDataStorage storage) { public String getId() {
this.id = id; return mId;
this.storage = storage;
} }
/** /**
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tab.state;
/**
* Creates a {@link PersistedTabDataStorage}
* @param <T> {@link PersistedTabDataStorage} being created
*/
public interface PersistedTabDataStorageFactory<T extends PersistedTabDataStorage> {
/**
* @return {@link PersistedTabDataStorage}
*/
T create();
}
\ No newline at end of file
...@@ -86,9 +86,9 @@ public class ShoppingPersistedTabData extends PersistedTabData { ...@@ -86,9 +86,9 @@ public class ShoppingPersistedTabData extends PersistedTabData {
public ShoppingPersistedTabData(Tab tab) { public ShoppingPersistedTabData(Tab tab) {
super(tab, super(tab,
PersistedTabDataConfiguration.get(ShoppingPersistedTabData.class, tab.isIncognito()) PersistedTabDataConfiguration.get(ShoppingPersistedTabData.class, tab.isIncognito())
.storage, .getStorage(),
PersistedTabDataConfiguration.get(ShoppingPersistedTabData.class, tab.isIncognito()) PersistedTabDataConfiguration.get(ShoppingPersistedTabData.class, tab.isIncognito())
.id); .getId());
} }
private ShoppingPersistedTabData( private ShoppingPersistedTabData(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment