OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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/chrome/browser/sessions/session_service_ios.h" | 5 #import "ios/chrome/browser/sessions/session_service_ios.h" |
6 | 6 |
7 #import <UIKit/UIKit.h> | 7 #import <UIKit/UIKit.h> |
8 | 8 |
9 #include "base/critical_closure.h" | 9 #include "base/critical_closure.h" |
10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/format_macros.h" |
11 #include "base/location.h" | 12 #include "base/location.h" |
12 #include "base/logging.h" | 13 #include "base/logging.h" |
13 #import "base/mac/bind_objc_block.h" | 14 #import "base/mac/bind_objc_block.h" |
| 15 #import "base/mac/foundation_util.h" |
14 #include "base/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
15 #include "base/sequenced_task_runner.h" | 17 #include "base/sequenced_task_runner.h" |
16 #include "base/strings/sys_string_conversions.h" | 18 #include "base/strings/sys_string_conversions.h" |
17 #include "base/threading/sequenced_worker_pool.h" | 19 #include "base/threading/sequenced_worker_pool.h" |
18 #include "base/threading/thread_restrictions.h" | 20 #include "base/threading/thread_restrictions.h" |
| 21 #import "ios/chrome/browser/sessions/session_ios.h" |
19 #import "ios/chrome/browser/sessions/session_window_ios.h" | 22 #import "ios/chrome/browser/sessions/session_window_ios.h" |
20 #import "ios/web/public/crw_navigation_item_storage.h" | 23 #import "ios/web/public/crw_navigation_item_storage.h" |
21 #import "ios/web/public/crw_session_certificate_policy_cache_storage.h" | 24 #import "ios/web/public/crw_session_certificate_policy_cache_storage.h" |
22 #import "ios/web/public/crw_session_storage.h" | 25 #import "ios/web/public/crw_session_storage.h" |
23 #include "ios/web/public/web_thread.h" | 26 #include "ios/web/public/web_thread.h" |
24 | 27 |
25 #if !defined(__has_feature) || !__has_feature(objc_arc) | 28 #if !defined(__has_feature) || !__has_feature(objc_arc) |
26 #error "This file requires ARC support." | 29 #error "This file requires ARC support." |
27 #endif | 30 #endif |
28 | 31 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 [self setClass:[CRWSessionCertificatePolicyCacheStorage class] | 68 [self setClass:[CRWSessionCertificatePolicyCacheStorage class] |
66 forClassName:@"CRWSessionCertificatePolicyManager"]; | 69 forClassName:@"CRWSessionCertificatePolicyManager"]; |
67 } | 70 } |
68 | 71 |
69 @end | 72 @end |
70 | 73 |
71 @implementation SessionServiceIOS { | 74 @implementation SessionServiceIOS { |
72 // The SequencedTaskRunner on which File IO operations are performed. | 75 // The SequencedTaskRunner on which File IO operations are performed. |
73 scoped_refptr<base::SequencedTaskRunner> _taskRunner; | 76 scoped_refptr<base::SequencedTaskRunner> _taskRunner; |
74 | 77 |
75 // Maps session path to the pending session window for the delayed save | 78 // Maps session path to the pending session for the delayed save behaviour. |
76 // behaviour. | 79 NSMutableDictionary<NSString*, SessionIOS*>* _pendingSessions; |
77 NSMutableDictionary<NSString*, SessionWindowIOS*>* _pendingSessionWindows; | |
78 } | 80 } |
79 | 81 |
80 #pragma mark - NSObject overrides | 82 #pragma mark - NSObject overrides |
81 | 83 |
82 - (instancetype)init { | 84 - (instancetype)init { |
83 base::SequencedWorkerPool* pool = web::WebThread::GetBlockingPool(); | 85 base::SequencedWorkerPool* pool = web::WebThread::GetBlockingPool(); |
84 scoped_refptr<base::SequencedTaskRunner> taskRunner = | 86 scoped_refptr<base::SequencedTaskRunner> taskRunner = |
85 pool->GetSequencedTaskRunner(pool->GetSequenceToken()); | 87 pool->GetSequencedTaskRunner(pool->GetSequenceToken()); |
86 return [self initWithTaskRunner:taskRunner]; | 88 return [self initWithTaskRunner:taskRunner]; |
87 } | 89 } |
88 | 90 |
89 #pragma mark - Public interface | 91 #pragma mark - Public interface |
90 | 92 |
91 + (SessionServiceIOS*)sharedService { | 93 + (SessionServiceIOS*)sharedService { |
92 static SessionServiceIOS* singleton = nil; | 94 static SessionServiceIOS* singleton = nil; |
93 if (!singleton) { | 95 if (!singleton) { |
94 singleton = [[[self class] alloc] init]; | 96 singleton = [[[self class] alloc] init]; |
95 } | 97 } |
96 return singleton; | 98 return singleton; |
97 } | 99 } |
98 | 100 |
99 - (instancetype)initWithTaskRunner: | 101 - (instancetype)initWithTaskRunner: |
100 (const scoped_refptr<base::SequencedTaskRunner>&)taskRunner { | 102 (const scoped_refptr<base::SequencedTaskRunner>&)taskRunner { |
101 DCHECK(taskRunner); | 103 DCHECK(taskRunner); |
102 self = [super init]; | 104 self = [super init]; |
103 if (self) { | 105 if (self) { |
104 _pendingSessionWindows = [NSMutableDictionary dictionary]; | 106 _pendingSessions = [NSMutableDictionary dictionary]; |
105 _taskRunner = taskRunner; | 107 _taskRunner = taskRunner; |
106 } | 108 } |
107 return self; | 109 return self; |
108 } | 110 } |
109 | 111 |
110 - (void)saveSessionWindow:(SessionWindowIOS*)sessionWindow | 112 - (void)saveSession:(SessionIOS*)session |
111 directory:(NSString*)directory | 113 directory:(NSString*)directory |
112 immediately:(BOOL)immediately { | 114 immediately:(BOOL)immediately { |
113 NSString* sessionPath = [[self class] sessionPathForDirectory:directory]; | 115 NSString* sessionPath = [[self class] sessionPathForDirectory:directory]; |
114 BOOL hadPendingSession = | 116 BOOL hadPendingSession = [_pendingSessions objectForKey:sessionPath] != nil; |
115 [_pendingSessionWindows objectForKey:sessionPath] != nil; | 117 [_pendingSessions setObject:session forKey:sessionPath]; |
116 [_pendingSessionWindows setObject:sessionWindow forKey:sessionPath]; | |
117 if (immediately) { | 118 if (immediately) { |
118 [NSObject cancelPreviousPerformRequestsWithTarget:self]; | 119 [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
119 [self performSaveToPathInBackground:sessionPath]; | 120 [self performSaveToPathInBackground:sessionPath]; |
120 } else if (!hadPendingSession) { | 121 } else if (!hadPendingSession) { |
121 // If there wasn't previously a delayed save pending for |sessionPath|, | 122 // If there wasn't previously a delayed save pending for |sessionPath|, |
122 // enqueue one now. | 123 // enqueue one now. |
123 [self performSelector:@selector(performSaveToPathInBackground:) | 124 [self performSelector:@selector(performSaveToPathInBackground:) |
124 withObject:sessionPath | 125 withObject:sessionPath |
125 afterDelay:kSaveDelay]; | 126 afterDelay:kSaveDelay]; |
126 } | 127 } |
127 } | 128 } |
128 | 129 |
129 - (SessionWindowIOS*)loadSessionWindowFromDirectory:(NSString*)directory { | 130 - (SessionIOS*)loadSessionFromDirectory:(NSString*)directory { |
130 NSString* sessionPath = [[self class] sessionPathForDirectory:directory]; | 131 NSString* sessionPath = [[self class] sessionPathForDirectory:directory]; |
131 return [self loadSessionWindowFromPath:sessionPath]; | 132 return [self loadSessionFromPath:sessionPath]; |
132 } | 133 } |
133 | 134 |
134 - (SessionWindowIOS*)loadSessionWindowFromPath:(NSString*)sessionPath { | 135 - (SessionIOS*)loadSessionFromPath:(NSString*)sessionPath { |
| 136 NSObject<NSCoding>* rootObject = nil; |
135 @try { | 137 @try { |
136 NSData* data = [NSData dataWithContentsOfFile:sessionPath]; | 138 NSData* data = [NSData dataWithContentsOfFile:sessionPath]; |
137 if (!data) | 139 if (!data) |
138 return nil; | 140 return nil; |
139 | 141 |
140 NSKeyedUnarchiver* unarchiver = | 142 NSKeyedUnarchiver* unarchiver = |
141 [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; | 143 [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; |
142 | 144 |
143 // Register compatibility aliases to support legacy saved sessions. | 145 // Register compatibility aliases to support legacy saved sessions. |
144 [unarchiver cr_registerCompatibilityAliases]; | 146 [unarchiver cr_registerCompatibilityAliases]; |
145 return [unarchiver decodeObjectForKey:kRootObjectKey]; | 147 rootObject = [unarchiver decodeObjectForKey:kRootObjectKey]; |
146 } @catch (NSException* exception) { | 148 } @catch (NSException* exception) { |
147 NOTREACHED() << "Error loading session file: " | 149 NOTREACHED() << "Error loading session file: " |
148 << base::SysNSStringToUTF8(sessionPath) << ": " | 150 << base::SysNSStringToUTF8(sessionPath) << ": " |
149 << base::SysNSStringToUTF8([exception reason]); | 151 << base::SysNSStringToUTF8([exception reason]); |
| 152 } |
| 153 |
| 154 if (!rootObject) |
150 return nil; | 155 return nil; |
| 156 |
| 157 // Support for legacy saved session that contained a single SessionWindowIOS |
| 158 // object as the root object (pre-M-59). |
| 159 if ([rootObject isKindOfClass:[SessionWindowIOS class]]) { |
| 160 return [[SessionIOS alloc] initWithWindows:@[ |
| 161 base::mac::ObjCCastStrict<SessionWindowIOS>(rootObject) |
| 162 ]]; |
151 } | 163 } |
| 164 |
| 165 return base::mac::ObjCCastStrict<SessionIOS>(rootObject); |
152 } | 166 } |
153 | 167 |
154 - (void)deleteLastSessionFileInDirectory:(NSString*)directory { | 168 - (void)deleteLastSessionFileInDirectory:(NSString*)directory { |
155 NSString* sessionPath = [[self class] sessionPathForDirectory:directory]; | 169 NSString* sessionPath = [[self class] sessionPathForDirectory:directory]; |
156 _taskRunner->PostTask( | 170 _taskRunner->PostTask( |
157 FROM_HERE, base::BindBlockArc(^{ | 171 FROM_HERE, base::BindBlockArc(^{ |
158 base::ThreadRestrictions::AssertIOAllowed(); | 172 base::ThreadRestrictions::AssertIOAllowed(); |
159 NSFileManager* fileManager = [NSFileManager defaultManager]; | 173 NSFileManager* fileManager = [NSFileManager defaultManager]; |
160 if (![fileManager fileExistsAtPath:sessionPath]) | 174 if (![fileManager fileExistsAtPath:sessionPath]) |
161 return; | 175 return; |
162 | 176 |
163 NSError* error = nil; | 177 NSError* error = nil; |
164 if (![fileManager removeItemAtPath:sessionPath error:nil]) | 178 if (![fileManager removeItemAtPath:sessionPath error:nil]) |
165 CHECK(false) << "Unable to delete session file: " | 179 CHECK(false) << "Unable to delete session file: " |
166 << base::SysNSStringToUTF8(sessionPath) << ": " | 180 << base::SysNSStringToUTF8(sessionPath) << ": " |
167 << base::SysNSStringToUTF8([error description]); | 181 << base::SysNSStringToUTF8([error description]); |
168 })); | 182 })); |
169 } | 183 } |
170 | 184 |
171 + (NSString*)sessionPathForDirectory:(NSString*)directory { | 185 + (NSString*)sessionPathForDirectory:(NSString*)directory { |
172 return [directory stringByAppendingPathComponent:@"session.plist"]; | 186 return [directory stringByAppendingPathComponent:@"session.plist"]; |
173 } | 187 } |
174 | 188 |
175 #pragma mark - Private methods | 189 #pragma mark - Private methods |
176 | 190 |
177 // Do the work of saving on a background thread. | 191 // Do the work of saving on a background thread. |
178 - (void)performSaveToPathInBackground:(NSString*)sessionPath { | 192 - (void)performSaveToPathInBackground:(NSString*)sessionPath { |
179 DCHECK(sessionPath); | 193 DCHECK(sessionPath); |
180 DCHECK([_pendingSessionWindows objectForKey:sessionPath] != nil); | 194 DCHECK([_pendingSessions objectForKey:sessionPath] != nil); |
181 | 195 |
182 // Serialize to NSData on the main thread to avoid accessing potentially | 196 // Serialize to NSData on the main thread to avoid accessing potentially |
183 // non-threadsafe objects on a background thread. | 197 // non-threadsafe objects on a background thread. |
184 SessionWindowIOS* sessionWindow = | 198 SessionIOS* session = [_pendingSessions objectForKey:sessionPath]; |
185 [_pendingSessionWindows objectForKey:sessionPath]; | 199 [_pendingSessions removeObjectForKey:sessionPath]; |
186 [_pendingSessionWindows removeObjectForKey:sessionPath]; | |
187 | 200 |
188 @try { | 201 @try { |
189 NSData* sessionData = | 202 NSData* sessionData = [NSKeyedArchiver archivedDataWithRootObject:session]; |
190 [NSKeyedArchiver archivedDataWithRootObject:sessionWindow]; | |
191 _taskRunner->PostTask( | 203 _taskRunner->PostTask( |
192 FROM_HERE, base::MakeCriticalClosure(base::BindBlockArc(^{ | 204 FROM_HERE, base::MakeCriticalClosure(base::BindBlockArc(^{ |
193 [self performSaveSessionData:sessionData sessionPath:sessionPath]; | 205 [self performSaveSessionData:sessionData sessionPath:sessionPath]; |
194 }))); | 206 }))); |
195 } @catch (NSException* exception) { | 207 } @catch (NSException* exception) { |
196 NOTREACHED() << "Error serializing session for path: " | 208 NOTREACHED() << "Error serializing session for path: " |
197 << base::SysNSStringToUTF8(sessionPath) << ": " | 209 << base::SysNSStringToUTF8(sessionPath) << ": " |
198 << base::SysNSStringToUTF8([exception description]); | 210 << base::SysNSStringToUTF8([exception description]); |
199 return; | 211 return; |
200 } | 212 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 | 250 |
239 if (![sessionData writeToFile:sessionPath options:options error:&error]) { | 251 if (![sessionData writeToFile:sessionPath options:options error:&error]) { |
240 NOTREACHED() << "Error writing session file: " | 252 NOTREACHED() << "Error writing session file: " |
241 << base::SysNSStringToUTF8(sessionPath) << ": " | 253 << base::SysNSStringToUTF8(sessionPath) << ": " |
242 << base::SysNSStringToUTF8([error description]); | 254 << base::SysNSStringToUTF8([error description]); |
243 return; | 255 return; |
244 } | 256 } |
245 } | 257 } |
246 | 258 |
247 @end | 259 @end |
OLD | NEW |