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

Unified Diff: ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm

Issue 2580363002: Upstream Chrome on iOS source code [1/11]. (Closed)
Patch Set: Created 4 years 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: ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
diff --git a/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm b/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..a04ec4d416cd2c844f42be162f75d7b378474a7b
--- /dev/null
+++ b/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
@@ -0,0 +1,453 @@
+// Copyright 2015 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.
+
+#import "ios/chrome/browser/browsing_data/browsing_data_removal_controller.h"
+
+#import <WebKit/WebKit.h>
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/containers/hash_tables.h"
+#import "base/ios/weak_nsobject.h"
+#include "base/logging.h"
+#import "base/mac/bind_objc_block.h"
+#include "base/memory/ref_counted.h"
+#include "components/open_from_clipboard/clipboard_recent_content.h"
+#include "components/signin/ios/browser/account_consistency_service.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/browsing_data/browsing_data_remover_helper.h"
+#include "ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.h"
+#include "ios/chrome/browser/callback_counter.h"
+#include "ios/chrome/browser/sessions/session_util.h"
+#include "ios/chrome/browser/signin/account_consistency_service_factory.h"
+#import "ios/chrome/browser/snapshots/snapshots_util.h"
+#import "ios/chrome/browser/ui/browser_view_controller.h"
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#import "ios/public/provider/chrome/browser/native_app_launcher/native_app_metadata.h"
+#import "ios/public/provider/chrome/browser/native_app_launcher/native_app_whitelist_manager.h"
+#include "ios/web/public/web_thread.h"
+#import "ios/web/public/web_view_creation_util.h"
+#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
+#include "net/cookies/cookie_store.h"
+#include "net/ssl/channel_id_service.h"
+#include "net/ssl/channel_id_store.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace {
+// Empty callback used by DeleteAllCreatedBetweenAsync below.
+void DoNothing(int n) {}
+}
+
+@interface BrowsingDataRemovalController ()
+// Removes data used by the Google App Launcher.
+- (void)removeGALData;
+// Removes browsing data that is created by web views associated with
+// |browserState|. |mask| is obtained from
+// IOSChromeBrowsingDataRemover::RemoveDataMask. |deleteBegin| defines the begin
+// time from which the data has to be removed, up to the present time.
+// |completionHandler| is called when this operation finishes. This method
+// finishes removal of the browsing data even if |browserState| is destroyed
+// after this method call.
+- (void)removeWebViewCreatedBrowsingDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask
+ deleteBegin:(base::Time)deleteBegin
+ completionHandler:
+ (ProceduralBlock)completionHandler;
+// Removes browsing data that is created by WKWebViews associated with
+// |browserState|. |browserState| must not be off the record. |mask| is obtained
+// from IOSChromeBrowsingDataRemover::RemoveDataMask. |deleteBegin| defines the
+// begin time from which the data has to be removed, up to the present time.
+// |completionHandler| is called when this operation finishes. This method
+// finishes removal of the browsing data even if |browserState| is destroyed
+// after this method call.
+// Note: This method works only on iOS9+.
+- (void)removeWKWebViewCreatedBrowsingDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask
+ deleteBegin:
+ (base::Time)deleteBegin
+ completionHandler:
+ (ProceduralBlock)completionHandler;
+
+// Removes browsing data associated with |browserState| that is specific to iOS
+// and not removed when the |browserState| is destroyed.
+// |mask| is obtained from IOSChromeBrowsingDataRemover::RemoveDataMask
+// |deleteBegin| defines the begin time from which the data has to be removed.
+// |browserState| cannot be null. |completionHandler| is called when
+// this operation finishes. This method finishes removal of the browsing data
+// even if |browserState| is destroyed after this method call.
+- (void)removeIOSSpecificBrowsingDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask
+ deleteBegin:(base::Time)deleteBegin
+ completionHandler:
+ (ProceduralBlock)completionHandler;
+// Removes browsing data from |browserState| that is persisted on disk.
+// |mask| is obtained from IOSChromeBrowsingDataRemover::RemoveDataMask.
+// |browserState| cannot be null and must be off the record.
+// This method finishes removal of the browsing data even if |browserState| is
+// destroyed after this method call.
+- (void)removeIOSSpecificPersistentIncognitoDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask;
+
+// Increments the count of pending removal operations for |browserState|.
+// Called when any removal operation for |browserState| starts.
+- (void)incrementPendingRemovalCountForBrowserState:
+ (ios::ChromeBrowserState*)browserState;
+// Decrements the count of pending removal operations for |browserState|.
+// Called when a removal operation for |browserState| finishes.
+- (void)decrementPendingRemovalCountForBrowserState:
+ (ios::ChromeBrowserState*)browserState;
+@end
+
+@implementation BrowsingDataRemovalController {
+ // Wrapper around IOSChromeBrowsingDataRemover that serializes removal
+ // operations.
+ std::unique_ptr<BrowsingDataRemoverHelper> _browsingDataRemoverHelper;
+ // The delegate.
+ base::WeakNSProtocol<id<BrowsingDataRemovalControllerDelegate>> _delegate;
+ // A map that tracks the number of pending removals for a given
+ // ChromeBrowserState.
+ base::hash_map<ios::ChromeBrowserState*, int> _pendingRemovalCount;
+}
+
+- (instancetype)initWithDelegate:
+ (id<BrowsingDataRemovalControllerDelegate>)delegate {
+ if ((self = [super init])) {
+ DCHECK(delegate);
+ _browsingDataRemoverHelper.reset(new BrowsingDataRemoverHelper());
+ _delegate.reset(delegate);
+ }
+ return self;
+}
+
+- (instancetype)init {
+ NOTREACHED();
+ return nil;
+}
+
+- (void)removeBrowsingDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask
+ timePeriod:(browsing_data::TimePeriod)timePeriod
+ completionHandler:(ProceduralBlock)completionHandler {
+ DCHECK(browserState);
+ DLOG_IF(WARNING, !mask) << "Nothing to remove!";
+ // Cookies and server bound certificates should have the same lifetime.
+ DCHECK_EQ((mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) != 0,
+ (mask & IOSChromeBrowsingDataRemover::REMOVE_CHANNEL_IDS) != 0);
+
+ [self incrementPendingRemovalCountForBrowserState:browserState];
+
+ ProceduralBlock browsingDataCleared = ^{
+ [self decrementPendingRemovalCountForBrowserState:browserState];
+ if (AccountConsistencyService* accountConsistencyService =
+ ios::AccountConsistencyServiceFactory::GetForBrowserState(
+ browserState)) {
+ accountConsistencyService->OnBrowsingDataRemoved();
+ }
+ if (completionHandler) {
+ completionHandler();
+ }
+ };
+
+ scoped_refptr<CallbackCounter> callbackCounter =
+ new CallbackCounter(base::BindBlock(browsingDataCleared));
+ ProceduralBlock decrementCallbackCounterCount = ^{
+ callbackCounter->DecrementCount();
+ };
+
+ callbackCounter->IncrementCount();
+ base::Time beginDeleteTime =
+ browsing_data::CalculateBeginDeleteTime(timePeriod);
+ [self removeIOSSpecificBrowsingDataFromBrowserState:browserState
+ mask:mask
+ deleteBegin:beginDeleteTime
+ completionHandler:
+ decrementCallbackCounterCount];
+
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_DOWNLOADS) {
+ DCHECK_EQ(browsing_data::ALL_TIME, timePeriod)
+ << "Partial clearing not supported";
+ callbackCounter->IncrementCount();
+ [_delegate
+ removeExternalFilesForBrowserState:browserState
+ completionHandler:decrementCallbackCounterCount];
+ }
+
+ if (!browserState->IsOffTheRecord()) {
+ callbackCounter->IncrementCount();
+ _browsingDataRemoverHelper->Remove(browserState, mask, timePeriod,
+ base::BindBlock(^{
+ callbackCounter->DecrementCount();
+ }));
+ }
+}
+
+- (void)removeIOSSpecificIncognitoBrowsingDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask
+ completionHandler:
+ (ProceduralBlock)
+ completionHandler {
+ DCHECK(browserState && browserState->IsOffTheRecord());
+ [self removeIOSSpecificBrowsingDataFromBrowserState:browserState
+ mask:mask
+ deleteBegin:base::Time()
+ completionHandler:completionHandler];
+}
+
+- (void)removeIOSSpecificBrowsingDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask
+ deleteBegin:(base::Time)deleteBegin
+ completionHandler:
+ (ProceduralBlock)completionHandler {
+ DCHECK(browserState);
+ [self incrementPendingRemovalCountForBrowserState:browserState];
+
+ ProceduralBlock browsingDataCleared = ^{
+ [self decrementPendingRemovalCountForBrowserState:browserState];
+ if (completionHandler) {
+ completionHandler();
+ }
+ };
+
+ // Note: Before adding any method below, make sure that it can finish clearing
+ // browsing data even when |browserState| is destroyed after this method call.
+
+ // If deleting history, clear visited links.
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_HISTORY) {
+ if (!browserState->IsOffTheRecord()) {
+ ClipboardRecentContent::GetInstance()->SuppressClipboardContent();
+ session_util::DeleteLastSession(browserState);
+ }
+ // Remove the screenshots taken by the system when backgrounding the
+ // application. Partial removal based on timePeriod is not required.
+ ClearIOSSnapshots();
+ }
+
+ // TODO(crbug.com/227636): Support multiple profile.
+ // Google App Launcher data is tied to the normal profile.
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_GOOGLE_APP_LAUNCHER_DATA &&
+ !browserState->IsOffTheRecord()) {
+ [self removeGALData];
+ }
+
+ if (browserState->IsOffTheRecord()) {
+ // In incognito, only data removal for all time is currently supported.
+ DCHECK_EQ(base::Time(), deleteBegin);
+ [self removeIOSSpecificPersistentIncognitoDataFromBrowserState:browserState
+ mask:mask];
+ }
+
+ [self removeWebViewCreatedBrowsingDataFromBrowserState:browserState
+ mask:mask
+ deleteBegin:deleteBegin
+ completionHandler:browsingDataCleared];
+}
+
+- (void)removeGALData {
+ [ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()
+ filteredAppsUsingBlock:^BOOL(const id<NativeAppMetadata> app,
+ BOOL* stop) {
+ [app resetInfobarHistory];
+ return NO;
+ }];
+}
+
+- (void)removeWebViewCreatedBrowsingDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask
+ deleteBegin:(base::Time)deleteBegin
+ completionHandler:
+ (ProceduralBlock)completionHandler {
+ // TODO(crbug.com/480654): Remove this check once browsing data partitioning
+ // between BrowserStates is achieved.
+ if (browserState->IsOffTheRecord()) {
+ if (completionHandler) {
+ dispatch_async(dispatch_get_main_queue(), completionHandler);
+ }
+ return;
+ }
+ scoped_refptr<CallbackCounter> callbackCounter =
+ new CallbackCounter(base::BindBlock(completionHandler ? completionHandler
+ : ^{
+ }));
+
+ // Note: Before adding any method below, make sure that it can finish clearing
+ // browsing data even when |browserState| is destroyed after this method call.
+
+ callbackCounter->IncrementCount();
+ [self removeWKWebViewCreatedBrowsingDataFromBrowserState:browserState
+ mask:mask
+ deleteBegin:deleteBegin
+ completionHandler:^{
+ callbackCounter->DecrementCount();
+ }];
+}
+
+- (void)
+removeWKWebViewCreatedBrowsingDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask
+ deleteBegin:(base::Time)deleteBegin
+ completionHandler:
+ (ProceduralBlock)completionHandler {
+ scoped_refptr<CallbackCounter> callbackCounter =
+ new CallbackCounter(base::BindBlock(completionHandler ? completionHandler
+ : ^{
+ }));
+ ProceduralBlock decrementCallbackCounterCount = ^{
+ callbackCounter->DecrementCount();
+ };
+
+ // Converts browsing data types from
+ // IOSChromeBrowsingDataRemover::RemoveDataMask to
+ // WKWebsiteDataStore strings.
+ base::scoped_nsobject<NSMutableSet> dataTypesToRemove(
+ [[NSMutableSet alloc] init]);
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_CACHE_STORAGE) {
+ [dataTypesToRemove addObject:WKWebsiteDataTypeDiskCache];
+ [dataTypesToRemove addObject:WKWebsiteDataTypeMemoryCache];
+ }
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_APPCACHE) {
+ [dataTypesToRemove addObject:WKWebsiteDataTypeOfflineWebApplicationCache];
+ }
+ WKWebView* markerWKWebView = nil;
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) {
+ // TODO(crbug.com/661630): This approach of creating a WKWebView to clear
+ // cookies is a workaround for
+ // https://bugs.webkit.org/show_bug.cgi?id=149078. Remove this, when that
+ // bug is fixed. Note: This WKWebView will be released when cookies have
+ // been cleared.
+ markerWKWebView = web::BuildWKWebView(CGRectZero, browserState);
+ [dataTypesToRemove addObject:WKWebsiteDataTypeCookies];
+ }
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_LOCAL_STORAGE) {
+ [dataTypesToRemove addObject:WKWebsiteDataTypeSessionStorage];
+ [dataTypesToRemove addObject:WKWebsiteDataTypeLocalStorage];
+ }
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_WEBSQL) {
+ [dataTypesToRemove addObject:WKWebsiteDataTypeWebSQLDatabases];
+ }
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_INDEXEDDB) {
+ [dataTypesToRemove addObject:WKWebsiteDataTypeIndexedDBDatabases];
+ }
+
+ ProceduralBlock afterRemovalFromWKWebsiteDataStore = ^{
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_VISITED_LINKS) {
+ // TODO(crbug.com/557963): Purging the WKProcessPool is a workaround for
+ // the fact that there is no public API to clear visited links in
+ // WKWebView. Remove this workaround if/when that API is made public.
+ // Note: Purging the WKProcessPool for clearing visisted links does have
+ // the side-effect of also losing the in-memory cookies of WKWebView but
+ // it is not a problem in practice since there is no UI to only have
+ // visited links be removed but not cookies.
+ DCHECK(mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES);
+ web::WKWebViewConfigurationProvider::FromBrowserState(browserState)
+ .Purge();
+ }
+
+ decrementCallbackCounterCount();
+ };
+
+ if ([dataTypesToRemove count]) {
+ callbackCounter->IncrementCount();
+ ProceduralBlock removeFromWKWebsiteDataStore = ^{
+ NSDate* beginDeleteDate =
+ [NSDate dateWithTimeIntervalSince1970:deleteBegin.ToDoubleT()];
+ [[WKWebsiteDataStore defaultDataStore]
+ removeDataOfTypes:dataTypesToRemove
+ modifiedSince:beginDeleteDate
+ completionHandler:afterRemovalFromWKWebsiteDataStore];
+ };
+
+ if (markerWKWebView) {
+ // TODO(crbug.com/661630): Executing JS enables the markerWKWebView to
+ // connect to the Networking process. This is so that the
+ // -[WKWebsiteDataStore removeDataOfTypes:] API is able to send an IPC
+ // message to the Networking process to clear cookies. This has been
+ // reverse-engineered by code inspection on the WebKit2 source code and is
+ // an undocumented workaround for
+ // https://bugs.webkit.org/show_bug.cgi?id=149078. Remove it, when that
+ // bug is fixed.
+ [markerWKWebView evaluateJavaScript:@""
+ completionHandler:^(id, NSError*) {
+ removeFromWKWebsiteDataStore();
+ }];
+ } else {
+ removeFromWKWebsiteDataStore();
+ }
+ }
+
+ // This is to ensure that the caller of this API still gets a callback even
+ // when none of the masks matched.
+ callbackCounter->IncrementCount();
+ dispatch_async(dispatch_get_main_queue(), decrementCallbackCounterCount);
+}
+
+- (void)removeIOSSpecificPersistentIncognitoDataFromBrowserState:
+ (ios::ChromeBrowserState*)browserState
+ mask:(int)mask {
+ DCHECK(browserState && browserState->IsOffTheRecord());
+ // Note: Before adding any method below, make sure that it can finish clearing
+ // browsing data even when |browserState| is destroyed after this method call.
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_HISTORY) {
+ session_util::DeleteLastSession(browserState);
+ }
+
+ // Cookies and server bound certificates should have the same lifetime.
+ DCHECK_EQ((mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) != 0,
+ (mask & IOSChromeBrowsingDataRemover::REMOVE_CHANNEL_IDS) != 0);
+ if (mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) {
+ scoped_refptr<net::URLRequestContextGetter> contextGetter =
+ browserState->GetRequestContext();
+ base::Closure callback = base::BindBlock(^{
+ });
+ web::WebThread::PostTask(
+ web::WebThread::IO, FROM_HERE, base::BindBlock(^{
+ net::URLRequestContext* requestContext =
+ contextGetter->GetURLRequestContext();
+ net::ChannelIDService* channelIdService =
+ requestContext->channel_id_service();
+ DCHECK(channelIdService);
+ DCHECK(channelIdService->GetChannelIDStore());
+ channelIdService->GetChannelIDStore()->DeleteAll(callback);
+ DCHECK(requestContext->cookie_store());
+ requestContext->cookie_store()->DeleteAllCreatedBetweenAsync(
+ base::Time(), base::Time(), base::Bind(&DoNothing));
+ }));
+ }
+}
+
+- (void)incrementPendingRemovalCountForBrowserState:
+ (ios::ChromeBrowserState*)browserState {
+ ++_pendingRemovalCount[browserState];
+}
+
+- (void)decrementPendingRemovalCountForBrowserState:
+ (ios::ChromeBrowserState*)browserState {
+ if (_pendingRemovalCount.find(browserState) != _pendingRemovalCount.end()) {
+ --_pendingRemovalCount[browserState];
+ if (!_pendingRemovalCount[browserState]) {
+ _pendingRemovalCount.erase(browserState);
+ }
+ }
+}
+
+- (BOOL)hasPendingRemovalOperations:(ios::ChromeBrowserState*)browserState {
+ return _pendingRemovalCount[browserState] != 0;
+}
+
+- (void)browserStateDestroyed:(ios::ChromeBrowserState*)browserState {
+ _pendingRemovalCount.erase(browserState);
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698