Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Unified Diff: ios/chrome/browser/sessions/session_service.mm

Issue 2585233003: Upstream Chrome on iOS source code [2/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/sessions/session_service.mm
diff --git a/ios/chrome/browser/sessions/session_service.mm b/ios/chrome/browser/sessions/session_service.mm
new file mode 100644
index 0000000000000000000000000000000000000000..16f66347770dcd0e462307c0d7b6b3ac7a957dcf
--- /dev/null
+++ b/ios/chrome/browser/sessions/session_service.mm
@@ -0,0 +1,251 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/sessions/session_service.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/files/file_path.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/mac/foundation_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_restrictions.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/sessions/session_window.h"
+#import "ios/web/navigation/crw_session_certificate_policy_manager.h"
+#import "ios/web/navigation/crw_session_controller.h"
+#import "ios/web/navigation/crw_session_entry.h"
+#include "ios/web/public/web_thread.h"
+
+// When C++ exceptions are disabled, the C++ library defines |try| and
+// |catch| so as to allow exception-expecting C++ code to build properly when
+// language support for exceptions is not present. These macros interfere
+// with the use of |@try| and |@catch| in Objective-C files such as this one.
+// Undefine these macros here, after everything has been #included, since
+// there will be no C++ uses and only Objective-C uses from this point on.
+#undef try
+#undef catch
+
+const NSTimeInterval kSaveDelay = 2.5; // Value taken from Desktop Chrome.
+
+@interface SessionWindowUnarchiver () {
+ ios::ChromeBrowserState* _browserState;
+}
+
+@end
+
+@implementation SessionWindowUnarchiver
+
+@synthesize browserState = _browserState; // weak
+
+- (id)initForReadingWithData:(NSData*)data
+ browserState:(ios::ChromeBrowserState*)browserState {
+ if (self = [super initForReadingWithData:data]) {
+ _browserState = browserState;
+ }
+ return self;
+}
+
+@end
+
+@interface SessionServiceIOS () {
+ @private
+ // The SequencedTaskRunner on which File IO operations are performed.
+ scoped_refptr<base::SequencedTaskRunner> taskRunner_;
+
+ // Maps save directories to the pending SessionWindow for the delayed
+ // save behavior.
+ base::scoped_nsobject<NSMutableDictionary> pendingWindows_;
+}
+
+- (void)performSaveToDirectoryInBackground:(NSString*)directory;
+- (void)performSaveWindow:(SessionWindowIOS*)window
+ toDirectory:(NSString*)directory;
+@end
+
+@implementation SessionServiceIOS
+
++ (SessionServiceIOS*)sharedService {
+ static SessionServiceIOS* singleton = nil;
+ if (!singleton) {
+ singleton = [[[self class] alloc] init];
+ }
+ return singleton;
+}
+
+- (id)init {
+ self = [super init];
+ if (self) {
+ pendingWindows_.reset([[NSMutableDictionary alloc] init]);
+ auto pool = web::WebThread::GetBlockingPool();
+ taskRunner_ = pool->GetSequencedTaskRunner(pool->GetSequenceToken());
+ }
+ return self;
+}
+
+// Returns the path of the session file.
+- (NSString*)sessionFilePathForDirectory:(NSString*)directory {
+ return [directory stringByAppendingPathComponent:@"session.plist"];
+}
+
+// Do the work of saving on a background thread. Assumes |window| is threadsafe.
+- (void)performSaveToDirectoryInBackground:(NSString*)directory {
+ DCHECK(directory);
+ DCHECK([pendingWindows_ objectForKey:directory] != nil);
+ UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication]
+ beginBackgroundTaskWithExpirationHandler:^{
+ }];
+ DCHECK(identifier != UIBackgroundTaskInvalid);
+
+ // Put the window into a local var so it can be retained for the block, yet
+ // we can remove it from the dictionary to allow queuing another save.
+ SessionWindowIOS* localWindow =
+ [[pendingWindows_ objectForKey:directory] retain];
+ [pendingWindows_ removeObjectForKey:directory];
+
+ taskRunner_->PostTask(
+ FROM_HERE, base::BindBlock(^{
+ @try {
+ [self performSaveWindow:localWindow toDirectory:directory];
+ } @catch (NSException* e) {
+ // Do nothing.
+ }
+ [localWindow release];
+ [[UIApplication sharedApplication] endBackgroundTask:identifier];
+ }));
+}
+
+// Saves a SessionWindowIOS in a given directory. In case the directory doesn't
+// exists it will be automatically created.
+- (void)performSaveWindow:(SessionWindowIOS*)window
+ toDirectory:(NSString*)directory {
+ base::ThreadRestrictions::AssertIOAllowed();
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+ BOOL isDir;
+ if (![fileManager fileExistsAtPath:directory isDirectory:&isDir]) {
+ NSError* error = nil;
+ BOOL result = [fileManager createDirectoryAtPath:directory
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:&error];
+ DCHECK(result);
+ if (!result) {
+ DLOG(ERROR) << "Error creating destination dir: "
+ << base::SysNSStringToUTF8([error description]);
+ return;
+ }
+ } else {
+ DCHECK(isDir);
+ if (!isDir) {
+ DLOG(ERROR) << "Destination Directory already exists and is a file";
+ return;
+ }
+ }
+
+ NSString* filename = [self sessionFilePathForDirectory:directory];
+ if (filename) {
+ BOOL result = [NSKeyedArchiver archiveRootObject:window toFile:filename];
+ DCHECK(result);
+ if (!result)
+ DLOG(ERROR) << "Error writing session file to " << filename;
+ // Encrypt the session file (mostly for Incognito, but can't hurt to
+ // always do it).
+ NSDictionary* attributeDict =
+ [NSDictionary dictionaryWithObject:NSFileProtectionComplete
+ forKey:NSFileProtectionKey];
+ NSError* error = nil;
+ BOOL success = [[NSFileManager defaultManager] setAttributes:attributeDict
+ ofItemAtPath:filename
+ error:&error];
+ if (!success) {
+ DLOG(ERROR) << "Error encrypting session file"
+ << base::SysNSStringToUTF8([error description]);
+ }
+ }
+}
+
+- (void)saveWindow:(SessionWindowIOS*)window
+ forBrowserState:(ios::ChromeBrowserState*)browserState
+ immediately:(BOOL)immediately {
+ NSString* stashPath =
+ base::SysUTF8ToNSString(browserState->GetStatePath().value());
+ // If there's an existing session window for |stashPath|, clear it before it's
+ // replaced.
+ SessionWindowIOS* pendingSession = base::mac::ObjCCast<SessionWindowIOS>(
+ [pendingWindows_ objectForKey:stashPath]);
+ [pendingSession clearSessions];
+ // Set |window| as the pending save for |stashPath|.
+ [pendingWindows_ setObject:window forKey:stashPath];
+ if (immediately) {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ [self performSaveToDirectoryInBackground:stashPath];
+ } else if (!pendingSession) {
+ // If there wasn't previously a delayed save pending for |stashPath}|,
+ // enqueue one now.
+ [self performSelector:@selector(performSaveToDirectoryInBackground:)
+ withObject:stashPath
+ afterDelay:kSaveDelay];
+ }
+}
+
+- (SessionWindowIOS*)loadWindowForBrowserState:
+ (ios::ChromeBrowserState*)browserState {
+ NSString* stashPath =
+ base::SysUTF8ToNSString(browserState->GetStatePath().value());
+ SessionWindowIOS* window =
+ [self loadWindowFromPath:[self sessionFilePathForDirectory:stashPath]
+ forBrowserState:browserState];
+ return window;
+}
+
+- (SessionWindowIOS*)loadWindowFromPath:(NSString*)path
+ forBrowserState:(ios::ChromeBrowserState*)browserState {
+ // HACK: Handle the case where we had to change the class name of a persisted
+ // class on disk.
+ [SessionWindowUnarchiver setClass:[CRWSessionCertificatePolicyManager class]
+ forClassName:@"SessionCertificatePolicyManager"];
+ [SessionWindowUnarchiver setClass:[CRWSessionController class]
+ forClassName:@"SessionController"];
+ [SessionWindowUnarchiver setClass:[CRWSessionEntry class]
+ forClassName:@"SessionEntry"];
+ // TODO(crbug.com/661633): Remove this hack.
+ [SessionWindowUnarchiver setClass:[SessionWindowIOS class]
+ forClassName:@"SessionWindow"];
+ SessionWindowIOS* window = nil;
+ @try {
+ NSData* data = [NSData dataWithContentsOfFile:path];
+ if (data) {
+ base::scoped_nsobject<SessionWindowUnarchiver> unarchiver([
+ [SessionWindowUnarchiver alloc] initForReadingWithData:data
+ browserState:browserState]);
+ window = [[[unarchiver decodeObjectForKey:@"root"] retain] autorelease];
+ }
+ } @catch (NSException* exception) {
+ DLOG(ERROR) << "Error loading session.plist";
+ }
+ return window;
+}
+
+// Deletes the file containing the commands for the last session in the given
+// browserState directory.
+- (void)deleteLastSession:(NSString*)directory {
+ NSString* sessionFile = [self sessionFilePathForDirectory:directory];
+ taskRunner_->PostTask(
+ FROM_HERE, base::BindBlock(^{
+ base::ThreadRestrictions::AssertIOAllowed();
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+ if (![fileManager fileExistsAtPath:sessionFile])
+ return;
+ if (![fileManager removeItemAtPath:sessionFile error:nil])
+ CHECK(false) << "Unable to delete session file.";
+ }));
+}
+
+@end
« no previous file with comments | « ios/chrome/browser/sessions/session_service.h ('k') | ios/chrome/browser/sessions/session_service_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698