OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/web/public/crw_browsing_data_store.h" | 5 #import "ios/web/public/crw_browsing_data_store.h" |
6 | 6 |
7 #import <Foundation/Foundation.h> | 7 #import <Foundation/Foundation.h> |
8 | 8 |
9 #include "base/ios/ios_util.h" | 9 #include "base/ios/ios_util.h" |
10 #import "base/ios/weak_nsobject.h" | 10 #import "base/ios/weak_nsobject.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #import "base/mac/scoped_nsobject.h" | 12 #import "base/mac/scoped_nsobject.h" |
13 #import "ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.h" | 13 #import "ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.h" |
14 #include "ios/web/public/active_state_manager.h" | 14 #include "ios/web/public/active_state_manager.h" |
15 #include "ios/web/public/browser_state.h" | 15 #include "ios/web/public/browser_state.h" |
16 | 16 |
17 namespace { | 17 namespace { |
18 // Represents the type of operations that a CRWBrowsingDataStore can perform. | 18 // Represents the type of operations that a CRWBrowsingDataStore can perform. |
19 enum OperationType { | 19 enum OperationType { |
20 // Represents NOP. | 20 // Represents NOP. |
21 NONE = 1, | 21 NONE = 1, |
22 // Stash operation involves stashing browsing data that web views create to | 22 // Stash operation involves stashing browsing data that web views create to |
23 // the associated BrowserState's state path. | 23 // the associated BrowserState's state path. |
24 STASH, | 24 STASH, |
25 // Restore operation involves restoring browsing data from the | 25 // Restore operation involves restoring browsing data from the |
26 // associated BrowserState's state path so that web views (UIWebViews and | 26 // associated BrowserState's state path so that web views can read from them. |
27 // WKWebViews) can read from them. | |
28 RESTORE, | 27 RESTORE, |
29 // Remove operation involves removing the data that web views create. | 28 // Remove operation involves removing the data that web views create. |
30 REMOVE, | 29 REMOVE, |
31 }; | 30 }; |
32 | 31 |
33 // The name of the NSOperation that performs a restore operation. | 32 // The name of the NSOperation that performs a |RESTORE| operation. |
34 NSString* const kRestoreOperationName = @"CRWBrowsingDataStore.RESTORE"; | 33 NSString* const kRestoreOperationName = @"CRWBrowsingDataStore.RESTORE"; |
35 // The name of the NSOperation that performs a stash operation. | 34 // The name of the NSOperation that performs a |STASH| operation. |
36 NSString* const kStashOperationName = @"CRWBrowsingDataStore.STASH"; | 35 NSString* const kStashOperationName = @"CRWBrowsingDataStore.STASH"; |
37 } // namespace | 36 } // namespace |
38 | 37 |
38 // CRWBrowsingDataStore is implemented using 2 queues. | |
39 // 1) operationQueueForStashAndRestoreOperations: | |
40 // - This queue is used to perform |STASH| and |RESTORE| operations. | |
41 // - |STASH|, |RESTORE| operations are operations that have been explicitly | |
42 // requested by the user. And the performance of these operations block | |
43 // further user interaction. Hence this queue has a QoS of | |
44 // NSQualityOfServiceUserInitiated. | |
45 // - |STASH|, |RESTORE| operations from 2 different CRWBrowsingDataStores are | |
46 // not re-entrant. Hence this is a serial queue. | |
47 // 2) operationQueueForRemoveOperations: | |
48 // - This queue is used to perform |REMOVE| operations. | |
49 // - |REMOVE| operations is an operation that has been explicitly requested by | |
50 // the user. And the performance of this operation blocks further user | |
51 // interaction. Hence this queue has a QoS of NSQualityOfServiceUserInitiated. | |
52 // - |REMOVE| operations from 2 different CRWBrowingDataStores can be run in | |
53 // parallel. Hence this is a concurrent queue. | |
54 // | |
55 // |STASH|, |RESTORE|, |REMOVE| operations of a particular CRWBrowsingDataStore | |
56 // are not re-entrant. Hence these operations are serialized. | |
57 | |
39 @interface CRWBrowsingDataStore () | 58 @interface CRWBrowsingDataStore () |
40 // Returns a serial queue on which stash and restore operations can be scheduled | 59 // Redefined to be read-write. Must be called from the main thread. |
41 // to be run. All stash/restore operations need to be run on the same queue | 60 @property(nonatomic, assign) web::BrowsingDataStoreMode mode; |
42 // hence it is shared with all CRWBrowsingDataStores. | 61 // The array of all browsing data managers. Must be called from the main |
62 // thread. | |
63 @property(nonatomic, readonly) NSArray* allBrowsingDataManagers; | |
64 // The number of |STASH| or |RESTORE| operations that are still pending. Must be | |
65 // called from the main thread. | |
66 @property(nonatomic, assign) NSUInteger numberOfPendingStashOrRestoreOperations; | |
67 | |
68 // Returns a serial queue on which |STASH| and |RESTORE| operations can be | |
69 // scheduled to be run. All |STASH|/|RESTORE| operations need to be run on the | |
70 // same queue hence it is shared with all CRWBrowsingDataStores. | |
43 + (NSOperationQueue*)operationQueueForStashAndRestoreOperations; | 71 + (NSOperationQueue*)operationQueueForStashAndRestoreOperations; |
44 // Returns a concurrent queue on which remove operations can be scheduled to be | 72 // Returns a concurrent queue on which remove operations can be scheduled to be |
45 // run. All remove operations need to be run on the same queue hence it is | 73 // run. All |REMOVE| operations need to be run on the same queue hence it is |
46 // shared with all CRWBrowsingDataStores. | 74 // shared with all CRWBrowsingDataStores. |
47 + (NSOperationQueue*)operationQueueForRemoveOperations; | 75 + (NSOperationQueue*)operationQueueForRemoveOperations; |
48 - (instancetype)init NS_UNAVAILABLE; | |
49 | 76 |
50 // The array of all browsing data managers. Must be accessed from the main | 77 // Returns an array of CRWBrowsingDataManagers for the given |
51 // thread. | 78 // |browsingDataTypes|. |
52 @property(nonatomic, readonly) NSArray* allBrowsingDataManagers; | |
53 // Returns an array of browsing data managers for the given |browsingDataTypes|. | |
54 - (NSArray*)browsingDataManagersForBrowsingDataTypes: | 79 - (NSArray*)browsingDataManagersForBrowsingDataTypes: |
55 (web::BrowsingDataTypes)browsingDataTypes; | 80 (web::BrowsingDataTypes)browsingDataTypes; |
56 // Returns the selector that needs to be performed on the | 81 // Returns the selector that needs to be performed on the |
57 // CRWBrowsingDataManagers for the |operationType|. |operationType| cannot be | 82 // CRWBrowsingDataManagers for the |operationType|. |operationType| cannot be |
58 // |NONE|. | 83 // |NONE|. |
59 - (SEL)browsingDataManagerSelectorForOperationType:(OperationType)operationType; | 84 - (SEL)browsingDataManagerSelectorForOperationType:(OperationType)operationType; |
60 // Returns the selector that needs to be performed on the | 85 // Returns the selector that needs to be performed on the |
61 // CRWBrowsingDataManagers for a REMOVE operation. | 86 // CRWBrowsingDataManagers for a |REMOVE| operation. |
62 - (SEL)browsingDataManagerSelectorForRemoveOperationType; | 87 - (SEL)browsingDataManagerSelectorForRemoveOperationType; |
63 | 88 |
64 // Redefined to be read-write. Must be called from the main thread. | 89 // Sets the mode iff there are no more |STASH| or |RESTORE| operations that are |
65 @property(nonatomic, assign) web::BrowsingDataStoreMode mode; | |
66 // Sets the mode iff there are no more stash or restore operations that are | |
67 // still pending. |mode| can only be either |ACTIVE| or |INACTIVE|. | 90 // still pending. |mode| can only be either |ACTIVE| or |INACTIVE|. |
68 // |handler| is called immediately (in the same runloop) with a BOOL indicating | 91 // Returns YES if the mode was successfully changed to |mode|. |
69 // whether the mode change was successful or not. |handler| can be nil. | 92 - (BOOL)finalizeChangeToMode:(web::BrowsingDataStoreMode)mode; |
70 - (void)finalizeChangeToMode:(web::BrowsingDataStoreMode)mode | |
71 andCallCompletionHandler:(void (^)(BOOL modeChangeWasSuccessful))handler; | |
72 | |
73 // Changes the mode of the CRWBrowsingDataStore to |mode|. This is an | 93 // Changes the mode of the CRWBrowsingDataStore to |mode|. This is an |
74 // asynchronous operation and the mode is not changed immediately. | 94 // asynchronous operation and the mode is not changed immediately. |
75 // |completionHandler| can be nil. | 95 // |completionHandler| can be nil. |
76 // |completionHandler| is called on the main thread. This block has no return | 96 // |completionHandler| is called on the main thread. This block has no return |
77 // value and takes a single BOOL argument that indicates whether or not the | 97 // value and takes a single BOOL argument that indicates whether or not the |
78 // mode change was successfully changed to |mode|. | 98 // mode change was successfully changed to |mode|. |
79 - (void)changeMode:(web::BrowsingDataStoreMode)mode | 99 - (void)changeMode:(web::BrowsingDataStoreMode)mode |
80 completionHandler:(void (^)(BOOL modeChangeWasSuccessful))completionHandler; | 100 completionHandler:(void (^)(BOOL modeChangeWasSuccessful))completionHandler; |
81 | 101 |
82 // The number of stash or restore operations that are still pending. | 102 // Returns the OperationType (that needs to be performed) in order to change the |
83 @property(nonatomic, assign) NSUInteger numberOfPendingStashOrRestoreOperations; | 103 // mode to |mode|. Consults the delegate if one is present. |mode| cannot be |
84 | 104 // |CHANGING|. |
85 // Performs operations of type |operationType| on each of the | 105 - (OperationType)operationTypeToChangeMode:(web::BrowsingDataStoreMode)mode; |
106 // Performs an operation of type |operationType| on each of the | |
86 // |browsingDataManagers|. |operationType| cannot be |NONE|. | 107 // |browsingDataManagers|. |operationType| cannot be |NONE|. |
87 // Precondition: There must be no web views associated with the BrowserState. | 108 // Precondition: There must be no web views associated with the BrowserState. |
88 // |completionHandler| is called on the main thread and cannot be nil. | 109 // |completionHandler| is called on the main thread and cannot be nil. |
89 - (void)performOperationWithType:(OperationType)operationType | 110 - (void)performOperationWithType:(OperationType)operationType |
90 browsingDataManagers:(NSArray*)browsingDataManagers | 111 browsingDataManagers:(NSArray*)browsingDataManagers |
91 completionHandler:(ProceduralBlock)completionHandler; | 112 completionHandler:(ProceduralBlock)completionHandler; |
92 | 113 // Returns an NSOperation that calls |selector| on all the |
93 // Creates an NSOperation that calls |selector| on all the | |
94 // |browsingDataManagers|. |selector| needs to be one of the methods in | 114 // |browsingDataManagers|. |selector| needs to be one of the methods in |
95 // CRWBrowsingDataManager. | 115 // CRWBrowsingDataManager. |
96 - (NSOperation*) | 116 - (NSOperation*)operationWithBrowsingDataManagers:(NSArray*)browsingDataManagers |
97 newOperationWithBrowsingDataManagers:(NSArray*)browsingDataManagers | 117 selector:(SEL)selector; |
98 selector:(SEL)selector; | |
99 // Enqueues |operation| to be run on |queue|. All operations are serialized to | 118 // Enqueues |operation| to be run on |queue|. All operations are serialized to |
100 // be run one after another. | 119 // be run one after another. |
101 - (void)addOperation:(NSOperation*)operation toQueue:(NSOperationQueue*)queue; | 120 - (void)addOperation:(NSOperation*)operation toQueue:(NSOperationQueue*)queue; |
102 @end | 121 @end |
103 | 122 |
104 @implementation CRWBrowsingDataStore { | 123 @implementation CRWBrowsingDataStore { |
105 web::BrowserState* _browserState; // Weak, owns this object. | 124 web::BrowserState* _browserState; // Weak, owns this object. |
106 // The delegate. | 125 // The delegate. |
107 base::WeakNSProtocol<id<CRWBrowsingDataStoreDelegate>> _delegate; | 126 base::WeakNSProtocol<id<CRWBrowsingDataStoreDelegate>> _delegate; |
108 // The mode of the CRWBrowsingDataStore. | 127 // The mode of the CRWBrowsingDataStore. |
109 web::BrowsingDataStoreMode _mode; | 128 web::BrowsingDataStoreMode _mode; |
110 // The dictionary that maps a browsing data type to its | 129 // The dictionary that maps a browsing data type to its |
111 // CRWBrowsingDataManager. | 130 // CRWBrowsingDataManager. |
112 base::scoped_nsobject<NSDictionary> _browsingDataTypeMap; | 131 base::scoped_nsobject<NSDictionary> _browsingDataTypeMap; |
113 // The last operation that was enqueued to be run. Can be stash, restore or a | 132 // The last operation that was enqueued to be run. Can be a |STASH|, |RESTORE| |
114 // delete operation. | 133 // or a |REMOVE| operation. |
115 base::scoped_nsobject<NSOperation> _lastDispatchedOperation; | 134 base::scoped_nsobject<NSOperation> _lastDispatchedOperation; |
116 // The last dispatched stash or restore operation that was enqueued to be run. | 135 // The last dispatched |STASH| or |RESTORE| operation that was enqueued to be |
136 // run. | |
117 base::scoped_nsobject<NSOperation> _lastDispatchedStashOrRestoreOperation; | 137 base::scoped_nsobject<NSOperation> _lastDispatchedStashOrRestoreOperation; |
118 // The number of stash or restore operations that are still pending. If this | 138 // The number of |STASH| or |RESTORE| operations that are still pending. If |
119 // value > 0 the mode of the CRWBrowsingDataStore is |CHANGING|. The mode | 139 // the number of |STASH| or |RESTORE| operations is greater than 0U, the mode |
120 // can be made ACTIVE or INACTIVE only be set when this value is 0. | 140 // of the CRWBrowsingDataStore is |CHANGING|. The mode can be made ACTIVE or |
141 // INACTIVE only be set when this value is 0U. | |
121 NSUInteger _numberOfPendingStashOrRestoreOperations; | 142 NSUInteger _numberOfPendingStashOrRestoreOperations; |
122 } | 143 } |
123 | 144 |
124 + (NSOperationQueue*)operationQueueForStashAndRestoreOperations { | 145 #pragma mark - |
125 static dispatch_once_t onceToken = 0; | 146 #pragma mark NSObject Methods |
126 static NSOperationQueue* operationQueueForStashAndRestoreOperations = nil; | |
127 dispatch_once(&onceToken, ^{ | |
128 operationQueueForStashAndRestoreOperations = | |
129 [[NSOperationQueue alloc] init]; | |
130 [operationQueueForStashAndRestoreOperations | |
131 setMaxConcurrentOperationCount:1U]; | |
132 if (base::ios::IsRunningOnIOS8OrLater()) { | |
133 [operationQueueForStashAndRestoreOperations | |
134 setQualityOfService:NSQualityOfServiceUserInteractive]; | |
135 } | |
136 }); | |
137 return operationQueueForStashAndRestoreOperations; | |
138 } | |
139 | |
140 + (NSOperationQueue*)operationQueueForRemoveOperations { | |
141 static dispatch_once_t onceToken = 0; | |
142 static NSOperationQueue* operationQueueForRemoveOperations = nil; | |
143 dispatch_once(&onceToken, ^{ | |
144 operationQueueForRemoveOperations = [[NSOperationQueue alloc] init]; | |
145 [operationQueueForRemoveOperations | |
146 setMaxConcurrentOperationCount:NSUIntegerMax]; | |
147 if (base::ios::IsRunningOnIOS8OrLater()) { | |
148 [operationQueueForRemoveOperations | |
149 setQualityOfService:NSQualityOfServiceUserInitiated]; | |
150 } | |
151 }); | |
152 return operationQueueForRemoveOperations; | |
153 } | |
154 | 147 |
155 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState { | 148 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState { |
156 self = [super init]; | 149 self = [super init]; |
157 if (self) { | 150 if (self) { |
158 DCHECK([NSThread isMainThread]); | 151 DCHECK([NSThread isMainThread]); |
152 DCHECK(browserState); | |
159 // TODO(shreyasv): Instantiate the necessary CRWBrowsingDataManagers that | 153 // TODO(shreyasv): Instantiate the necessary CRWBrowsingDataManagers that |
160 // are encapsulated within this class. crbug.com/480654. | 154 // are encapsulated within this class. crbug.com/480654. |
161 _browserState = browserState; | 155 _browserState = browserState; |
162 web::ActiveStateManager* activeStateManager = | 156 web::ActiveStateManager* activeStateManager = |
163 web::BrowserState::GetActiveStateManager(browserState); | 157 web::BrowserState::GetActiveStateManager(browserState); |
164 DCHECK(activeStateManager); | 158 DCHECK(activeStateManager); |
165 _mode = activeStateManager->IsActive() ? web::ACTIVE : web::INACTIVE; | 159 _mode = activeStateManager->IsActive() ? web::ACTIVE : web::INACTIVE; |
166 // TODO(shreyasv): If the creation of CRWBrowsingDataManagers turns out to | 160 // TODO(shreyasv): If the creation of CRWBrowsingDataManagers turns out to |
167 // be an expensive operations re-visit this with a lazy-evaluation approach. | 161 // be an expensive operations re-visit this with a lazy-evaluation approach. |
168 base::scoped_nsobject<CRWCookieBrowsingDataManager> | 162 base::scoped_nsobject<CRWCookieBrowsingDataManager> |
169 cookieBrowsingDataManager([[CRWCookieBrowsingDataManager alloc] | 163 cookieBrowsingDataManager([[CRWCookieBrowsingDataManager alloc] |
170 initWithBrowserState:browserState]); | 164 initWithBrowserState:browserState]); |
171 _browsingDataTypeMap.reset([@{ | 165 _browsingDataTypeMap.reset([@{ |
172 @(web::BROWSING_DATA_TYPE_COOKIES) : cookieBrowsingDataManager, | 166 @(web::BROWSING_DATA_TYPE_COOKIES) : cookieBrowsingDataManager, |
173 } retain]); | 167 } retain]); |
174 } | 168 } |
175 return self; | 169 return self; |
176 } | 170 } |
177 | 171 |
178 - (instancetype)init { | 172 - (instancetype)init { |
Eugene But (OOO till 7-30)
2015/07/09 20:08:08
You don't need this since you marked it as NS_UNA
shreyasv1
2015/07/10 17:06:22
Removed here and in the unittest.
| |
179 NOTREACHED(); | 173 NOTREACHED(); |
180 return nil; | 174 return nil; |
181 } | 175 } |
182 | 176 |
183 - (NSString*)description { | 177 - (NSString*)description { |
184 NSString* format = @"<%@: %p; hasPendingOperations = { %@ }>"; | 178 NSString* format = @"<%@: %p; hasPendingOperations = { %@ }; mode = { %@ }>"; |
185 NSString* hasPendingOperationsString = | 179 NSString* hasPendingOperationsString = |
186 [self hasPendingOperations] ? @"YES" : @"NO"; | 180 [self hasPendingOperations] ? @"YES" : @"NO"; |
187 NSString* result = | 181 NSString* modeString = nil; |
188 [NSString stringWithFormat:format, NSStringFromClass(self.class), self, | 182 switch (self.mode) { |
189 hasPendingOperationsString]; | 183 case web::ACTIVE: |
184 modeString = @"ACTIVE"; | |
185 break; | |
186 case web::CHANGING: | |
187 modeString = @"CHANGING"; | |
188 break; | |
189 case web::INACTIVE: | |
190 modeString = @"INACTIVE"; | |
191 break; | |
192 } | |
193 NSString* result = [NSString stringWithFormat:format, | |
194 NSStringFromClass(self.class), self, hasPendingOperationsString, | |
195 modeString]; | |
190 return result; | 196 return result; |
191 } | 197 } |
192 | 198 |
199 + (BOOL)automaticallyNotifiesObserversForKey:(NSString*)key { | |
200 // It is necessary to override this for |mode| because the default KVO | |
201 // behavior in NSObject is to fire a notification irrespective of if an actual | |
202 // change was made to the ivar or not. The |mode| property needs fine grained | |
203 // control over the actual notifications being fired since observers need to | |
204 // be notified iff the |mode| actually changed. | |
205 if ([key isEqual:@"mode"]) { | |
206 return NO; | |
207 } | |
208 return [super automaticallyNotifiesObserversForKey:key]; | |
209 } | |
210 | |
211 #pragma mark - | |
212 #pragma mark Public Properties | |
213 | |
214 - (id<CRWBrowsingDataStoreDelegate>)delegate { | |
215 return _delegate; | |
216 } | |
217 | |
218 - (void)setDelegate:(id<CRWBrowsingDataStoreDelegate>)delegate { | |
219 _delegate.reset(delegate); | |
220 } | |
221 | |
222 - (web::BrowsingDataStoreMode)mode { | |
223 DCHECK([NSThread isMainThread]); | |
224 return _mode; | |
225 } | |
226 | |
227 - (BOOL)hasPendingOperations { | |
228 if (!_lastDispatchedOperation) { | |
229 return NO; | |
230 } | |
231 return ![_lastDispatchedOperation isFinished]; | |
232 } | |
233 | |
234 #pragma mark - | |
235 #pragma mark Public Methods | |
236 | |
237 - (void)makeActiveWithCompletionHandler: | |
238 (void (^)(BOOL success))completionHandler { | |
239 DCHECK([NSThread isMainThread]); | |
240 // TODO(shreyasv): Verify the preconditions for this method when | |
241 // web::WebViewCounter class is implemented. crbug.com/480507. | |
242 | |
243 [self changeMode:web::ACTIVE completionHandler:completionHandler]; | |
244 } | |
245 | |
246 - (void)makeInactiveWithCompletionHandler: | |
247 (void (^)(BOOL success))completionHandler { | |
248 DCHECK([NSThread isMainThread]); | |
249 // TODO(shreyasv): Verify the preconditions for this method when | |
250 // web::WebViewCounter class is implemented. crbug.com/480507. | |
251 | |
252 [self changeMode:web::INACTIVE completionHandler:completionHandler]; | |
253 } | |
254 | |
255 - (void)removeDataOfTypes:(web::BrowsingDataTypes)browsingDataTypes | |
256 completionHandler:(ProceduralBlock)completionHandler { | |
257 DCHECK([NSThread isMainThread]); | |
258 // TODO(shreyasv): Verify the preconditions for this method when | |
259 // web::WebViewCounter class is implemented. crbug.com/480507. | |
260 | |
261 NSArray* browsingDataManagers = | |
262 [self browsingDataManagersForBrowsingDataTypes:browsingDataTypes]; | |
263 [self performOperationWithType:REMOVE | |
264 browsingDataManagers:browsingDataManagers | |
265 completionHandler:completionHandler]; | |
266 } | |
267 | |
268 #pragma mark - | |
269 #pragma mark Private Properties | |
270 | |
271 - (void)setMode:(web::BrowsingDataStoreMode)mode { | |
272 DCHECK([NSThread isMainThread]); | |
273 | |
274 if (_mode == mode) { | |
275 return; | |
276 } | |
277 if (mode == web::ACTIVE || mode == web::INACTIVE) { | |
278 DCHECK(!self.numberOfPendingStashOrRestoreOperations); | |
279 } | |
280 [self willChangeValueForKey:@"mode"]; | |
281 _mode = mode; | |
282 [self didChangeValueForKey:@"mode"]; | |
283 } | |
193 | 284 |
194 - (NSArray*)allBrowsingDataManagers { | 285 - (NSArray*)allBrowsingDataManagers { |
195 DCHECK([NSThread isMainThread]); | 286 DCHECK([NSThread isMainThread]); |
196 return [_browsingDataTypeMap allValues]; | 287 return [_browsingDataTypeMap allValues]; |
197 } | 288 } |
198 | 289 |
290 - (NSUInteger)numberOfPendingStashOrRestoreOperations { | |
291 DCHECK([NSThread isMainThread]); | |
292 return _numberOfPendingStashOrRestoreOperations; | |
293 } | |
294 | |
295 - (void)setNumberOfPendingStashOrRestoreOperations: | |
296 (NSUInteger)numberOfPendingStashOrRestoreOperations { | |
297 DCHECK([NSThread isMainThread]); | |
298 _numberOfPendingStashOrRestoreOperations = | |
299 numberOfPendingStashOrRestoreOperations; | |
300 } | |
301 | |
302 #pragma mark - | |
303 #pragma mark Private Class Methods | |
304 | |
305 + (NSOperationQueue*)operationQueueForStashAndRestoreOperations { | |
306 static dispatch_once_t onceToken = 0; | |
307 static NSOperationQueue* operationQueueForStashAndRestoreOperations = nil; | |
308 dispatch_once(&onceToken, ^{ | |
309 operationQueueForStashAndRestoreOperations = | |
310 [[NSOperationQueue alloc] init]; | |
311 [operationQueueForStashAndRestoreOperations | |
312 setMaxConcurrentOperationCount:1U]; | |
313 if (base::ios::IsRunningOnIOS8OrLater()) { | |
314 [operationQueueForStashAndRestoreOperations | |
315 setQualityOfService:NSQualityOfServiceUserInitiated]; | |
316 } | |
317 }); | |
318 return operationQueueForStashAndRestoreOperations; | |
319 } | |
320 | |
321 + (NSOperationQueue*)operationQueueForRemoveOperations { | |
322 static dispatch_once_t onceToken = 0; | |
323 static NSOperationQueue* operationQueueForRemoveOperations = nil; | |
324 dispatch_once(&onceToken, ^{ | |
325 operationQueueForRemoveOperations = [[NSOperationQueue alloc] init]; | |
326 [operationQueueForRemoveOperations | |
327 setMaxConcurrentOperationCount:NSUIntegerMax]; | |
328 if (base::ios::IsRunningOnIOS8OrLater()) { | |
329 [operationQueueForRemoveOperations | |
330 setQualityOfService:NSQualityOfServiceUserInitiated]; | |
331 } | |
332 }); | |
333 return operationQueueForRemoveOperations; | |
334 } | |
335 | |
336 #pragma mark - | |
337 #pragma mark Private Methods | |
338 | |
199 - (NSArray*)browsingDataManagersForBrowsingDataTypes: | 339 - (NSArray*)browsingDataManagersForBrowsingDataTypes: |
200 (web::BrowsingDataTypes)browsingDataTypes { | 340 (web::BrowsingDataTypes)browsingDataTypes { |
201 __block NSMutableArray* result = [NSMutableArray array]; | 341 __block NSMutableArray* result = [NSMutableArray array]; |
202 [_browsingDataTypeMap | 342 [_browsingDataTypeMap |
203 enumerateKeysAndObjectsUsingBlock:^(NSNumber* dataType, | 343 enumerateKeysAndObjectsUsingBlock:^(NSNumber* dataType, |
204 id<CRWBrowsingDataManager> manager, | 344 id<CRWBrowsingDataManager> manager, |
205 BOOL*) { | 345 BOOL*) { |
206 if ([dataType unsignedIntegerValue] & browsingDataTypes) { | 346 if ([dataType unsignedIntegerValue] & browsingDataTypes) { |
207 [result addObject:manager]; | 347 [result addObject:manager]; |
208 } | 348 } |
209 }]; | 349 }]; |
210 return result; | 350 return result; |
211 } | 351 } |
212 | 352 |
213 - (id<CRWBrowsingDataStoreDelegate>)delegate { | |
214 return _delegate; | |
215 } | |
216 | |
217 - (void)setDelegate:(id<CRWBrowsingDataStoreDelegate>)delegate { | |
218 _delegate.reset(delegate); | |
219 } | |
220 | |
221 - (SEL)browsingDataManagerSelectorForOperationType: | 353 - (SEL)browsingDataManagerSelectorForOperationType: |
222 (OperationType)operationType { | 354 (OperationType)operationType { |
223 switch (operationType) { | 355 switch (operationType) { |
224 case NONE: | 356 case NONE: |
225 NOTREACHED(); | 357 NOTREACHED(); |
226 return nullptr; | 358 return nullptr; |
227 case STASH: | 359 case STASH: |
228 return @selector(stashData); | 360 return @selector(stashData); |
229 case RESTORE: | 361 case RESTORE: |
230 return @selector(restoreData); | 362 return @selector(restoreData); |
231 case REMOVE: | 363 case REMOVE: |
232 return [self browsingDataManagerSelectorForRemoveOperationType]; | 364 return [self browsingDataManagerSelectorForRemoveOperationType]; |
233 }; | 365 }; |
234 NOTREACHED(); | |
235 return nullptr; | |
236 } | 366 } |
237 | 367 |
238 - (SEL)browsingDataManagerSelectorForRemoveOperationType { | 368 - (SEL)browsingDataManagerSelectorForRemoveOperationType { |
239 if (self.mode == web::ACTIVE) { | 369 if (self.mode == web::ACTIVE) { |
240 return @selector(removeDataAtCanonicalPath); | 370 return @selector(removeDataAtCanonicalPath); |
241 } | 371 } |
242 if (self.mode == web::INACTIVE) { | 372 if (self.mode == web::INACTIVE) { |
243 return @selector(removeDataAtStashPath); | 373 return @selector(removeDataAtStashPath); |
244 } | 374 } |
375 // Since the mode is |CHANGING|, find the last |STASH| or |RESTORE| operation | |
376 // that was enqueued in order to find out the eventual mode that the | |
377 // CRWBrowsingDataStore will be in when this |REMOVE| operation is run. | |
245 DCHECK(_lastDispatchedStashOrRestoreOperation); | 378 DCHECK(_lastDispatchedStashOrRestoreOperation); |
246 NSString* lastDispatchedStashOrRestoreOperationName = | 379 NSString* lastDispatchedStashOrRestoreOperationName = |
247 [_lastDispatchedStashOrRestoreOperation name]; | 380 [_lastDispatchedStashOrRestoreOperation name]; |
248 if ([lastDispatchedStashOrRestoreOperationName | 381 if ([lastDispatchedStashOrRestoreOperationName |
249 isEqual:kRestoreOperationName]) { | 382 isEqual:kRestoreOperationName]) { |
250 return @selector(removeDataAtCanonicalPath); | 383 return @selector(removeDataAtCanonicalPath); |
251 } | 384 } |
252 if ([lastDispatchedStashOrRestoreOperationName isEqual:kStashOperationName]) { | 385 if ([lastDispatchedStashOrRestoreOperationName isEqual:kStashOperationName]) { |
253 return @selector(removeDataAtStashPath); | 386 return @selector(removeDataAtStashPath); |
254 } | 387 } |
255 NOTREACHED(); | 388 NOTREACHED(); |
256 return nullptr; | 389 return nullptr; |
257 } | 390 } |
258 | 391 |
259 + (BOOL)automaticallyNotifiesObserversForKey:(NSString*)key { | 392 - (BOOL)finalizeChangeToMode:(web::BrowsingDataStoreMode)mode { |
260 // It is necessary to override this for |mode| because the default KVO | |
261 // behavior in NSObject is to fire a notification irrespective of if an actual | |
262 // change was made to the ivar or not. The |mode| property needs fine grained | |
263 // control over the actual notifications being fired since observers need to | |
264 // be notified iff the |mode| actually changed. | |
265 if ([key isEqual:@"mode"]) { | |
266 return NO; | |
267 } | |
268 return [super automaticallyNotifiesObserversForKey:(NSString*)key]; | |
269 } | |
270 | |
271 - (web::BrowsingDataStoreMode)mode { | |
272 DCHECK([NSThread isMainThread]); | |
273 return _mode; | |
274 } | |
275 | |
276 - (void)setMode:(web::BrowsingDataStoreMode)mode { | |
277 DCHECK([NSThread isMainThread]); | |
278 if (_mode == mode) { | |
279 return; | |
280 } | |
281 if (mode == web::ACTIVE || mode == web::INACTIVE) { | |
282 DCHECK(!self.numberOfPendingStashOrRestoreOperations); | |
283 } | |
284 [self willChangeValueForKey:@"mode"]; | |
285 _mode = mode; | |
286 [self didChangeValueForKey:@"mode"]; | |
287 } | |
288 | |
289 - (void)finalizeChangeToMode:(web::BrowsingDataStoreMode)mode | |
290 andCallCompletionHandler:(void (^)(BOOL modeChangeWasSuccessful))handler { | |
291 DCHECK([NSThread isMainThread]); | 393 DCHECK([NSThread isMainThread]); |
292 DCHECK_NE(web::CHANGING, mode); | 394 DCHECK_NE(web::CHANGING, mode); |
293 | 395 |
294 BOOL modeChangeWasSuccessful = NO; | 396 BOOL modeChangeWasSuccessful = NO; |
295 if (!self.numberOfPendingStashOrRestoreOperations) { | 397 if (!self.numberOfPendingStashOrRestoreOperations) { |
296 [self setMode:mode]; | 398 [self setMode:mode]; |
297 modeChangeWasSuccessful = YES; | 399 modeChangeWasSuccessful = YES; |
298 } | 400 } |
299 if (handler) { | 401 return modeChangeWasSuccessful; |
300 handler(modeChangeWasSuccessful); | |
301 } | |
302 } | |
303 | |
304 - (NSUInteger)numberOfPendingStashOrRestoreOperations { | |
305 DCHECK([NSThread isMainThread]); | |
306 return _numberOfPendingStashOrRestoreOperations; | |
307 } | |
308 | |
309 - (void)setNumberOfPendingStashOrRestoreOperations: | |
310 (NSUInteger)numberOfPendingStashOrRestoreOperations { | |
311 DCHECK([NSThread isMainThread]); | |
312 _numberOfPendingStashOrRestoreOperations = | |
313 numberOfPendingStashOrRestoreOperations; | |
314 } | |
315 | |
316 - (void)makeActiveWithCompletionHandler: | |
317 (void (^)(BOOL success))completionHandler { | |
318 DCHECK([NSThread isMainThread]); | |
319 | |
320 [self changeMode:web::ACTIVE completionHandler:completionHandler]; | |
321 } | |
322 | |
323 - (void)makeInactiveWithCompletionHandler: | |
324 (void (^)(BOOL success))completionHandler { | |
325 DCHECK([NSThread isMainThread]); | |
326 | |
327 [self changeMode:web::INACTIVE completionHandler:completionHandler]; | |
328 } | 402 } |
329 | 403 |
330 - (void)changeMode:(web::BrowsingDataStoreMode)mode | 404 - (void)changeMode:(web::BrowsingDataStoreMode)mode |
331 completionHandler: | 405 completionHandler: |
332 (void (^)(BOOL modeChangeWasSuccessful))completionHandler { | 406 (void (^)(BOOL modeChangeWasSuccessful))completionHandler { |
333 DCHECK([NSThread isMainThread]); | 407 DCHECK([NSThread isMainThread]); |
334 | 408 |
335 ProceduralBlock completionHandlerAfterPerformingOperation = ^{ | 409 ProceduralBlock completionHandlerAfterPerformingOperation = ^{ |
336 [self finalizeChangeToMode:mode andCallCompletionHandler:completionHandler]; | 410 BOOL modeChangeWasSuccessful = [self finalizeChangeToMode:mode]; |
411 if (completionHandler) { | |
412 completionHandler(modeChangeWasSuccessful); | |
413 } | |
337 }; | 414 }; |
338 | 415 |
339 // Already in the desired mode. | 416 OperationType operationType = [self operationTypeToChangeMode:mode]; |
340 if (self.mode == mode) { | 417 if (operationType == NONE) { |
341 // As a caller of this API, it is awkward to get the callback before the | 418 // As a caller of this API, it is awkward to get the callback before the |
342 // method call has completed, hence defer it. | 419 // method call has completed, hence defer it. |
343 dispatch_async(dispatch_get_main_queue(), ^{ | 420 dispatch_async(dispatch_get_main_queue(), |
344 completionHandlerAfterPerformingOperation(); | 421 completionHandlerAfterPerformingOperation); |
345 }); | 422 } else { |
346 return; | 423 [self performOperationWithType:operationType |
424 browsingDataManagers:[self allBrowsingDataManagers] | |
425 completionHandler:completionHandlerAfterPerformingOperation]; | |
347 } | 426 } |
427 } | |
428 | |
429 - (OperationType)operationTypeToChangeMode:(web::BrowsingDataStoreMode)mode { | |
430 DCHECK_NE(web::CHANGING, mode); | |
348 | 431 |
349 OperationType operationType = NONE; | 432 OperationType operationType = NONE; |
350 if (mode == web::ACTIVE) { | 433 if (mode == self.mode) { |
434 // Already in the desired mode. | |
435 operationType = NONE; | |
436 } else if (mode == web::ACTIVE) { | |
351 // By default a |RESTORE| operation is performed when the mode is changed | 437 // By default a |RESTORE| operation is performed when the mode is changed |
352 // to |ACTIVE|. | 438 // to |ACTIVE|. |
353 operationType = RESTORE; | 439 operationType = RESTORE; |
354 web::BrowsingDataStoreMakeActivePolicy makeActivePolicy = | 440 web::BrowsingDataStoreMakeActivePolicy makeActivePolicy = |
355 [_delegate decideMakeActiveOperationPolicyForBrowsingDataStore:self]; | 441 [_delegate decideMakeActiveOperationPolicyForBrowsingDataStore:self]; |
356 operationType = (makeActivePolicy == web::ADOPT) ? REMOVE : RESTORE; | 442 operationType = (makeActivePolicy == web::ADOPT) ? REMOVE : RESTORE; |
357 } else { | 443 } else { |
358 // By default a |STASH| operation is performed when the mode is changed to | 444 // By default a |STASH| operation is performed when the mode is changed to |
359 // |INACTIVE|. | 445 // |INACTIVE|. |
360 operationType = STASH; | 446 operationType = STASH; |
361 web::BrowsingDataStoreMakeInactivePolicy makeInactivePolicy = | 447 web::BrowsingDataStoreMakeInactivePolicy makeInactivePolicy = |
362 [_delegate decideMakeInactiveOperationPolicyForBrowsingDataStore:self]; | 448 [_delegate decideMakeInactiveOperationPolicyForBrowsingDataStore:self]; |
363 operationType = (makeInactivePolicy == web::DELETE) ? REMOVE : STASH; | 449 operationType = (makeInactivePolicy == web::DELETE) ? REMOVE : STASH; |
364 } | 450 } |
365 DCHECK_NE(NONE, operationType); | 451 return operationType; |
366 [self performOperationWithType:operationType | |
367 browsingDataManagers:[self allBrowsingDataManagers] | |
368 completionHandler:completionHandlerAfterPerformingOperation]; | |
369 } | |
370 | |
371 - (void)removeDataOfTypes:(web::BrowsingDataTypes)browsingDataTypes | |
372 completionHandler:(ProceduralBlock)completionHandler { | |
373 DCHECK([NSThread isMainThread]); | |
374 | |
375 NSArray* browsingDataManagers = | |
376 [self browsingDataManagersForBrowsingDataTypes:browsingDataTypes]; | |
377 [self performOperationWithType:REMOVE | |
378 browsingDataManagers:browsingDataManagers | |
379 completionHandler:^{ | |
380 // Since this may be called on a background thread, bounce to | |
381 // the main thread. | |
382 dispatch_async(dispatch_get_main_queue(), completionHandler); | |
383 }]; | |
384 } | |
385 | |
386 - (BOOL)hasPendingOperations { | |
387 if (!_lastDispatchedOperation) { | |
388 return NO; | |
389 } | |
390 return ![_lastDispatchedOperation isFinished]; | |
391 } | 452 } |
392 | 453 |
393 - (void)performOperationWithType:(OperationType)operationType | 454 - (void)performOperationWithType:(OperationType)operationType |
394 browsingDataManagers:(NSArray*)browsingDataManagers | 455 browsingDataManagers:(NSArray*)browsingDataManagers |
395 completionHandler:(ProceduralBlock)completionHandler { | 456 completionHandler:(ProceduralBlock)completionHandler { |
396 DCHECK([NSThread isMainThread]); | 457 DCHECK([NSThread isMainThread]); |
397 DCHECK(completionHandler); | 458 DCHECK(completionHandler); |
398 DCHECK_NE(NONE, operationType); | 459 DCHECK_NE(NONE, operationType); |
399 | 460 |
400 SEL selector = | 461 SEL selector = |
401 [self browsingDataManagerSelectorForOperationType:operationType]; | 462 [self browsingDataManagerSelectorForOperationType:operationType]; |
402 DCHECK(selector); | 463 DCHECK(selector); |
403 | 464 |
404 if (operationType == RESTORE || operationType == STASH) { | 465 if (operationType == RESTORE || operationType == STASH) { |
405 [self setMode:web::CHANGING]; | 466 [self setMode:web::CHANGING]; |
406 ++self.numberOfPendingStashOrRestoreOperations; | 467 ++self.numberOfPendingStashOrRestoreOperations; |
407 completionHandler = ^{ | 468 completionHandler = ^{ |
408 --self.numberOfPendingStashOrRestoreOperations; | 469 --self.numberOfPendingStashOrRestoreOperations; |
409 // It is safe to this and does not lead to the block (|completionHandler|) | 470 // It is safe to this and does not lead to the block (|completionHandler|) |
410 // retaining itself. | 471 // retaining itself. |
411 completionHandler(); | 472 completionHandler(); |
412 }; | 473 }; |
413 } | 474 } |
414 | 475 |
415 ProceduralBlock callCompletionHandlerOnMainThread = ^{ | 476 ProceduralBlock callCompletionHandlerOnMainThread = ^{ |
416 // This is called on a background thread, hence the need to bounce to the | 477 // This is called on a background thread, hence the need to bounce to the |
417 // main thread. | 478 // main thread. |
418 dispatch_async(dispatch_get_main_queue(), ^{ | 479 dispatch_async(dispatch_get_main_queue(), completionHandler); |
419 completionHandler(); | |
420 }); | |
421 }; | 480 }; |
422 base::scoped_nsobject<NSOperation> operation( | 481 NSOperation* operation = |
423 [self newOperationWithBrowsingDataManagers:browsingDataManagers | 482 [self operationWithBrowsingDataManagers:browsingDataManagers |
424 selector:selector]); | 483 selector:selector]; |
425 | 484 |
426 if (operationType == RESTORE || operationType == STASH) { | 485 if (operationType == RESTORE || operationType == STASH) { |
427 [operation setName:(RESTORE ? kRestoreOperationName : kStashOperationName)]; | 486 [operation setName:(RESTORE ? kRestoreOperationName : kStashOperationName)]; |
428 _lastDispatchedStashOrRestoreOperation.reset([operation retain]); | 487 _lastDispatchedStashOrRestoreOperation.reset([operation retain]); |
429 } | 488 } |
430 | 489 |
431 NSOperationQueue* queue = nil; | 490 NSOperationQueue* queue = nil; |
432 switch (operationType) { | 491 switch (operationType) { |
492 case NONE: | |
493 NOTREACHED(); | |
494 break; | |
433 case STASH: | 495 case STASH: |
434 case RESTORE: | 496 case RESTORE: |
435 queue = [CRWBrowsingDataStore operationQueueForStashAndRestoreOperations]; | 497 queue = [CRWBrowsingDataStore operationQueueForStashAndRestoreOperations]; |
436 break; | 498 break; |
437 case REMOVE: | 499 case REMOVE: |
438 queue = [CRWBrowsingDataStore operationQueueForRemoveOperations]; | 500 queue = [CRWBrowsingDataStore operationQueueForRemoveOperations]; |
439 break; | 501 break; |
440 default: | |
441 NOTREACHED(); | |
442 break; | |
443 } | 502 } |
444 | 503 |
445 NSOperation* completionHandlerOperation = [NSBlockOperation | 504 NSOperation* completionHandlerOperation = [NSBlockOperation |
446 blockOperationWithBlock:callCompletionHandlerOnMainThread]; | 505 blockOperationWithBlock:callCompletionHandlerOnMainThread]; |
447 | 506 |
448 [self addOperation:operation toQueue:queue]; | 507 [self addOperation:operation toQueue:queue]; |
449 [self addOperation:completionHandlerOperation toQueue:queue]; | 508 [self addOperation:completionHandlerOperation toQueue:queue]; |
450 } | 509 } |
451 | 510 |
452 - (NSOperation*) | 511 - (NSOperation*)operationWithBrowsingDataManagers:(NSArray*)browsingDataManagers |
453 newOperationWithBrowsingDataManagers:(NSArray*)browsingDataManagers | 512 selector:(SEL)selector { |
454 selector:(SEL)selector { | 513 NSBlockOperation* operation = [[[NSBlockOperation alloc] init] autorelease]; |
455 NSBlockOperation* operation = [[NSBlockOperation alloc] init]; | |
456 for (id<CRWBrowsingDataManager> manager : browsingDataManagers) { | 514 for (id<CRWBrowsingDataManager> manager : browsingDataManagers) { |
457 // |addExecutionBlock| farms out the different blocks added to it. hence the | 515 // |addExecutionBlock| farms out the different blocks added to it. hence the |
458 // operations are implicitly parallelized. | 516 // operations are implicitly parallelized. |
459 [operation addExecutionBlock:^{ | 517 [operation addExecutionBlock:^{ |
460 [manager performSelector:selector]; | 518 [manager performSelector:selector]; |
461 }]; | 519 }]; |
462 } | 520 } |
463 return operation; | 521 return operation; |
464 } | 522 } |
465 | 523 |
466 - (void)addOperation:(NSOperation*)operation toQueue:(NSOperationQueue*)queue { | 524 - (void)addOperation:(NSOperation*)operation toQueue:(NSOperationQueue*)queue { |
467 DCHECK([NSThread isMainThread]); | 525 DCHECK([NSThread isMainThread]); |
468 DCHECK(operation); | 526 DCHECK(operation); |
469 DCHECK(queue); | 527 DCHECK(queue); |
470 | 528 |
471 if (_lastDispatchedOperation) { | 529 if (_lastDispatchedOperation) { |
472 [operation addDependency:_lastDispatchedOperation]; | 530 [operation addDependency:_lastDispatchedOperation]; |
473 } | 531 } |
474 _lastDispatchedOperation.reset([operation retain]); | 532 _lastDispatchedOperation.reset([operation retain]); |
475 [queue addOperation:operation]; | 533 [queue addOperation:operation]; |
476 } | 534 } |
477 | 535 |
478 @end | 536 @end |
OLD | NEW |