Chromium Code Reviews| 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_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/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 10 #include "base/location.h" | 11 #include "base/location.h" |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/mac/bind_objc_block.h" | 13 #import "base/mac/bind_objc_block.h" |
| 13 #include "base/mac/foundation_util.h" | |
| 14 #include "base/memory/ref_counted.h" | 14 #include "base/memory/ref_counted.h" |
| 15 #include "base/sequenced_task_runner.h" | 15 #include "base/sequenced_task_runner.h" |
| 16 #include "base/strings/sys_string_conversions.h" | 16 #include "base/strings/sys_string_conversions.h" |
| 17 #include "base/synchronization/lock.h" | |
| 18 #include "base/threading/sequenced_worker_pool.h" | 17 #include "base/threading/sequenced_worker_pool.h" |
| 19 #include "base/threading/thread_restrictions.h" | 18 #include "base/threading/thread_restrictions.h" |
| 20 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" | 19 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
| 21 #import "ios/chrome/browser/sessions/session_window_ios.h" | 20 #import "ios/chrome/browser/sessions/session_window_ios.h" |
| 22 #import "ios/web/public/crw_navigation_item_storage.h" | 21 #import "ios/web/public/crw_navigation_item_storage.h" |
| 23 #import "ios/web/public/crw_session_certificate_policy_cache_storage.h" | 22 #import "ios/web/public/crw_session_certificate_policy_cache_storage.h" |
| 24 #import "ios/web/public/crw_session_storage.h" | 23 #import "ios/web/public/crw_session_storage.h" |
| 25 #include "ios/web/public/web_thread.h" | 24 #include "ios/web/public/web_thread.h" |
| 26 | 25 |
| 26 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
| 27 #error "This file requires ARC support." | |
| 28 #endif | |
| 29 | |
| 27 // When C++ exceptions are disabled, the C++ library defines |try| and | 30 // When C++ exceptions are disabled, the C++ library defines |try| and |
| 28 // |catch| so as to allow exception-expecting C++ code to build properly when | 31 // |catch| so as to allow exception-expecting C++ code to build properly when |
| 29 // language support for exceptions is not present. These macros interfere | 32 // 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. | 33 // 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 | 34 // 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. | 35 // there will be no C++ uses and only Objective-C uses from this point on. |
| 33 #undef try | 36 #undef try |
| 34 #undef catch | 37 #undef catch |
| 35 | 38 |
| 36 const NSTimeInterval kSaveDelay = 2.5; // Value taken from Desktop Chrome. | 39 const NSTimeInterval kSaveDelay = 2.5; // Value taken from Desktop Chrome. |
| 37 | 40 |
| 38 @interface SessionWindowUnarchiver () | 41 @implementation NSKeyedUnarchiver (CrLegacySessionCompatibility) |
| 39 | |
| 40 // Register compatibility aliases to support loading serialised sessions | |
| 41 // informations when the serialised classes are renamed. | |
| 42 + (void)registerCompatibilityAliases; | |
| 43 | |
| 44 @end | |
| 45 | |
| 46 @implementation SessionWindowUnarchiver | |
| 47 | |
| 48 @synthesize browserState = _browserState; | |
| 49 | |
| 50 - (instancetype)initForReadingWithData:(NSData*)data | |
| 51 browserState:(ios::ChromeBrowserState*)browserState { | |
| 52 if (self = [super initForReadingWithData:data]) { | |
| 53 _browserState = browserState; | |
| 54 } | |
| 55 return self; | |
| 56 } | |
| 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 | 42 |
| 67 // When adding a new compatibility alias here, create a new crbug to track its | 43 // 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 | 44 // removal and mark it with a release at least one year after the introduction |
| 69 // of the alias. | 45 // of the alias. |
| 70 + (void)registerCompatibilityAliases { | 46 - (void)cr_registerCompatibilityAliases { |
| 71 // TODO(crbug.com/661633): those aliases where introduced between M57 and | 47 // TODO(crbug.com/661633): those aliases where introduced between M57 and |
| 72 // M58, so remove them after M67 has shipped to stable. | 48 // M58, so remove them after M67 has shipped to stable. |
| 73 [SessionWindowUnarchiver | 49 [self setClass:[CRWSessionCertificatePolicyCacheStorage class] |
| 74 setClass:[CRWSessionCertificatePolicyCacheStorage class] | |
| 75 forClassName:@"SessionCertificatePolicyManager"]; | 50 forClassName:@"SessionCertificatePolicyManager"]; |
| 76 [SessionWindowUnarchiver setClass:[CRWSessionStorage class] | 51 [self setClass:[CRWSessionStorage class] forClassName:@"SessionController"]; |
| 77 forClassName:@"SessionController"]; | 52 [self setClass:[CRWSessionStorage class] |
| 78 [SessionWindowUnarchiver setClass:[CRWSessionStorage class] | 53 forClassName:@"CRWSessionController"]; |
| 79 forClassName:@"CRWSessionController"]; | 54 [self setClass:[CRWNavigationItemStorage class] forClassName:@"SessionEntry"]; |
| 80 [SessionWindowUnarchiver setClass:[CRWNavigationItemStorage class] | 55 [self setClass:[CRWNavigationItemStorage class] |
| 81 forClassName:@"SessionEntry"]; | 56 forClassName:@"CRWSessionEntry"]; |
| 82 [SessionWindowUnarchiver setClass:[CRWNavigationItemStorage class] | 57 [self setClass:[SessionWindowIOS class] forClassName:@"SessionWindow"]; |
| 83 forClassName:@"CRWSessionEntry"]; | |
| 84 [SessionWindowUnarchiver setClass:[SessionWindowIOS class] | |
| 85 forClassName:@"SessionWindow"]; | |
| 86 | 58 |
| 87 // TODO(crbug.com/661633): this alias was introduced between M58 and M59, so | 59 // TODO(crbug.com/661633): this alias was introduced between M58 and M59, so |
| 88 // remove it after M68 has shipped to stable. | 60 // remove it after M68 has shipped to stable. |
| 89 [SessionWindowUnarchiver setClass:[CRWSessionStorage class] | 61 [self setClass:[CRWSessionStorage class] |
| 90 forClassName:@"CRWNavigationManagerStorage"]; | 62 forClassName:@"CRWNavigationManagerStorage"]; |
| 91 [SessionWindowUnarchiver | 63 [self setClass:[CRWSessionCertificatePolicyCacheStorage class] |
| 92 setClass:[CRWSessionCertificatePolicyCacheStorage class] | |
| 93 forClassName:@"CRWSessionCertificatePolicyManager"]; | 64 forClassName:@"CRWSessionCertificatePolicyManager"]; |
| 94 } | 65 } |
| 95 | 66 |
| 96 @end | 67 @end |
| 97 | 68 |
| 98 @interface SessionServiceIOS () { | 69 @interface SessionServiceIOS () { |
| 99 // The SequencedTaskRunner on which File IO operations are performed. | 70 // The SequencedTaskRunner on which File IO operations are performed. |
| 100 scoped_refptr<base::SequencedTaskRunner> _taskRunner; | 71 scoped_refptr<base::SequencedTaskRunner> _taskRunner; |
| 101 | 72 |
| 102 // Maps save directories to the pending SessionWindow for the delayed | 73 // Maps save directories to the pending SessionWindow for the delayed |
| 103 // save behavior. | 74 // save behavior. |
| 104 base::scoped_nsobject<NSMutableDictionary> _pendingWindows; | 75 NSMutableDictionary<NSString*, SessionWindowIOS*>* _pendingWindows; |
| 105 } | 76 } |
| 106 | 77 |
| 107 // Saves the session corresponding to |directory| on the background | 78 // Saves the session corresponding to |directory| on the background |
| 108 // task runner |_taskRunner|. | 79 // task runner |_taskRunner|. |
| 109 - (void)performSaveToDirectoryInBackground:(NSString*)directory; | 80 - (void)performSaveToDirectoryInBackground:(NSString*)directory; |
| 110 @end | 81 @end |
| 111 | 82 |
| 112 @implementation SessionServiceIOS | 83 @implementation SessionServiceIOS |
| 113 | 84 |
| 114 + (SessionServiceIOS*)sharedService { | 85 + (SessionServiceIOS*)sharedService { |
| 115 static SessionServiceIOS* singleton = nil; | 86 static SessionServiceIOS* singleton = nil; |
| 116 if (!singleton) { | 87 if (!singleton) { |
| 117 singleton = [[[self class] alloc] init]; | 88 singleton = [[[self class] alloc] init]; |
| 118 } | 89 } |
| 119 return singleton; | 90 return singleton; |
| 120 } | 91 } |
| 121 | 92 |
| 122 - (instancetype)init { | 93 - (instancetype)init { |
| 123 self = [super init]; | 94 self = [super init]; |
| 124 if (self) { | 95 if (self) { |
| 125 _pendingWindows.reset([[NSMutableDictionary alloc] init]); | 96 _pendingWindows = [NSMutableDictionary dictionary]; |
| 126 auto* pool = web::WebThread::GetBlockingPool(); | 97 base::SequencedWorkerPool* pool = web::WebThread::GetBlockingPool(); |
| 127 _taskRunner = pool->GetSequencedTaskRunner(pool->GetSequenceToken()); | 98 _taskRunner = pool->GetSequencedTaskRunner(pool->GetSequenceToken()); |
| 128 } | 99 } |
| 129 return self; | 100 return self; |
| 130 } | 101 } |
| 131 | 102 |
| 132 // Returns the path of the session file. | 103 // Returns the path of the session file. |
| 133 - (NSString*)sessionFilePathForDirectory:(NSString*)directory { | 104 - (NSString*)sessionFilePathForDirectory:(NSString*)directory { |
| 134 return [directory stringByAppendingPathComponent:@"session.plist"]; | 105 return [directory stringByAppendingPathComponent:@"session.plist"]; |
| 135 } | 106 } |
| 136 | 107 |
| 137 // Do the work of saving on a background thread. Assumes |window| is threadsafe. | 108 // Do the work of saving on a background thread. Assumes |window| is threadsafe. |
| 138 - (void)performSaveToDirectoryInBackground:(NSString*)directory { | 109 - (void)performSaveToDirectoryInBackground:(NSString*)directory { |
| 139 DCHECK(directory); | 110 DCHECK(directory); |
| 140 DCHECK([_pendingWindows objectForKey:directory] != nil); | 111 DCHECK([_pendingWindows objectForKey:directory] != nil); |
| 141 UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication] | |
|
marq (ping after 24h)
2017/04/06 11:58:16
Was this code just not doing anything useful? I'm
sdefresne
2017/04/06 14:57:01
This is replaced by CriticalClosure (look in scope
| |
| 142 beginBackgroundTaskWithExpirationHandler:^{ | |
| 143 }]; | |
| 144 DCHECK(identifier != UIBackgroundTaskInvalid); | |
| 145 | 112 |
| 146 // Put the window into a local var so it can be retained for the block, yet | 113 // Put the window into a local var so it can be retained for the block, yet |
| 147 // we can remove it from the dictionary to allow queuing another save. | 114 // we can remove it from the dictionary to allow queuing another save. |
| 148 SessionWindowIOS* localWindow = | 115 SessionWindowIOS* localWindow = [_pendingWindows objectForKey:directory]; |
| 149 [[_pendingWindows objectForKey:directory] retain]; | |
| 150 [_pendingWindows removeObjectForKey:directory]; | 116 [_pendingWindows removeObjectForKey:directory]; |
| 151 | 117 |
| 152 _taskRunner->PostTask( | 118 _taskRunner->PostTask( |
| 153 FROM_HERE, base::BindBlock(^{ | 119 FROM_HERE, base::MakeCriticalClosure(base::BindBlockArc(^{ |
| 154 @try { | 120 @try { |
| 155 [self performSaveWindow:localWindow toDirectory:directory]; | 121 [self performSaveWindow:localWindow toDirectory:directory]; |
| 156 } @catch (NSException* e) { | 122 } @catch (NSException* e) { |
| 157 // Do nothing. | 123 // Do nothing. |
| 158 } | 124 } |
| 159 [localWindow release]; | 125 }))); |
| 160 [[UIApplication sharedApplication] endBackgroundTask:identifier]; | |
| 161 })); | |
| 162 } | 126 } |
| 163 | 127 |
| 164 // Saves a SessionWindowIOS in a given directory. In case the directory doesn't | 128 // Saves a SessionWindowIOS in a given directory. In case the directory doesn't |
| 165 // exists it will be automatically created. | 129 // exists it will be automatically created. |
| 166 - (void)performSaveWindow:(SessionWindowIOS*)window | 130 - (void)performSaveWindow:(SessionWindowIOS*)window |
| 167 toDirectory:(NSString*)directory { | 131 toDirectory:(NSString*)directory { |
| 168 base::ThreadRestrictions::AssertIOAllowed(); | 132 base::ThreadRestrictions::AssertIOAllowed(); |
| 169 NSFileManager* fileManager = [NSFileManager defaultManager]; | 133 NSFileManager* fileManager = [NSFileManager defaultManager]; |
| 170 BOOL isDir; | 134 BOOL isDir; |
| 171 if (![fileManager fileExistsAtPath:directory isDirectory:&isDir]) { | 135 if (![fileManager fileExistsAtPath:directory isDirectory:&isDir]) { |
| 172 NSError* error = nil; | 136 NSError* error = nil; |
| 173 BOOL result = [fileManager createDirectoryAtPath:directory | 137 BOOL result = [fileManager createDirectoryAtPath:directory |
| 174 withIntermediateDirectories:YES | 138 withIntermediateDirectories:YES |
| 175 attributes:nil | 139 attributes:nil |
| 176 error:&error]; | 140 error:&error]; |
| 177 DCHECK(result); | 141 DCHECK(result); |
| 178 if (!result) { | 142 if (!result) { |
| 179 DLOG(ERROR) << "Error creating destination dir: " | 143 DLOG(ERROR) << "Error creating destination directory: " |
| 144 << base::SysNSStringToUTF8(directory) << ": " | |
| 180 << base::SysNSStringToUTF8([error description]); | 145 << base::SysNSStringToUTF8([error description]); |
| 181 return; | 146 return; |
| 182 } | 147 } |
| 183 } else { | 148 } else { |
| 184 DCHECK(isDir); | 149 DCHECK(isDir); |
| 185 if (!isDir) { | 150 if (!isDir) { |
| 186 DLOG(ERROR) << "Destination Directory already exists and is a file"; | 151 DLOG(ERROR) << "Error creating destination directory: " |
| 152 << base::SysNSStringToUTF8(directory) << ": " | |
| 153 << "file exists and is not a directory."; | |
| 187 return; | 154 return; |
| 188 } | 155 } |
| 189 } | 156 } |
| 190 | 157 |
| 191 NSString* filename = [self sessionFilePathForDirectory:directory]; | 158 NSString* filename = [self sessionFilePathForDirectory:directory]; |
| 192 if (filename) { | 159 if (filename) { |
| 193 BOOL result = [NSKeyedArchiver archiveRootObject:window toFile:filename]; | 160 BOOL result = [NSKeyedArchiver archiveRootObject:window toFile:filename]; |
| 194 DCHECK(result); | 161 DCHECK(result); |
| 195 if (!result) | 162 if (!result) { |
| 196 DLOG(ERROR) << "Error writing session file to " << filename; | 163 DLOG(ERROR) << "Error writing session file to " << filename; |
| 164 return; | |
| 165 } | |
| 166 | |
| 197 // Encrypt the session file (mostly for Incognito, but can't hurt to | 167 // Encrypt the session file (mostly for Incognito, but can't hurt to |
| 198 // always do it). | 168 // always do it). |
| 199 NSDictionary* attributeDict = | 169 NSDictionary* attributeDict = |
|
marq (ping after 24h)
2017/04/06 11:58:16
Since you're here, make this
NSDictionary<NSFile
sdefresne
2017/04/06 14:57:01
Inlined in the method call.
| |
| 200 [NSDictionary dictionaryWithObject:NSFileProtectionComplete | 170 [NSDictionary dictionaryWithObject:NSFileProtectionComplete |
| 201 forKey:NSFileProtectionKey]; | 171 forKey:NSFileProtectionKey]; |
| 202 NSError* error = nil; | 172 NSError* error = nil; |
| 203 BOOL success = [[NSFileManager defaultManager] setAttributes:attributeDict | 173 BOOL success = [[NSFileManager defaultManager] setAttributes:attributeDict |
| 204 ofItemAtPath:filename | 174 ofItemAtPath:filename |
| 205 error:&error]; | 175 error:&error]; |
| 206 if (!success) { | 176 if (!success) { |
| 207 DLOG(ERROR) << "Error encrypting session file" | 177 DLOG(ERROR) << "Error encrypting session file: " |
| 178 << base::SysNSStringToUTF8(filename) << ": " | |
| 208 << base::SysNSStringToUTF8([error description]); | 179 << base::SysNSStringToUTF8([error description]); |
| 209 } | 180 } |
| 210 } | 181 } |
| 211 } | 182 } |
| 212 | 183 |
| 213 - (void)saveWindow:(SessionWindowIOS*)window | 184 - (void)saveWindow:(SessionWindowIOS*)window |
| 214 forBrowserState:(ios::ChromeBrowserState*)browserState | 185 forBrowserState:(ios::ChromeBrowserState*)browserState |
| 215 immediately:(BOOL)immediately { | 186 immediately:(BOOL)immediately { |
| 216 NSString* stashPath = | 187 NSString* stashPath = |
| 217 base::SysUTF8ToNSString(browserState->GetStatePath().value()); | 188 base::SysUTF8ToNSString(browserState->GetStatePath().value()); |
| 218 // If there's an existing session window for |stashPath|, clear it before it's | 189 BOOL hadPendingSession = [_pendingWindows objectForKey:stashPath] != nil; |
| 219 // replaced. | |
| 220 SessionWindowIOS* pendingSession = base::mac::ObjCCast<SessionWindowIOS>( | |
| 221 [_pendingWindows objectForKey:stashPath]); | |
| 222 [pendingSession clearSessions]; | |
| 223 // Set |window| as the pending save for |stashPath|. | |
| 224 [_pendingWindows setObject:window forKey:stashPath]; | 190 [_pendingWindows setObject:window forKey:stashPath]; |
| 225 if (immediately) { | 191 if (immediately) { |
| 226 [NSObject cancelPreviousPerformRequestsWithTarget:self]; | 192 [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
| 227 [self performSaveToDirectoryInBackground:stashPath]; | 193 [self performSaveToDirectoryInBackground:stashPath]; |
| 228 } else if (!pendingSession) { | 194 } else if (!hadPendingSession) { |
| 229 // If there wasn't previously a delayed save pending for |stashPath|, | 195 // If there wasn't previously a delayed save pending for |stashPath|, |
| 230 // enqueue one now. | 196 // enqueue one now. |
| 231 [self performSelector:@selector(performSaveToDirectoryInBackground:) | 197 [self performSelector:@selector(performSaveToDirectoryInBackground:) |
| 232 withObject:stashPath | 198 withObject:stashPath |
| 233 afterDelay:kSaveDelay]; | 199 afterDelay:kSaveDelay]; |
| 234 } | 200 } |
| 235 } | 201 } |
| 236 | 202 |
| 237 - (SessionWindowIOS*)loadWindowForBrowserState: | 203 - (SessionWindowIOS*)loadWindowForBrowserState: |
| 238 (ios::ChromeBrowserState*)browserState { | 204 (ios::ChromeBrowserState*)browserState { |
| 239 NSString* stashPath = | 205 NSString* stashPath = |
| 240 base::SysUTF8ToNSString(browserState->GetStatePath().value()); | 206 base::SysUTF8ToNSString(browserState->GetStatePath().value()); |
| 241 SessionWindowIOS* window = | 207 SessionWindowIOS* window = |
| 242 [self loadWindowFromPath:[self sessionFilePathForDirectory:stashPath] | 208 [self loadWindowFromPath:[self sessionFilePathForDirectory:stashPath]]; |
| 243 forBrowserState:browserState]; | |
| 244 return window; | 209 return window; |
| 245 } | 210 } |
| 246 | 211 |
| 247 - (SessionWindowIOS*)loadWindowFromPath:(NSString*)path | 212 - (SessionWindowIOS*)loadWindowFromPath:(NSString*)sessionPath { |
| 248 forBrowserState:(ios::ChromeBrowserState*)browserState { | |
| 249 SessionWindowIOS* window = nil; | |
| 250 @try { | 213 @try { |
| 251 NSData* data = [NSData dataWithContentsOfFile:path]; | 214 NSData* data = [NSData dataWithContentsOfFile:sessionPath]; |
| 252 if (data) { | 215 if (!data) |
| 253 base::scoped_nsobject<SessionWindowUnarchiver> unarchiver([ | 216 return nil; |
| 254 [SessionWindowUnarchiver alloc] initForReadingWithData:data | 217 |
| 255 browserState:browserState]); | 218 NSKeyedUnarchiver* unarchiver = |
| 256 window = [[[unarchiver decodeObjectForKey:@"root"] retain] autorelease]; | 219 [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; |
| 257 } | 220 |
| 221 // Register compatibility aliases to support legacy saved sessions. | |
| 222 [unarchiver cr_registerCompatibilityAliases]; | |
| 223 return [unarchiver decodeObjectForKey:@"root"]; | |
|
marq (ping after 24h)
2017/04/06 11:58:16
Extract @"root" into a constant?
sdefresne
2017/04/06 14:57:01
Done.
| |
| 258 } @catch (NSException* exception) { | 224 } @catch (NSException* exception) { |
| 259 DLOG(ERROR) << "Error loading session file."; | 225 DLOG(ERROR) << "Error loading session file: " |
| 226 << base::SysNSStringToUTF8(sessionPath) << ": " | |
| 227 << base::SysNSStringToUTF8([exception reason]); | |
| 228 return nil; | |
| 260 } | 229 } |
| 261 return window; | |
| 262 } | 230 } |
| 263 | 231 |
| 264 // Deletes the file containing the commands for the last session in the given | 232 // Deletes the file containing the commands for the last session in the given |
| 265 // browserState directory. | 233 // browserState directory. |
| 266 - (void)deleteLastSession:(NSString*)directory { | 234 - (void)deleteLastSession:(NSString*)directory { |
| 267 NSString* sessionFile = [self sessionFilePathForDirectory:directory]; | 235 NSString* sessionPath = [self sessionFilePathForDirectory:directory]; |
| 268 _taskRunner->PostTask( | 236 _taskRunner->PostTask( |
| 269 FROM_HERE, base::BindBlock(^{ | 237 FROM_HERE, base::BindBlockArc(^{ |
|
marq (ping after 24h)
2017/04/06 11:58:16
Should this use criticalClosure()?
sdefresne
2017/04/06 14:57:01
Not sure. This is called from the startup code to
marq (ping after 24h)
2017/04/06 16:15:56
I think the answer to my question is "no", then. ;
| |
| 270 base::ThreadRestrictions::AssertIOAllowed(); | 238 base::ThreadRestrictions::AssertIOAllowed(); |
| 271 NSFileManager* fileManager = [NSFileManager defaultManager]; | 239 NSFileManager* fileManager = [NSFileManager defaultManager]; |
| 272 if (![fileManager fileExistsAtPath:sessionFile]) | 240 if (![fileManager fileExistsAtPath:sessionPath]) |
| 273 return; | 241 return; |
| 274 if (![fileManager removeItemAtPath:sessionFile error:nil]) | 242 |
| 275 CHECK(false) << "Unable to delete session file."; | 243 NSError* error = nil; |
| 244 if (![fileManager removeItemAtPath:sessionPath error:nil]) | |
| 245 CHECK(false) << "Unable to delete session file: " | |
| 246 << base::SysNSStringToUTF8(sessionPath) << ": " | |
| 247 << base::SysNSStringToUTF8([error description]); | |
| 276 })); | 248 })); |
| 277 } | 249 } |
| 278 | 250 |
| 279 @end | 251 @end |
| OLD | NEW |