Commit d79a4e51 authored by Christian Dullweber's avatar Christian Dullweber Committed by Commit Bot

Delete navigation entries from frozen state

When Chrome is restarted, tabs are initially in a frozen state and have
no WebContents. History deletions need to clean up this frozen state
to correctly remove navigation entries.

Add integration tests for deletion of navigation entries from regular
and frozen tabs.

Bug: 407074
Change-Id: Id69ffcf05622f8e02eace0036e6787cea0b4dfab
Reviewed-on: https://chromium-review.googlesource.com/949323
Commit-Queue: Christian Dullweber <dullweber@chromium.org>
Reviewed-by: default avatarBernhard Bauer <bauerb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#541768}
parent f787b55c
...@@ -596,6 +596,7 @@ android_library("chrome_test_java") { ...@@ -596,6 +596,7 @@ android_library("chrome_test_java") {
data = [ data = [
"//chrome/test/data/android/", "//chrome/test/data/android/",
"//chrome/test/data/banners/", "//chrome/test/data/banners/",
"//chrome/test/data/browsing_data/",
"//chrome/test/data/encoding_tests/auto_detect/Big5_with_no_encoding_specified.html", "//chrome/test/data/encoding_tests/auto_detect/Big5_with_no_encoding_specified.html",
"//chrome/test/data/geolocation/", "//chrome/test/data/geolocation/",
"//chrome/test/data/google/", "//chrome/test/data/google/",
......
...@@ -242,6 +242,7 @@ public abstract class ChromeFeatureList { ...@@ -242,6 +242,7 @@ public abstract class ChromeFeatureList {
public static final String PROGRESS_BAR_THROTTLE = "ProgressBarThrottle"; public static final String PROGRESS_BAR_THROTTLE = "ProgressBarThrottle";
public static final String PWA_PERSISTENT_NOTIFICATION = "PwaPersistentNotification"; public static final String PWA_PERSISTENT_NOTIFICATION = "PwaPersistentNotification";
public static final String READER_MODE_IN_CCT = "ReaderModeInCCT"; public static final String READER_MODE_IN_CCT = "ReaderModeInCCT";
public static final String REMOVE_NAVIGATION_HISTORY = "RemoveNavigationHistory";
public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps"; public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps";
public static final String SITE_NOTIFICATION_CHANNELS = "SiteNotificationChannels"; public static final String SITE_NOTIFICATION_CHANNELS = "SiteNotificationChannels";
public static final String SOLE_INTEGRATION = "SoleIntegration"; public static final String SOLE_INTEGRATION = "SoleIntegration";
......
...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser; ...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser;
import android.graphics.Color; import android.graphics.Color;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
...@@ -92,6 +93,21 @@ public class TabState { ...@@ -92,6 +93,21 @@ public class TabState {
return nativeRestoreContentsFromByteBuffer(mBuffer, mVersion, isHidden); return nativeRestoreContentsFromByteBuffer(mBuffer, mVersion, isHidden);
} }
/**
* Deletes navigation entries from this buffer matching predicate.
* @param predicate Handle for a deletion predicate interpreted by native code.
Only valid during this call frame.
* @return WebContentsState A new state or null if nothing changed.
*/
@Nullable
public WebContentsState deleteNavigationEntries(long predicate) {
ByteBuffer newBuffer = nativeDeleteNavigationEntries(mBuffer, mVersion, predicate);
if (newBuffer == null) return null;
WebContentsState newState = new TabState.WebContentsStateNative(newBuffer);
newState.setVersion(TabState.CONTENTS_STATE_CURRENT_VERSION);
return newState;
}
/** /**
* Creates a WebContents for the ContentsState and adds it as an historical tab, then * Creates a WebContents for the ContentsState and adds it as an historical tab, then
* deletes the WebContents. * deletes the WebContents.
...@@ -470,6 +486,9 @@ public class TabState { ...@@ -470,6 +486,9 @@ public class TabState {
private static native ByteBuffer nativeGetContentsStateAsByteBuffer(Tab tab); private static native ByteBuffer nativeGetContentsStateAsByteBuffer(Tab tab);
private static native ByteBuffer nativeDeleteNavigationEntries(
ByteBuffer state, int saveStateVersion, long predicate);
private static native ByteBuffer nativeCreateSingleNavigationStateAsByteBuffer( private static native ByteBuffer nativeCreateSingleNavigationStateAsByteBuffer(
String url, String referrerUrl, int referrerPolicy, boolean isIncognito); String url, String referrerUrl, int referrerPolicy, boolean isIncognito);
......
...@@ -2737,6 +2737,21 @@ public class Tab ...@@ -2737,6 +2737,21 @@ public class Tab
} }
} }
/**
* Delete navigation entries from frozen state matching the predicate.
* @param predicate Handle for a deletion predicate interpreted by native code.
* Only valid during this call frame.
*/
@CalledByNative
private void deleteNavigationEntriesFromFrozenState(long predicate) {
if (mFrozenContentsState == null) return;
WebContentsState newState = mFrozenContentsState.deleteNavigationEntries(predicate);
if (newState != null) {
mFrozenContentsState = newState;
notifyNavigationEntriesDeleted();
}
}
/** /**
* @return The reason the Tab was launched. * @return The reason the Tab was launched.
*/ */
......
...@@ -4,6 +4,12 @@ ...@@ -4,6 +4,12 @@
package org.chromium.chrome.browser.preferences.privacy; package org.chromium.chrome.browser.preferences.privacy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import android.content.Intent; import android.content.Intent;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.preference.Preference; import android.preference.Preference;
...@@ -15,11 +21,13 @@ import android.support.v7.app.AlertDialog; ...@@ -15,11 +21,13 @@ import android.support.v7.app.AlertDialog;
import android.widget.Button; import android.widget.Button;
import android.widget.ListView; import android.widget.ListView;
import org.hamcrest.Matchers;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
...@@ -31,23 +39,31 @@ import org.chromium.chrome.browser.ChromeActivity; ...@@ -31,23 +39,31 @@ import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.ShortcutHelper;
import org.chromium.chrome.browser.TabState;
import org.chromium.chrome.browser.browsing_data.ClearBrowsingDataTab; import org.chromium.chrome.browser.browsing_data.ClearBrowsingDataTab;
import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.preferences.Preferences; import org.chromium.chrome.browser.preferences.Preferences;
import org.chromium.chrome.browser.preferences.privacy.ClearBrowsingDataPreferences.DialogOption; import org.chromium.chrome.browser.preferences.privacy.ClearBrowsingDataPreferences.DialogOption;
import org.chromium.chrome.browser.preferences.website.ContentSetting; import org.chromium.chrome.browser.preferences.website.ContentSetting;
import org.chromium.chrome.browser.preferences.website.NotificationInfo; import org.chromium.chrome.browser.preferences.website.NotificationInfo;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.webapps.TestFetchStorageCallback; import org.chromium.chrome.browser.webapps.TestFetchStorageCallback;
import org.chromium.chrome.browser.webapps.WebappDataStorage; import org.chromium.chrome.browser.webapps.WebappDataStorage;
import org.chromium.chrome.browser.webapps.WebappRegistry; import org.chromium.chrome.browser.webapps.WebappRegistry;
import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.chrome.test.util.browser.signin.SigninTestUtil; import org.chromium.chrome.test.util.browser.signin.SigninTestUtil;
import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper; import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.NavigationController;
import org.chromium.content_public.browser.NavigationEntry;
import org.chromium.content_public.browser.WebContents;
import org.chromium.net.test.EmbeddedTestServer; import org.chromium.net.test.EmbeddedTestServer;
import java.net.URL; import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
...@@ -62,6 +78,8 @@ public class ClearBrowsingDataPreferencesTest { ...@@ -62,6 +78,8 @@ public class ClearBrowsingDataPreferencesTest {
@Rule @Rule
public ChromeActivityTestRule<ChromeActivity> mActivityTestRule = public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
new ChromeActivityTestRule<>(ChromeActivity.class); new ChromeActivityTestRule<>(ChromeActivity.class);
@Rule
public TestRule mProcessor = new Features.InstrumentationProcessor();
private EmbeddedTestServer mTestServer; private EmbeddedTestServer mTestServer;
...@@ -527,6 +545,93 @@ public class ClearBrowsingDataPreferencesTest { ...@@ -527,6 +545,93 @@ public class ClearBrowsingDataPreferencesTest {
"true", mActivityTestRule.runJavaScriptCodeInCurrentTab("hasAllStorage()")); "true", mActivityTestRule.runJavaScriptCodeInCurrentTab("hasAllStorage()"));
} }
/**
* Tests navigation entries are removed by history deletions.
*/
@Test
@EnableFeatures(ChromeFeatureList.REMOVE_NAVIGATION_HISTORY)
@MediumTest
public void testNavigationDeletion() throws Exception {
final String url1 = mTestServer.getURL("/chrome/test/data/browsing_data/a.html");
final String url2 = mTestServer.getURL("/chrome/test/data/browsing_data/b.html");
// Navigate to url1 and url2.
Tab tab = mActivityTestRule.loadUrlInNewTab(url1);
mActivityTestRule.loadUrl(url2);
NavigationController controller = tab.getWebContents().getNavigationController();
assertTrue(tab.canGoBack());
assertEquals(1, controller.getLastCommittedEntryIndex());
assertThat(getUrls(controller), Matchers.contains(url1, url2));
// Clear history.
setDataTypesToClear(Arrays.asList(DialogOption.CLEAR_HISTORY));
ClearBrowsingDataPreferences preferences =
(ClearBrowsingDataPreferences) startPreferences().getFragmentForTest();
ThreadUtils.runOnUiThreadBlocking(() -> clickClearButton(preferences));
waitForProgressToComplete(preferences);
// Check navigation entries.
assertFalse(tab.canGoBack());
assertEquals(0, controller.getLastCommittedEntryIndex());
assertThat(getUrls(controller), Matchers.contains(url2));
}
/**
* Tests navigation entries from frozen state are removed by history deletions.
*/
@Test
@MediumTest
@EnableFeatures(ChromeFeatureList.REMOVE_NAVIGATION_HISTORY)
public void testFrozenNavigationDeletion() throws Exception {
final String url1 = mTestServer.getURL("/chrome/test/data/browsing_data/a.html");
final String url2 = mTestServer.getURL("/chrome/test/data/browsing_data/b.html");
// Navigate to url1 and url2, close and recreate as frozen tab.
Tab tab = mActivityTestRule.loadUrlInNewTab(url1);
mActivityTestRule.loadUrl(url2);
Tab[] frozen = new Tab[1];
WebContents[] restored = new WebContents[1];
ThreadUtils.runOnUiThreadBlocking(() -> {
TabState state = tab.getState();
mActivityTestRule.getActivity().getCurrentTabModel().closeTab(tab);
frozen[0] = mActivityTestRule.getActivity().getCurrentTabCreator().createFrozenTab(
state, tab.getId(), 1);
restored[0] = frozen[0].getState().contentsState.restoreContentsFromByteBuffer(false);
});
// Check content of frozen state.
NavigationController controller = restored[0].getNavigationController();
assertEquals(1, controller.getLastCommittedEntryIndex());
assertThat(getUrls(controller), Matchers.contains(url1, url2));
assertNull(frozen[0].getWebContents());
// Delete history.
setDataTypesToClear(Arrays.asList(DialogOption.CLEAR_HISTORY));
ClearBrowsingDataPreferences preferences =
(ClearBrowsingDataPreferences) startPreferences().getFragmentForTest();
ThreadUtils.runOnUiThreadBlocking(() -> clickClearButton(preferences));
waitForProgressToComplete(preferences);
// Check that frozen state was cleaned up.
ThreadUtils.runOnUiThreadBlocking(() -> {
restored[0] = frozen[0].getState().contentsState.restoreContentsFromByteBuffer(false);
});
controller = restored[0].getNavigationController();
assertEquals(0, controller.getLastCommittedEntryIndex());
assertThat(getUrls(controller), Matchers.contains(url2));
assertNull(frozen[0].getWebContents());
}
private List<String> getUrls(NavigationController controller) {
List<String> urls = new ArrayList<>();
int i = 0;
while (true) {
NavigationEntry entry = controller.getEntryAtIndex(i++);
if (entry == null) return urls;
urls.add(entry.getUrl());
}
}
private void setDataTypesToClear(final List<DialogOption> typesToClear) { private void setDataTypesToClear(final List<DialogOption> typesToClear) {
ThreadUtils.runOnUiThreadBlocking(() -> { ThreadUtils.runOnUiThreadBlocking(() -> {
for (DialogOption option : DialogOption.values()) { for (DialogOption option : DialogOption.values()) {
......
...@@ -238,6 +238,13 @@ sync_sessions::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const { ...@@ -238,6 +238,13 @@ sync_sessions::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
return synced_tab_delegate_.get(); return synced_tab_delegate_.get();
} }
void TabAndroid::DeleteFrozenNavigationEntries(
const WebContentsState::DeletionPredicate& predicate) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_Tab_deleteNavigationEntriesFromFrozenState(
env, weak_java_tab_.get(env), reinterpret_cast<intptr_t>(&predicate));
}
void TabAndroid::SetWindowSessionID(SessionID::id_type window_id) { void TabAndroid::SetWindowSessionID(SessionID::id_type window_id) {
session_window_id_.set_id(window_id); session_window_id_.set_id(window_id);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "chrome/browser/android/tab_state.h"
#include "chrome/browser/sync/glue/synced_tab_delegate_android.h" #include "chrome/browser/sync/glue/synced_tab_delegate_android.h"
#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
#include "components/favicon/core/favicon_driver_observer.h" #include "components/favicon/core/favicon_driver_observer.h"
...@@ -114,6 +115,10 @@ class TabAndroid : public CoreTabHelperDelegate, ...@@ -114,6 +115,10 @@ class TabAndroid : public CoreTabHelperDelegate,
Profile* GetProfile() const; Profile* GetProfile() const;
sync_sessions::SyncedTabDelegate* GetSyncedTabDelegate() const; sync_sessions::SyncedTabDelegate* GetSyncedTabDelegate() const;
// Delete navigation entries matching predicate from frozen state.
void DeleteFrozenNavigationEntries(
const WebContentsState::DeletionPredicate& predicate);
void SetWindowSessionID(SessionID::id_type window_id); void SetWindowSessionID(SessionID::id_type window_id);
void SetSyncId(int sync_id); void SetSyncId(int sync_id);
......
This diff is collapsed.
...@@ -9,9 +9,8 @@ ...@@ -9,9 +9,8 @@
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
namespace content { namespace sessions {
class NavigationEntry; class SerializedNavigationEntry;
class WebContents;
} }
class TabAndroid; class TabAndroid;
...@@ -19,18 +18,20 @@ class TabAndroid; ...@@ -19,18 +18,20 @@ class TabAndroid;
// Stores state for a WebContents, including its navigation history. // Stores state for a WebContents, including its navigation history.
class WebContentsState { class WebContentsState {
public: public:
using DeletionPredicate = base::RepeatingCallback<bool(
const sessions::SerializedNavigationEntry& entry)>;
static base::android::ScopedJavaLocalRef<jobject> static base::android::ScopedJavaLocalRef<jobject>
GetContentsStateAsByteBuffer(JNIEnv* env, TabAndroid* tab); GetContentsStateAsByteBuffer(JNIEnv* env, TabAndroid* tab);
// Common implementation for GetContentsStateAsByteBuffer() and // Returns a new buffer without the navigations matching |predicate|.
// CreateContentsStateAsByteBuffer(). Does not assume ownership of the // Returns null if no deletions happened.
// navigations.
static base::android::ScopedJavaLocalRef<jobject> static base::android::ScopedJavaLocalRef<jobject>
WriteNavigationsAsByteBuffer( DeleteNavigationEntriesFromByteBuffer(JNIEnv* env,
JNIEnv* env, void* data,
bool is_off_the_record, int size,
const std::vector<content::NavigationEntry*>& navigations, int saved_state_version,
int current_entry); const DeletionPredicate& predicate);
// Extracts display title from serialized tab data on restore // Extracts display title from serialized tab data on restore
static base::android::ScopedJavaLocalRef<jstring> static base::android::ScopedJavaLocalRef<jstring>
...@@ -42,13 +43,6 @@ class WebContentsState { ...@@ -42,13 +43,6 @@ class WebContentsState {
GetVirtualUrlFromByteBuffer(JNIEnv* env, void* data, GetVirtualUrlFromByteBuffer(JNIEnv* env, void* data,
int size, int saved_state_version); int size, int saved_state_version);
// Restores a WebContents from the passed in state.
static content::WebContents* RestoreContentsFromByteBuffer(
void* data,
int size,
int saved_state_version,
bool initially_hidden);
// Restores a WebContents from the passed in state. // Restores a WebContents from the passed in state.
static base::android::ScopedJavaLocalRef<jobject> static base::android::ScopedJavaLocalRef<jobject>
RestoreContentsFromByteBuffer(JNIEnv* env, RestoreContentsFromByteBuffer(JNIEnv* env,
......
...@@ -60,33 +60,20 @@ bool UrlMatcherForSession(const base::flat_set<GURL>& urls, ...@@ -60,33 +60,20 @@ bool UrlMatcherForSession(const base::flat_set<GURL>& urls,
base::flat_set<GURL> CreateUrlSet(const history::URLRows& deleted_rows) { base::flat_set<GURL> CreateUrlSet(const history::URLRows& deleted_rows) {
std::vector<GURL> urls; std::vector<GURL> urls;
for (const history::URLRow& row : deleted_rows) { for (const history::URLRow& row : deleted_rows)
urls.push_back(row.url()); urls.push_back(row.url());
}
return base::flat_set<GURL>(std::move(urls)); return base::flat_set<GURL>(std::move(urls));
} }
// Desktop is using |TabStripModel|, Android |TabModel|. They don't have a
// common base class but both have a |GetWebContentsAt()| method.
// TODO(dullweber): Add a common base class?
template <typename TabList>
void DeleteNavigationEntries( void DeleteNavigationEntries(
TabList* tab_list, content::WebContents* web_contents,
int tab_count,
const content::NavigationController::DeletionPredicate& predicate) { const content::NavigationController::DeletionPredicate& predicate) {
for (int i = 0; i < tab_count; i++) { content::NavigationController* controller = &web_contents->GetController();
content::WebContents* web_contents = tab_list->GetWebContentsAt(i); controller->DiscardNonCommittedEntries();
// TODO(dullweber): Non-loaded tabs on Android don't have a WebContents. // We discarded pending and transient entries but there could still be
// We need to cleanup their TabState instead. // no last_committed_entry, which would prevent deletion.
if (!web_contents) if (controller->CanPruneAllButLastCommitted())
continue; controller->DeleteNavigationEntries(predicate);
content::NavigationController* controller = &web_contents->GetController();
controller->DiscardNonCommittedEntries();
// We discarded pending and transient entries but there could still be
// no last_committed_entry, which would prevent deletion.
if (controller->CanPruneAllButLastCommitted())
controller->DeleteNavigationEntries(predicate);
}
} }
void DeleteTabNavigationEntries(Profile* profile, void DeleteTabNavigationEntries(Profile* profile,
...@@ -99,17 +86,30 @@ void DeleteTabNavigationEntries(Profile* profile, ...@@ -99,17 +86,30 @@ void DeleteTabNavigationEntries(Profile* profile,
: base::BindRepeating(&UrlMatcher, base::ConstRef(url_set)); : base::BindRepeating(&UrlMatcher, base::ConstRef(url_set));
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
auto session_predicate =
time_range.IsValid()
? base::BindRepeating(&TimeRangeMatcherForSession, time_range.begin(),
time_range.end())
: base::BindRepeating(&UrlMatcherForSession, base::ConstRef(url_set));
for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) {
TabModel* tab_model = *it; TabModel* tab_model = *it;
if (tab_model->GetProfile() == profile) { if (tab_model->GetProfile() == profile) {
DeleteNavigationEntries(tab_model, tab_model->GetTabCount(), predicate); for (int i = 0; i < tab_model->GetTabCount(); i++) {
TabAndroid* tab = tab_model->GetTabAt(i);
tab->DeleteFrozenNavigationEntries(session_predicate);
content::WebContents* web_contents = tab->web_contents();
if (web_contents)
DeleteNavigationEntries(web_contents, predicate);
}
} }
} }
#else #else
for (Browser* browser : *BrowserList::GetInstance()) { for (Browser* browser : *BrowserList::GetInstance()) {
TabStripModel* tab_strip = browser->tab_strip_model(); TabStripModel* tab_strip = browser->tab_strip_model();
if (browser->profile() == profile) { if (browser->profile() == profile) {
DeleteNavigationEntries(tab_strip, tab_strip->count(), predicate); for (int i = 0; i < tab_strip->count(); i++)
DeleteNavigationEntries(tab_strip->GetWebContentsAt(i), predicate);
} }
} }
#endif #endif
...@@ -160,18 +160,19 @@ void DeleteTabRestoreEntries(Profile* profile, ...@@ -160,18 +160,19 @@ void DeleteTabRestoreEntries(Profile* profile,
const base::flat_set<GURL>& url_set) { const base::flat_set<GURL>& url_set) {
sessions::TabRestoreService* tab_service = sessions::TabRestoreService* tab_service =
TabRestoreServiceFactory::GetForProfile(profile); TabRestoreServiceFactory::GetForProfile(profile);
if (tab_service) { if (!tab_service)
auto predicate = return;
time_range.IsValid()
? base::BindRepeating(&TimeRangeMatcherForSession, auto predicate =
time_range.begin(), time_range.end()) time_range.IsValid()
: base::BindRepeating(&UrlMatcherForSession, url_set); ? base::BindRepeating(&TimeRangeMatcherForSession, time_range.begin(),
if (tab_service->IsLoaded()) { time_range.end())
PerformTabRestoreDeletion(tab_service, predicate); : base::BindRepeating(&UrlMatcherForSession, url_set);
} else { if (tab_service->IsLoaded()) {
// The helper deletes itself when the tab entry deletion is finished. PerformTabRestoreDeletion(tab_service, predicate);
new TabRestoreDeletionHelper(tab_service, predicate); } else {
} // The helper deletes itself when the tab entry deletion is finished.
new TabRestoreDeletionHelper(tab_service, predicate);
} }
} }
......
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