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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/browsing_data/browsing_data_removal_controller.h"
6
7 #import <WebKit/WebKit.h>
8
9 #include <memory>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/containers/hash_tables.h"
14 #import "base/ios/weak_nsobject.h"
15 #include "base/logging.h"
16 #import "base/mac/bind_objc_block.h"
17 #include "base/memory/ref_counted.h"
18 #include "components/open_from_clipboard/clipboard_recent_content.h"
19 #include "components/signin/ios/browser/account_consistency_service.h"
20 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
21 #include "ios/chrome/browser/browsing_data/browsing_data_remover_helper.h"
22 #include "ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.h"
23 #include "ios/chrome/browser/callback_counter.h"
24 #include "ios/chrome/browser/sessions/session_util.h"
25 #include "ios/chrome/browser/signin/account_consistency_service_factory.h"
26 #import "ios/chrome/browser/snapshots/snapshots_util.h"
27 #import "ios/chrome/browser/ui/browser_view_controller.h"
28 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
29 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_metad ata.h"
30 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_white list_manager.h"
31 #include "ios/web/public/web_thread.h"
32 #import "ios/web/public/web_view_creation_util.h"
33 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
34 #include "net/cookies/cookie_store.h"
35 #include "net/ssl/channel_id_service.h"
36 #include "net/ssl/channel_id_store.h"
37 #include "net/url_request/url_request_context.h"
38 #include "net/url_request/url_request_context_getter.h"
39
40 namespace {
41 // Empty callback used by DeleteAllCreatedBetweenAsync below.
42 void DoNothing(int n) {}
43 }
44
45 @interface BrowsingDataRemovalController ()
46 // Removes data used by the Google App Launcher.
47 - (void)removeGALData;
48 // Removes browsing data that is created by web views associated with
49 // |browserState|. |mask| is obtained from
50 // IOSChromeBrowsingDataRemover::RemoveDataMask. |deleteBegin| defines the begin
51 // time from which the data has to be removed, up to the present time.
52 // |completionHandler| is called when this operation finishes. This method
53 // finishes removal of the browsing data even if |browserState| is destroyed
54 // after this method call.
55 - (void)removeWebViewCreatedBrowsingDataFromBrowserState:
56 (ios::ChromeBrowserState*)browserState
57 mask:(int)mask
58 deleteBegin:(base::Time)deleteBegin
59 completionHandler:
60 (ProceduralBlock)completionHandler;
61 // Removes browsing data that is created by WKWebViews associated with
62 // |browserState|. |browserState| must not be off the record. |mask| is obtained
63 // from IOSChromeBrowsingDataRemover::RemoveDataMask. |deleteBegin| defines the
64 // begin time from which the data has to be removed, up to the present time.
65 // |completionHandler| is called when this operation finishes. This method
66 // finishes removal of the browsing data even if |browserState| is destroyed
67 // after this method call.
68 // Note: This method works only on iOS9+.
69 - (void)removeWKWebViewCreatedBrowsingDataFromBrowserState:
70 (ios::ChromeBrowserState*)browserState
71 mask:(int)mask
72 deleteBegin:
73 (base::Time)deleteBegin
74 completionHandler:
75 (ProceduralBlock)completionHandler;
76
77 // Removes browsing data associated with |browserState| that is specific to iOS
78 // and not removed when the |browserState| is destroyed.
79 // |mask| is obtained from IOSChromeBrowsingDataRemover::RemoveDataMask
80 // |deleteBegin| defines the begin time from which the data has to be removed.
81 // |browserState| cannot be null. |completionHandler| is called when
82 // this operation finishes. This method finishes removal of the browsing data
83 // even if |browserState| is destroyed after this method call.
84 - (void)removeIOSSpecificBrowsingDataFromBrowserState:
85 (ios::ChromeBrowserState*)browserState
86 mask:(int)mask
87 deleteBegin:(base::Time)deleteBegin
88 completionHandler:
89 (ProceduralBlock)completionHandler;
90 // Removes browsing data from |browserState| that is persisted on disk.
91 // |mask| is obtained from IOSChromeBrowsingDataRemover::RemoveDataMask.
92 // |browserState| cannot be null and must be off the record.
93 // This method finishes removal of the browsing data even if |browserState| is
94 // destroyed after this method call.
95 - (void)removeIOSSpecificPersistentIncognitoDataFromBrowserState:
96 (ios::ChromeBrowserState*)browserState
97 mask:(int)mask;
98
99 // Increments the count of pending removal operations for |browserState|.
100 // Called when any removal operation for |browserState| starts.
101 - (void)incrementPendingRemovalCountForBrowserState:
102 (ios::ChromeBrowserState*)browserState;
103 // Decrements the count of pending removal operations for |browserState|.
104 // Called when a removal operation for |browserState| finishes.
105 - (void)decrementPendingRemovalCountForBrowserState:
106 (ios::ChromeBrowserState*)browserState;
107 @end
108
109 @implementation BrowsingDataRemovalController {
110 // Wrapper around IOSChromeBrowsingDataRemover that serializes removal
111 // operations.
112 std::unique_ptr<BrowsingDataRemoverHelper> _browsingDataRemoverHelper;
113 // The delegate.
114 base::WeakNSProtocol<id<BrowsingDataRemovalControllerDelegate>> _delegate;
115 // A map that tracks the number of pending removals for a given
116 // ChromeBrowserState.
117 base::hash_map<ios::ChromeBrowserState*, int> _pendingRemovalCount;
118 }
119
120 - (instancetype)initWithDelegate:
121 (id<BrowsingDataRemovalControllerDelegate>)delegate {
122 if ((self = [super init])) {
123 DCHECK(delegate);
124 _browsingDataRemoverHelper.reset(new BrowsingDataRemoverHelper());
125 _delegate.reset(delegate);
126 }
127 return self;
128 }
129
130 - (instancetype)init {
131 NOTREACHED();
132 return nil;
133 }
134
135 - (void)removeBrowsingDataFromBrowserState:
136 (ios::ChromeBrowserState*)browserState
137 mask:(int)mask
138 timePeriod:(browsing_data::TimePeriod)timePeriod
139 completionHandler:(ProceduralBlock)completionHandler {
140 DCHECK(browserState);
141 DLOG_IF(WARNING, !mask) << "Nothing to remove!";
142 // Cookies and server bound certificates should have the same lifetime.
143 DCHECK_EQ((mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) != 0,
144 (mask & IOSChromeBrowsingDataRemover::REMOVE_CHANNEL_IDS) != 0);
145
146 [self incrementPendingRemovalCountForBrowserState:browserState];
147
148 ProceduralBlock browsingDataCleared = ^{
149 [self decrementPendingRemovalCountForBrowserState:browserState];
150 if (AccountConsistencyService* accountConsistencyService =
151 ios::AccountConsistencyServiceFactory::GetForBrowserState(
152 browserState)) {
153 accountConsistencyService->OnBrowsingDataRemoved();
154 }
155 if (completionHandler) {
156 completionHandler();
157 }
158 };
159
160 scoped_refptr<CallbackCounter> callbackCounter =
161 new CallbackCounter(base::BindBlock(browsingDataCleared));
162 ProceduralBlock decrementCallbackCounterCount = ^{
163 callbackCounter->DecrementCount();
164 };
165
166 callbackCounter->IncrementCount();
167 base::Time beginDeleteTime =
168 browsing_data::CalculateBeginDeleteTime(timePeriod);
169 [self removeIOSSpecificBrowsingDataFromBrowserState:browserState
170 mask:mask
171 deleteBegin:beginDeleteTime
172 completionHandler:
173 decrementCallbackCounterCount];
174
175 if (mask & IOSChromeBrowsingDataRemover::REMOVE_DOWNLOADS) {
176 DCHECK_EQ(browsing_data::ALL_TIME, timePeriod)
177 << "Partial clearing not supported";
178 callbackCounter->IncrementCount();
179 [_delegate
180 removeExternalFilesForBrowserState:browserState
181 completionHandler:decrementCallbackCounterCount];
182 }
183
184 if (!browserState->IsOffTheRecord()) {
185 callbackCounter->IncrementCount();
186 _browsingDataRemoverHelper->Remove(browserState, mask, timePeriod,
187 base::BindBlock(^{
188 callbackCounter->DecrementCount();
189 }));
190 }
191 }
192
193 - (void)removeIOSSpecificIncognitoBrowsingDataFromBrowserState:
194 (ios::ChromeBrowserState*)browserState
195 mask:(int)mask
196 completionHandler:
197 (ProceduralBlock)
198 completionHandler {
199 DCHECK(browserState && browserState->IsOffTheRecord());
200 [self removeIOSSpecificBrowsingDataFromBrowserState:browserState
201 mask:mask
202 deleteBegin:base::Time()
203 completionHandler:completionHandler];
204 }
205
206 - (void)removeIOSSpecificBrowsingDataFromBrowserState:
207 (ios::ChromeBrowserState*)browserState
208 mask:(int)mask
209 deleteBegin:(base::Time)deleteBegin
210 completionHandler:
211 (ProceduralBlock)completionHandler {
212 DCHECK(browserState);
213 [self incrementPendingRemovalCountForBrowserState:browserState];
214
215 ProceduralBlock browsingDataCleared = ^{
216 [self decrementPendingRemovalCountForBrowserState:browserState];
217 if (completionHandler) {
218 completionHandler();
219 }
220 };
221
222 // Note: Before adding any method below, make sure that it can finish clearing
223 // browsing data even when |browserState| is destroyed after this method call.
224
225 // If deleting history, clear visited links.
226 if (mask & IOSChromeBrowsingDataRemover::REMOVE_HISTORY) {
227 if (!browserState->IsOffTheRecord()) {
228 ClipboardRecentContent::GetInstance()->SuppressClipboardContent();
229 session_util::DeleteLastSession(browserState);
230 }
231 // Remove the screenshots taken by the system when backgrounding the
232 // application. Partial removal based on timePeriod is not required.
233 ClearIOSSnapshots();
234 }
235
236 // TODO(crbug.com/227636): Support multiple profile.
237 // Google App Launcher data is tied to the normal profile.
238 if (mask & IOSChromeBrowsingDataRemover::REMOVE_GOOGLE_APP_LAUNCHER_DATA &&
239 !browserState->IsOffTheRecord()) {
240 [self removeGALData];
241 }
242
243 if (browserState->IsOffTheRecord()) {
244 // In incognito, only data removal for all time is currently supported.
245 DCHECK_EQ(base::Time(), deleteBegin);
246 [self removeIOSSpecificPersistentIncognitoDataFromBrowserState:browserState
247 mask:mask];
248 }
249
250 [self removeWebViewCreatedBrowsingDataFromBrowserState:browserState
251 mask:mask
252 deleteBegin:deleteBegin
253 completionHandler:browsingDataCleared];
254 }
255
256 - (void)removeGALData {
257 [ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()
258 filteredAppsUsingBlock:^BOOL(const id<NativeAppMetadata> app,
259 BOOL* stop) {
260 [app resetInfobarHistory];
261 return NO;
262 }];
263 }
264
265 - (void)removeWebViewCreatedBrowsingDataFromBrowserState:
266 (ios::ChromeBrowserState*)browserState
267 mask:(int)mask
268 deleteBegin:(base::Time)deleteBegin
269 completionHandler:
270 (ProceduralBlock)completionHandler {
271 // TODO(crbug.com/480654): Remove this check once browsing data partitioning
272 // between BrowserStates is achieved.
273 if (browserState->IsOffTheRecord()) {
274 if (completionHandler) {
275 dispatch_async(dispatch_get_main_queue(), completionHandler);
276 }
277 return;
278 }
279 scoped_refptr<CallbackCounter> callbackCounter =
280 new CallbackCounter(base::BindBlock(completionHandler ? completionHandler
281 : ^{
282 }));
283
284 // Note: Before adding any method below, make sure that it can finish clearing
285 // browsing data even when |browserState| is destroyed after this method call.
286
287 callbackCounter->IncrementCount();
288 [self removeWKWebViewCreatedBrowsingDataFromBrowserState:browserState
289 mask:mask
290 deleteBegin:deleteBegin
291 completionHandler:^{
292 callbackCounter->DecrementCount();
293 }];
294 }
295
296 - (void)
297 removeWKWebViewCreatedBrowsingDataFromBrowserState:
298 (ios::ChromeBrowserState*)browserState
299 mask:(int)mask
300 deleteBegin:(base::Time)deleteBegin
301 completionHandler:
302 (ProceduralBlock)completionHandler {
303 scoped_refptr<CallbackCounter> callbackCounter =
304 new CallbackCounter(base::BindBlock(completionHandler ? completionHandler
305 : ^{
306 }));
307 ProceduralBlock decrementCallbackCounterCount = ^{
308 callbackCounter->DecrementCount();
309 };
310
311 // Converts browsing data types from
312 // IOSChromeBrowsingDataRemover::RemoveDataMask to
313 // WKWebsiteDataStore strings.
314 base::scoped_nsobject<NSMutableSet> dataTypesToRemove(
315 [[NSMutableSet alloc] init]);
316 if (mask & IOSChromeBrowsingDataRemover::REMOVE_CACHE_STORAGE) {
317 [dataTypesToRemove addObject:WKWebsiteDataTypeDiskCache];
318 [dataTypesToRemove addObject:WKWebsiteDataTypeMemoryCache];
319 }
320 if (mask & IOSChromeBrowsingDataRemover::REMOVE_APPCACHE) {
321 [dataTypesToRemove addObject:WKWebsiteDataTypeOfflineWebApplicationCache];
322 }
323 WKWebView* markerWKWebView = nil;
324 if (mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) {
325 // TODO(crbug.com/661630): This approach of creating a WKWebView to clear
326 // cookies is a workaround for
327 // https://bugs.webkit.org/show_bug.cgi?id=149078. Remove this, when that
328 // bug is fixed. Note: This WKWebView will be released when cookies have
329 // been cleared.
330 markerWKWebView = web::BuildWKWebView(CGRectZero, browserState);
331 [dataTypesToRemove addObject:WKWebsiteDataTypeCookies];
332 }
333 if (mask & IOSChromeBrowsingDataRemover::REMOVE_LOCAL_STORAGE) {
334 [dataTypesToRemove addObject:WKWebsiteDataTypeSessionStorage];
335 [dataTypesToRemove addObject:WKWebsiteDataTypeLocalStorage];
336 }
337 if (mask & IOSChromeBrowsingDataRemover::REMOVE_WEBSQL) {
338 [dataTypesToRemove addObject:WKWebsiteDataTypeWebSQLDatabases];
339 }
340 if (mask & IOSChromeBrowsingDataRemover::REMOVE_INDEXEDDB) {
341 [dataTypesToRemove addObject:WKWebsiteDataTypeIndexedDBDatabases];
342 }
343
344 ProceduralBlock afterRemovalFromWKWebsiteDataStore = ^{
345 if (mask & IOSChromeBrowsingDataRemover::REMOVE_VISITED_LINKS) {
346 // TODO(crbug.com/557963): Purging the WKProcessPool is a workaround for
347 // the fact that there is no public API to clear visited links in
348 // WKWebView. Remove this workaround if/when that API is made public.
349 // Note: Purging the WKProcessPool for clearing visisted links does have
350 // the side-effect of also losing the in-memory cookies of WKWebView but
351 // it is not a problem in practice since there is no UI to only have
352 // visited links be removed but not cookies.
353 DCHECK(mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES);
354 web::WKWebViewConfigurationProvider::FromBrowserState(browserState)
355 .Purge();
356 }
357
358 decrementCallbackCounterCount();
359 };
360
361 if ([dataTypesToRemove count]) {
362 callbackCounter->IncrementCount();
363 ProceduralBlock removeFromWKWebsiteDataStore = ^{
364 NSDate* beginDeleteDate =
365 [NSDate dateWithTimeIntervalSince1970:deleteBegin.ToDoubleT()];
366 [[WKWebsiteDataStore defaultDataStore]
367 removeDataOfTypes:dataTypesToRemove
368 modifiedSince:beginDeleteDate
369 completionHandler:afterRemovalFromWKWebsiteDataStore];
370 };
371
372 if (markerWKWebView) {
373 // TODO(crbug.com/661630): Executing JS enables the markerWKWebView to
374 // connect to the Networking process. This is so that the
375 // -[WKWebsiteDataStore removeDataOfTypes:] API is able to send an IPC
376 // message to the Networking process to clear cookies. This has been
377 // reverse-engineered by code inspection on the WebKit2 source code and is
378 // an undocumented workaround for
379 // https://bugs.webkit.org/show_bug.cgi?id=149078. Remove it, when that
380 // bug is fixed.
381 [markerWKWebView evaluateJavaScript:@""
382 completionHandler:^(id, NSError*) {
383 removeFromWKWebsiteDataStore();
384 }];
385 } else {
386 removeFromWKWebsiteDataStore();
387 }
388 }
389
390 // This is to ensure that the caller of this API still gets a callback even
391 // when none of the masks matched.
392 callbackCounter->IncrementCount();
393 dispatch_async(dispatch_get_main_queue(), decrementCallbackCounterCount);
394 }
395
396 - (void)removeIOSSpecificPersistentIncognitoDataFromBrowserState:
397 (ios::ChromeBrowserState*)browserState
398 mask:(int)mask {
399 DCHECK(browserState && browserState->IsOffTheRecord());
400 // Note: Before adding any method below, make sure that it can finish clearing
401 // browsing data even when |browserState| is destroyed after this method call.
402 if (mask & IOSChromeBrowsingDataRemover::REMOVE_HISTORY) {
403 session_util::DeleteLastSession(browserState);
404 }
405
406 // Cookies and server bound certificates should have the same lifetime.
407 DCHECK_EQ((mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) != 0,
408 (mask & IOSChromeBrowsingDataRemover::REMOVE_CHANNEL_IDS) != 0);
409 if (mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) {
410 scoped_refptr<net::URLRequestContextGetter> contextGetter =
411 browserState->GetRequestContext();
412 base::Closure callback = base::BindBlock(^{
413 });
414 web::WebThread::PostTask(
415 web::WebThread::IO, FROM_HERE, base::BindBlock(^{
416 net::URLRequestContext* requestContext =
417 contextGetter->GetURLRequestContext();
418 net::ChannelIDService* channelIdService =
419 requestContext->channel_id_service();
420 DCHECK(channelIdService);
421 DCHECK(channelIdService->GetChannelIDStore());
422 channelIdService->GetChannelIDStore()->DeleteAll(callback);
423 DCHECK(requestContext->cookie_store());
424 requestContext->cookie_store()->DeleteAllCreatedBetweenAsync(
425 base::Time(), base::Time(), base::Bind(&DoNothing));
426 }));
427 }
428 }
429
430 - (void)incrementPendingRemovalCountForBrowserState:
431 (ios::ChromeBrowserState*)browserState {
432 ++_pendingRemovalCount[browserState];
433 }
434
435 - (void)decrementPendingRemovalCountForBrowserState:
436 (ios::ChromeBrowserState*)browserState {
437 if (_pendingRemovalCount.find(browserState) != _pendingRemovalCount.end()) {
438 --_pendingRemovalCount[browserState];
439 if (!_pendingRemovalCount[browserState]) {
440 _pendingRemovalCount.erase(browserState);
441 }
442 }
443 }
444
445 - (BOOL)hasPendingRemovalOperations:(ios::ChromeBrowserState*)browserState {
446 return _pendingRemovalCount[browserState] != 0;
447 }
448
449 - (void)browserStateDestroyed:(ios::ChromeBrowserState*)browserState {
450 _pendingRemovalCount.erase(browserState);
451 }
452
453 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698