| 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 |