Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / ios / web / crw_browsing_data_store.mm
blob8a96d4a64aa1d1a81332102999d0750bdbc99e2e
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.
5 #import "ios/web/public/crw_browsing_data_store.h"
7 #import <Foundation/Foundation.h>
9 #import "base/ios/weak_nsobject.h"
10 #include "base/logging.h"
11 #import "base/mac/scoped_nsobject.h"
12 #import "ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.h"
13 #include "ios/web/public/active_state_manager.h"
14 #include "ios/web/public/browser_state.h"
16 namespace web {
17 NSString* const kBrowsingDataTypeCookies = @"kBrowsingDataTypeCookies";
18 }  // namespace web
20 namespace {
21 // Represents the type of operations that a CRWBrowsingDataStore can perform.
22 enum OperationType {
23   STASH = 0,
24   RESTORE,
25   REMOVE
27 }  // namespace
29 @interface CRWBrowsingDataStore ()
30 // Returns a serial queue on which stash and restore operations can be scheduled
31 // to be run. All stash/restore operations need to be run on the same queue
32 // hence it is shared with all CRWBrowsingDataStores.
33 + (NSOperationQueue*)operationQueueForStashAndRestoreOperations;
34 // Returns a concurrent queue on which remove operations can be scheduled to be
35 // run. All remove operations need to be run on the same queue hence it is
36 // shared with all CRWBrowsingDataStores.
37 + (NSOperationQueue*)operationQueueForRemoveOperations;
39 // The array of all browsing data managers. Must be accessed from the main
40 // thread.
41 @property(nonatomic, readonly) NSArray* allBrowsingDataManagers;
42 // Returns the |CRWBrowsingDataManager| that manages the browsing data for
43 // |browsingDataType|.
44 - (id<CRWBrowsingDataManager>)browsingDataManagerForBrowsingDataType:
45         (NSString*)browsingDataType;
46 // Returns an array of browsing data managers for all the |browsingDataType|.
47 - (NSArray*)browsingDataManagersForBrowsingDataTypes:(NSSet*)browsingDataTypes;
49 // Redefined to be read-write. Must be called from the main thread.
50 @property(nonatomic, assign) CRWBrowsingDataStoreMode mode;
51 // Sets the mode iff there are no more stash or restore operations that are
52 // still pending. |mode| can only be either |ACTIVE| or |INACTIVE|.
53 - (void)setModeIfNotStashingOrRestoring:(CRWBrowsingDataStoreMode)mode;
55 // Performs operations of type |operationType| on each of the
56 // |browsingDataManagers|.
57 // The kind of operations are:
58 // 1) STASH: Stash operation involves stashing browsing data that web views
59 // (UIWebViews and WKWebViews) create to the associated BrowserState's state
60 // path.
61 // 2) RESTORE: Restore operation involves restoring browsing data from the
62 // associated BrowserState's state path so that web views (UIWebViews and
63 // WKWebViews) can read from them.
64 // 3) REMOVE: Remove operation involves removing the data that web views
65 // (UIWebViews and WKWebViews) create.
66 // Precondition: There must be no web views associated with the BrowserState.
67 // |completionHandler| is called on the main thread and cannot be nil.
68 - (void)performOperationWithType:(OperationType)operationType
69             browsingDataManagers:(NSArray*)browsingDataManagers
70                completionHandler:(ProceduralBlock)completionHandler;
72 // Creates an NSOperation that calls |selector| on all the
73 // |browsingDataManagers|. |selector| needs to be one of the methods in
74 // CRWBrowsingDataManager. The created NSOperation will have a completionBlock
75 // of |completionHandler|.
76 - (NSOperation*)
77     newOperationWithBrowsingDataManagers:(NSArray*)browsingDataManagers
78                                 selector:(SEL)selector
79                        completionHandler:(ProceduralBlock)completionHandler;
80 // Enqueues |operation| to be run on |queue|. All operations are serialized to
81 // be run one after another.
82 - (void)addOperation:(NSOperation*)operation toQueue:(NSOperationQueue*)queue;
83 @end
85 @implementation CRWBrowsingDataStore {
86   web::BrowserState* _browserState;  // Weak, owns this object.
87   // The mode of the CRWBrowsingDataStore.
88   CRWBrowsingDataStoreMode _mode;
89   // The dictionary that maps a browsing data type to its
90   // CRWBrowsingDataManager.
91   base::scoped_nsobject<NSDictionary> _browsingDataTypeMap;
92   // The last operation that was enqueued to be run. Can be stash, restore or a
93   // delete operation.
94   base::scoped_nsobject<NSOperation> _lastDispatchedOperation;
95   // The last stash or restore operations that was dispatched to be run.
96   base::scoped_nsobject<NSOperation> _lastDispatchedStashOrRestoreOperation;
99 + (NSOperationQueue*)operationQueueForStashAndRestoreOperations {
100   static dispatch_once_t onceToken = 0;
101   static NSOperationQueue* operationQueueForStashAndRestoreOperations = nil;
102   dispatch_once(&onceToken, ^{
103     operationQueueForStashAndRestoreOperations =
104         [[NSOperationQueue alloc] init];
105     [operationQueueForStashAndRestoreOperations
106         setMaxConcurrentOperationCount:1U];
107     [operationQueueForStashAndRestoreOperations
108         setQualityOfService:NSQualityOfServiceUserInteractive];
109   });
110   return operationQueueForStashAndRestoreOperations;
113 + (NSOperationQueue*)operationQueueForRemoveOperations {
114   static dispatch_once_t onceToken = 0;
115   static NSOperationQueue* operationQueueForRemoveOperations = nil;
116   dispatch_once(&onceToken, ^{
117     operationQueueForRemoveOperations = [[NSOperationQueue alloc] init];
118     [operationQueueForRemoveOperations
119         setMaxConcurrentOperationCount:NSUIntegerMax];
120     [operationQueueForRemoveOperations
121         setQualityOfService:NSQualityOfServiceUserInitiated];
122   });
123   return operationQueueForRemoveOperations;
126 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState {
127   self = [super init];
128   if (self) {
129     DCHECK(web::BrowserState::GetActiveStateManager(browserState)->IsActive());
130     DCHECK([NSThread isMainThread]);
131     // TODO(shreyasv): Instantiate the necessary CRWBrowsingDataManagers that
132     // are encapsulated within this class. crbug.com/480654.
133     _browserState = browserState;
134     _mode = ACTIVE;
135     // TODO(shreyasv): If the creation of CRWBrowsingDataManagers turns out to
136     // be an expensive operations re-visit this with a lazy-evaluation approach.
137     base::scoped_nsobject<CRWCookieBrowsingDataManager>
138         cookieBrowsingDataManager([[CRWCookieBrowsingDataManager alloc]
139             initWithBrowserState:browserState]);
140     _browsingDataTypeMap.reset([@{
141       web::kBrowsingDataTypeCookies : cookieBrowsingDataManager,
142     } retain]);
143   }
144   return self;
147 - (NSString*)description {
148   NSString* format = @"<%@: %p; hasPendingOperations = { %@ }>";
149   NSString* hasPendingOperationsString =
150       [self hasPendingOperations] ? @"YES" : @"NO";
151   NSString* result =
152       [NSString stringWithFormat:format, NSStringFromClass(self.class), self,
153                                  hasPendingOperationsString];
154   return result;
157 + (NSSet*)allBrowsingDataTypes {
158   return [[[NSSet alloc]
159       initWithObjects:web::kBrowsingDataTypeCookies, nil] autorelease];
162 - (NSArray*)allBrowsingDataManagers {
163   DCHECK([NSThread isMainThread]);
164   return [_browsingDataTypeMap allValues];
167 - (id<CRWBrowsingDataManager>)browsingDataManagerForBrowsingDataType:
168         (NSString*)browsingDataType {
169   return [_browsingDataTypeMap objectForKey:browsingDataType];
172 - (NSArray*)browsingDataManagersForBrowsingDataTypes:(NSSet*)browsingDataTypes {
173   return [_browsingDataTypeMap objectsForKeys:[browsingDataTypes allObjects]
174                                notFoundMarker:[NSNull null]];
177 - (CRWBrowsingDataStoreMode)mode {
178   DCHECK([NSThread isMainThread]);
179   return _mode;
182 - (void)setMode:(CRWBrowsingDataStoreMode)mode {
183   DCHECK([NSThread isMainThread]);
184   _mode = mode;
187 - (void)setModeIfNotStashingOrRestoring:(CRWBrowsingDataStoreMode)mode {
188   DCHECK([NSThread isMainThread]);
189   DCHECK_NE(SYNCHRONIZING, mode);
190   if ([_lastDispatchedStashOrRestoreOperation isFinished]) {
191     _mode = mode;
192   }
195 - (void)makeActiveWithCompletionHandler:(ProceduralBlock)completionHandler {
196   DCHECK([NSThread isMainThread]);
198   base::WeakNSObject<CRWBrowsingDataStore> weakSelf(self);
199   [self performOperationWithType:RESTORE
200             browsingDataManagers:[self allBrowsingDataManagers]
201                completionHandler:^{
202                  [weakSelf setModeIfNotStashingOrRestoring:ACTIVE];
203                  if (completionHandler) {
204                    completionHandler();
205                  }
206                }];
209 - (void)makeInactiveWithCompletionHandler:(ProceduralBlock)completionHandler {
210   DCHECK([NSThread isMainThread]);
212   base::WeakNSObject<CRWBrowsingDataStore> weakSelf(self);
213   [self performOperationWithType:STASH
214             browsingDataManagers:[self allBrowsingDataManagers]
215                completionHandler:^{
216                  [weakSelf setModeIfNotStashingOrRestoring:INACTIVE];
217                  if (completionHandler) {
218                    completionHandler();
219                  }
220                }];
223 - (void)removeDataOfTypes:(NSSet*)browsingDataTypes
224         completionHandler:(ProceduralBlock)completionHandler {
225   DCHECK([NSThread isMainThread]);
227   NSArray* browsingDataManagers =
228       [self browsingDataManagersForBrowsingDataTypes:browsingDataTypes];
229   [self performOperationWithType:REMOVE
230             browsingDataManagers:browsingDataManagers
231                completionHandler:^{
232                  // Since this may be called on a background thread, bounce to
233                  // the main thread.
234                  dispatch_async(dispatch_get_main_queue(), completionHandler);
235                }];
238 - (BOOL)hasPendingOperations {
239   if (!_lastDispatchedOperation) {
240     return NO;
241   }
242   return ![_lastDispatchedOperation isFinished];
245 - (void)performOperationWithType:(OperationType)operationType
246             browsingDataManagers:(NSArray*)browsingDataManagers
247                completionHandler:(ProceduralBlock)completionHandler {
248   DCHECK([NSThread isMainThread]);
249   DCHECK(completionHandler);
251   SEL selector = nullptr;
252   switch (operationType) {
253     case STASH:
254       selector = @selector(stashData);
255       break;
256     case RESTORE:
257       selector = @selector(restoreData);
258       break;
259     case REMOVE:
260       selector = @selector(removeData);
261       break;
262     default:
263       NOTREACHED();
264       break;
265   };
267   id callCompletionHandlerOnMainThread = ^{
268     // This can be called on a background thread, hence the need to bounce to
269     // the main thread.
270     dispatch_async(dispatch_get_main_queue(), ^{
271       completionHandler();
272     });
273   };
274   base::scoped_nsobject<NSOperation> operation([self
275       newOperationWithBrowsingDataManagers:browsingDataManagers
276                                   selector:selector
277                          completionHandler:callCompletionHandlerOnMainThread]);
279   if (operationType == RESTORE || operationType == STASH) {
280     _mode = SYNCHRONIZING;
281     _lastDispatchedStashOrRestoreOperation.reset([operation retain]);
282   }
284   NSOperationQueue* queue = nil;
285   switch (operationType) {
286     case STASH:
287     case RESTORE:
288       queue = [CRWBrowsingDataStore operationQueueForStashAndRestoreOperations];
289       break;
290     case REMOVE:
291       queue = [CRWBrowsingDataStore operationQueueForRemoveOperations];
292       break;
293     default:
294       NOTREACHED();
295       break;
296   }
298   [self addOperation:operation toQueue:queue];
301 - (NSOperation*)
302     newOperationWithBrowsingDataManagers:(NSArray*)browsingDataManagers
303                                 selector:(SEL)selector
304                        completionHandler:(ProceduralBlock)completionHandler {
305   NSBlockOperation* operation = [[NSBlockOperation alloc] init];
306   for (id<CRWBrowsingDataManager> manager : browsingDataManagers) {
307     // |addExecutionBlock| farms out the different blocks added to it. hence the
308     // operations are implicitly parallelized.
309     [operation addExecutionBlock:^{
310       [manager performSelector:selector];
311     }];
312   }
313   [operation setCompletionBlock:completionHandler];
314   return operation;
317 - (void)addOperation:(NSOperation*)operation toQueue:(NSOperationQueue*)queue {
318   DCHECK([NSThread isMainThread]);
319   DCHECK(operation);
320   DCHECK(queue);
322   if (_lastDispatchedOperation) {
323     [operation addDependency:_lastDispatchedOperation];
324   }
325   _lastDispatchedOperation.reset([operation retain]);
326   [queue addOperation:operation];
329 @end