| 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.h" | 5 #import "ios/chrome/browser/sessions/session_service.h" |
| 6 | 6 |
| 7 #import <UIKit/UIKit.h> | 7 #import <UIKit/UIKit.h> |
| 8 | 8 |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 // |catch| so as to allow exception-expecting C++ code to build properly when | 28 // |catch| so as to allow exception-expecting C++ code to build properly when |
| 29 // language support for exceptions is not present. These macros interfere | 29 // language support for exceptions is not present. These macros interfere |
| 30 // with the use of |@try| and |@catch| in Objective-C files such as this one. | 30 // with the use of |@try| and |@catch| in Objective-C files such as this one. |
| 31 // Undefine these macros here, after everything has been #included, since | 31 // Undefine these macros here, after everything has been #included, since |
| 32 // there will be no C++ uses and only Objective-C uses from this point on. | 32 // there will be no C++ uses and only Objective-C uses from this point on. |
| 33 #undef try | 33 #undef try |
| 34 #undef catch | 34 #undef catch |
| 35 | 35 |
| 36 const NSTimeInterval kSaveDelay = 2.5; // Value taken from Desktop Chrome. | 36 const NSTimeInterval kSaveDelay = 2.5; // Value taken from Desktop Chrome. |
| 37 | 37 |
| 38 @interface SessionWindowUnarchiver () { | 38 @interface SessionWindowUnarchiver () |
| 39 ios::ChromeBrowserState* _browserState; | 39 |
| 40 } | 40 // Register compatibility aliases to support loading serialised sessions |
| 41 // informations when the serialised classes are renamed. |
| 42 + (void)registerCompatibilityAliases; |
| 41 | 43 |
| 42 @end | 44 @end |
| 43 | 45 |
| 44 @implementation SessionWindowUnarchiver | 46 @implementation SessionWindowUnarchiver |
| 45 | 47 |
| 46 @synthesize browserState = _browserState; // weak | 48 @synthesize browserState = _browserState; |
| 47 | 49 |
| 48 - (id)initForReadingWithData:(NSData*)data | 50 - (instancetype)initForReadingWithData:(NSData*)data |
| 49 browserState:(ios::ChromeBrowserState*)browserState { | 51 browserState:(ios::ChromeBrowserState*)browserState { |
| 50 if (self = [super initForReadingWithData:data]) { | 52 if (self = [super initForReadingWithData:data]) { |
| 51 _browserState = browserState; | 53 _browserState = browserState; |
| 52 } | 54 } |
| 53 return self; | 55 return self; |
| 54 } | 56 } |
| 55 | 57 |
| 58 - (instancetype)initForReadingWithData:(NSData*)data { |
| 59 return [self initForReadingWithData:data browserState:nullptr]; |
| 60 } |
| 61 |
| 62 + (void)initialize { |
| 63 [super initialize]; |
| 64 [self registerCompatibilityAliases]; |
| 65 } |
| 66 |
| 67 // When adding a new compatibility alias here, create a new crbug to track its |
| 68 // removal and mark it with a release at least one year after the introduction |
| 69 // of the alias. |
| 70 + (void)registerCompatibilityAliases { |
| 71 // TODO(crbug.com/661633): those aliases where introduced between M57 and |
| 72 // M58, so remove them after M67 has shipped to stable. |
| 73 [SessionWindowUnarchiver setClass:[CRWSessionCertificatePolicyManager class] |
| 74 forClassName:@"SessionCertificatePolicyManager"]; |
| 75 [SessionWindowUnarchiver setClass:[CRWSessionStorage class] |
| 76 forClassName:@"SessionController"]; |
| 77 [SessionWindowUnarchiver setClass:[CRWSessionStorage class] |
| 78 forClassName:@"CRWSessionController"]; |
| 79 [SessionWindowUnarchiver setClass:[CRWNavigationItemStorage class] |
| 80 forClassName:@"SessionEntry"]; |
| 81 [SessionWindowUnarchiver setClass:[CRWNavigationItemStorage class] |
| 82 forClassName:@"CRWSessionEntry"]; |
| 83 [SessionWindowUnarchiver setClass:[SessionWindowIOS class] |
| 84 forClassName:@"SessionWindow"]; |
| 85 |
| 86 // TODO(crbug.com/661633): this alias was introduced between M58 and M59, so |
| 87 // remove it after M68 has shipped to stable. |
| 88 [SessionWindowUnarchiver setClass:[CRWSessionStorage class] |
| 89 forClassName:@"CRWNavigationManagerStorage"]; |
| 90 } |
| 91 |
| 56 @end | 92 @end |
| 57 | 93 |
| 58 @interface SessionServiceIOS () { | 94 @interface SessionServiceIOS () { |
| 59 @private | |
| 60 // The SequencedTaskRunner on which File IO operations are performed. | 95 // The SequencedTaskRunner on which File IO operations are performed. |
| 61 scoped_refptr<base::SequencedTaskRunner> taskRunner_; | 96 scoped_refptr<base::SequencedTaskRunner> _taskRunner; |
| 62 | 97 |
| 63 // Maps save directories to the pending SessionWindow for the delayed | 98 // Maps save directories to the pending SessionWindow for the delayed |
| 64 // save behavior. | 99 // save behavior. |
| 65 base::scoped_nsobject<NSMutableDictionary> pendingWindows_; | 100 base::scoped_nsobject<NSMutableDictionary> _pendingWindows; |
| 66 } | 101 } |
| 67 | 102 |
| 103 // Saves the session corresponding to |directory| on the background |
| 104 // task runner |_taskRunner|. |
| 68 - (void)performSaveToDirectoryInBackground:(NSString*)directory; | 105 - (void)performSaveToDirectoryInBackground:(NSString*)directory; |
| 69 - (void)performSaveWindow:(SessionWindowIOS*)window | |
| 70 toDirectory:(NSString*)directory; | |
| 71 @end | 106 @end |
| 72 | 107 |
| 73 @implementation SessionServiceIOS | 108 @implementation SessionServiceIOS |
| 74 | 109 |
| 75 + (SessionServiceIOS*)sharedService { | 110 + (SessionServiceIOS*)sharedService { |
| 76 static SessionServiceIOS* singleton = nil; | 111 static SessionServiceIOS* singleton = nil; |
| 77 if (!singleton) { | 112 if (!singleton) { |
| 78 singleton = [[[self class] alloc] init]; | 113 singleton = [[[self class] alloc] init]; |
| 79 } | 114 } |
| 80 return singleton; | 115 return singleton; |
| 81 } | 116 } |
| 82 | 117 |
| 83 - (id)init { | 118 - (instancetype)init { |
| 84 self = [super init]; | 119 self = [super init]; |
| 85 if (self) { | 120 if (self) { |
| 86 pendingWindows_.reset([[NSMutableDictionary alloc] init]); | 121 _pendingWindows.reset([[NSMutableDictionary alloc] init]); |
| 87 auto* pool = web::WebThread::GetBlockingPool(); | 122 auto* pool = web::WebThread::GetBlockingPool(); |
| 88 taskRunner_ = pool->GetSequencedTaskRunner(pool->GetSequenceToken()); | 123 _taskRunner = pool->GetSequencedTaskRunner(pool->GetSequenceToken()); |
| 89 } | 124 } |
| 90 return self; | 125 return self; |
| 91 } | 126 } |
| 92 | 127 |
| 93 // Returns the path of the session file. | 128 // Returns the path of the session file. |
| 94 - (NSString*)sessionFilePathForDirectory:(NSString*)directory { | 129 - (NSString*)sessionFilePathForDirectory:(NSString*)directory { |
| 95 return [directory stringByAppendingPathComponent:@"session.plist"]; | 130 return [directory stringByAppendingPathComponent:@"session.plist"]; |
| 96 } | 131 } |
| 97 | 132 |
| 98 // Do the work of saving on a background thread. Assumes |window| is threadsafe. | 133 // Do the work of saving on a background thread. Assumes |window| is threadsafe. |
| 99 - (void)performSaveToDirectoryInBackground:(NSString*)directory { | 134 - (void)performSaveToDirectoryInBackground:(NSString*)directory { |
| 100 DCHECK(directory); | 135 DCHECK(directory); |
| 101 DCHECK([pendingWindows_ objectForKey:directory] != nil); | 136 DCHECK([_pendingWindows objectForKey:directory] != nil); |
| 102 UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication] | 137 UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication] |
| 103 beginBackgroundTaskWithExpirationHandler:^{ | 138 beginBackgroundTaskWithExpirationHandler:^{ |
| 104 }]; | 139 }]; |
| 105 DCHECK(identifier != UIBackgroundTaskInvalid); | 140 DCHECK(identifier != UIBackgroundTaskInvalid); |
| 106 | 141 |
| 107 // Put the window into a local var so it can be retained for the block, yet | 142 // Put the window into a local var so it can be retained for the block, yet |
| 108 // we can remove it from the dictionary to allow queuing another save. | 143 // we can remove it from the dictionary to allow queuing another save. |
| 109 SessionWindowIOS* localWindow = | 144 SessionWindowIOS* localWindow = |
| 110 [[pendingWindows_ objectForKey:directory] retain]; | 145 [[_pendingWindows objectForKey:directory] retain]; |
| 111 [pendingWindows_ removeObjectForKey:directory]; | 146 [_pendingWindows removeObjectForKey:directory]; |
| 112 | 147 |
| 113 taskRunner_->PostTask( | 148 _taskRunner->PostTask( |
| 114 FROM_HERE, base::BindBlock(^{ | 149 FROM_HERE, base::BindBlock(^{ |
| 115 @try { | 150 @try { |
| 116 [self performSaveWindow:localWindow toDirectory:directory]; | 151 [self performSaveWindow:localWindow toDirectory:directory]; |
| 117 } @catch (NSException* e) { | 152 } @catch (NSException* e) { |
| 118 // Do nothing. | 153 // Do nothing. |
| 119 } | 154 } |
| 120 [localWindow release]; | 155 [localWindow release]; |
| 121 [[UIApplication sharedApplication] endBackgroundTask:identifier]; | 156 [[UIApplication sharedApplication] endBackgroundTask:identifier]; |
| 122 })); | 157 })); |
| 123 } | 158 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 } | 207 } |
| 173 | 208 |
| 174 - (void)saveWindow:(SessionWindowIOS*)window | 209 - (void)saveWindow:(SessionWindowIOS*)window |
| 175 forBrowserState:(ios::ChromeBrowserState*)browserState | 210 forBrowserState:(ios::ChromeBrowserState*)browserState |
| 176 immediately:(BOOL)immediately { | 211 immediately:(BOOL)immediately { |
| 177 NSString* stashPath = | 212 NSString* stashPath = |
| 178 base::SysUTF8ToNSString(browserState->GetStatePath().value()); | 213 base::SysUTF8ToNSString(browserState->GetStatePath().value()); |
| 179 // If there's an existing session window for |stashPath|, clear it before it's | 214 // If there's an existing session window for |stashPath|, clear it before it's |
| 180 // replaced. | 215 // replaced. |
| 181 SessionWindowIOS* pendingSession = base::mac::ObjCCast<SessionWindowIOS>( | 216 SessionWindowIOS* pendingSession = base::mac::ObjCCast<SessionWindowIOS>( |
| 182 [pendingWindows_ objectForKey:stashPath]); | 217 [_pendingWindows objectForKey:stashPath]); |
| 183 [pendingSession clearSessions]; | 218 [pendingSession clearSessions]; |
| 184 // Set |window| as the pending save for |stashPath|. | 219 // Set |window| as the pending save for |stashPath|. |
| 185 [pendingWindows_ setObject:window forKey:stashPath]; | 220 [_pendingWindows setObject:window forKey:stashPath]; |
| 186 if (immediately) { | 221 if (immediately) { |
| 187 [NSObject cancelPreviousPerformRequestsWithTarget:self]; | 222 [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
| 188 [self performSaveToDirectoryInBackground:stashPath]; | 223 [self performSaveToDirectoryInBackground:stashPath]; |
| 189 } else if (!pendingSession) { | 224 } else if (!pendingSession) { |
| 190 // If there wasn't previously a delayed save pending for |stashPath|, | 225 // If there wasn't previously a delayed save pending for |stashPath|, |
| 191 // enqueue one now. | 226 // enqueue one now. |
| 192 [self performSelector:@selector(performSaveToDirectoryInBackground:) | 227 [self performSelector:@selector(performSaveToDirectoryInBackground:) |
| 193 withObject:stashPath | 228 withObject:stashPath |
| 194 afterDelay:kSaveDelay]; | 229 afterDelay:kSaveDelay]; |
| 195 } | 230 } |
| 196 } | 231 } |
| 197 | 232 |
| 198 - (SessionWindowIOS*)loadWindowForBrowserState: | 233 - (SessionWindowIOS*)loadWindowForBrowserState: |
| 199 (ios::ChromeBrowserState*)browserState { | 234 (ios::ChromeBrowserState*)browserState { |
| 200 NSString* stashPath = | 235 NSString* stashPath = |
| 201 base::SysUTF8ToNSString(browserState->GetStatePath().value()); | 236 base::SysUTF8ToNSString(browserState->GetStatePath().value()); |
| 202 SessionWindowIOS* window = | 237 SessionWindowIOS* window = |
| 203 [self loadWindowFromPath:[self sessionFilePathForDirectory:stashPath] | 238 [self loadWindowFromPath:[self sessionFilePathForDirectory:stashPath] |
| 204 forBrowserState:browserState]; | 239 forBrowserState:browserState]; |
| 205 return window; | 240 return window; |
| 206 } | 241 } |
| 207 | 242 |
| 208 - (SessionWindowIOS*)loadWindowFromPath:(NSString*)path | 243 - (SessionWindowIOS*)loadWindowFromPath:(NSString*)path |
| 209 forBrowserState:(ios::ChromeBrowserState*)browserState { | 244 forBrowserState:(ios::ChromeBrowserState*)browserState { |
| 210 // HACK: Handle the case where we had to change the class name of a persisted | |
| 211 // class on disk. | |
| 212 [SessionWindowUnarchiver setClass:[CRWSessionCertificatePolicyManager class] | |
| 213 forClassName:@"SessionCertificatePolicyManager"]; | |
| 214 [SessionWindowUnarchiver setClass:[CRWSessionStorage class] | |
| 215 forClassName:@"SessionController"]; | |
| 216 [SessionWindowUnarchiver setClass:[CRWSessionStorage class] | |
| 217 forClassName:@"CRWSessionController"]; | |
| 218 [SessionWindowUnarchiver setClass:[CRWSessionStorage class] | |
| 219 forClassName:@"CRWNavigationManagerStorage"]; | |
| 220 [SessionWindowUnarchiver setClass:[CRWNavigationItemStorage class] | |
| 221 forClassName:@"SessionEntry"]; | |
| 222 [SessionWindowUnarchiver setClass:[CRWNavigationItemStorage class] | |
| 223 forClassName:@"CRWSessionEntry"]; | |
| 224 // TODO(crbug.com/661633): Remove this hack. | |
| 225 [SessionWindowUnarchiver setClass:[SessionWindowIOS class] | |
| 226 forClassName:@"SessionWindow"]; | |
| 227 SessionWindowIOS* window = nil; | 245 SessionWindowIOS* window = nil; |
| 228 @try { | 246 @try { |
| 229 NSData* data = [NSData dataWithContentsOfFile:path]; | 247 NSData* data = [NSData dataWithContentsOfFile:path]; |
| 230 if (data) { | 248 if (data) { |
| 231 base::scoped_nsobject<SessionWindowUnarchiver> unarchiver([ | 249 base::scoped_nsobject<SessionWindowUnarchiver> unarchiver([ |
| 232 [SessionWindowUnarchiver alloc] initForReadingWithData:data | 250 [SessionWindowUnarchiver alloc] initForReadingWithData:data |
| 233 browserState:browserState]); | 251 browserState:browserState]); |
| 234 window = [[[unarchiver decodeObjectForKey:@"root"] retain] autorelease]; | 252 window = [[[unarchiver decodeObjectForKey:@"root"] retain] autorelease]; |
| 235 } | 253 } |
| 236 } @catch (NSException* exception) { | 254 } @catch (NSException* exception) { |
| 237 DLOG(ERROR) << "Error loading session.plist"; | 255 DLOG(ERROR) << "Error loading session file."; |
| 238 } | 256 } |
| 239 return window; | 257 return window; |
| 240 } | 258 } |
| 241 | 259 |
| 242 // Deletes the file containing the commands for the last session in the given | 260 // Deletes the file containing the commands for the last session in the given |
| 243 // browserState directory. | 261 // browserState directory. |
| 244 - (void)deleteLastSession:(NSString*)directory { | 262 - (void)deleteLastSession:(NSString*)directory { |
| 245 NSString* sessionFile = [self sessionFilePathForDirectory:directory]; | 263 NSString* sessionFile = [self sessionFilePathForDirectory:directory]; |
| 246 taskRunner_->PostTask( | 264 _taskRunner->PostTask( |
| 247 FROM_HERE, base::BindBlock(^{ | 265 FROM_HERE, base::BindBlock(^{ |
| 248 base::ThreadRestrictions::AssertIOAllowed(); | 266 base::ThreadRestrictions::AssertIOAllowed(); |
| 249 NSFileManager* fileManager = [NSFileManager defaultManager]; | 267 NSFileManager* fileManager = [NSFileManager defaultManager]; |
| 250 if (![fileManager fileExistsAtPath:sessionFile]) | 268 if (![fileManager fileExistsAtPath:sessionFile]) |
| 251 return; | 269 return; |
| 252 if (![fileManager removeItemAtPath:sessionFile error:nil]) | 270 if (![fileManager removeItemAtPath:sessionFile error:nil]) |
| 253 CHECK(false) << "Unable to delete session file."; | 271 CHECK(false) << "Unable to delete session file."; |
| 254 })); | 272 })); |
| 255 } | 273 } |
| 256 | 274 |
| 257 @end | 275 @end |
| OLD | NEW |