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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/sessions/session_service.h"
6
7 #import <UIKit/UIKit.h>
8
9 #include "base/files/file_path.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/mac/bind_objc_block.h"
13 #include "base/mac/foundation_util.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "base/synchronization/lock.h"
18 #include "base/threading/sequenced_worker_pool.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
21 #import "ios/chrome/browser/sessions/session_window.h"
22 #import "ios/web/navigation/crw_session_certificate_policy_manager.h"
23 #import "ios/web/navigation/crw_session_controller.h"
24 #import "ios/web/navigation/crw_session_entry.h"
25 #include "ios/web/public/web_thread.h"
26
27 // 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
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.
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.
33 #undef try
34 #undef catch
35
36 const NSTimeInterval kSaveDelay = 2.5; // Value taken from Desktop Chrome.
37
38 @interface SessionWindowUnarchiver () {
39 ios::ChromeBrowserState* _browserState;
40 }
41
42 @end
43
44 @implementation SessionWindowUnarchiver
45
46 @synthesize browserState = _browserState; // weak
47
48 - (id)initForReadingWithData:(NSData*)data
49 browserState:(ios::ChromeBrowserState*)browserState {
50 if (self = [super initForReadingWithData:data]) {
51 _browserState = browserState;
52 }
53 return self;
54 }
55
56 @end
57
58 @interface SessionServiceIOS () {
59 @private
60 // The SequencedTaskRunner on which File IO operations are performed.
61 scoped_refptr<base::SequencedTaskRunner> taskRunner_;
62
63 // Maps save directories to the pending SessionWindow for the delayed
64 // save behavior.
65 base::scoped_nsobject<NSMutableDictionary> pendingWindows_;
66 }
67
68 - (void)performSaveToDirectoryInBackground:(NSString*)directory;
69 - (void)performSaveWindow:(SessionWindowIOS*)window
70 toDirectory:(NSString*)directory;
71 @end
72
73 @implementation SessionServiceIOS
74
75 + (SessionServiceIOS*)sharedService {
76 static SessionServiceIOS* singleton = nil;
77 if (!singleton) {
78 singleton = [[[self class] alloc] init];
79 }
80 return singleton;
81 }
82
83 - (id)init {
84 self = [super init];
85 if (self) {
86 pendingWindows_.reset([[NSMutableDictionary alloc] init]);
87 auto pool = web::WebThread::GetBlockingPool();
88 taskRunner_ = pool->GetSequencedTaskRunner(pool->GetSequenceToken());
89 }
90 return self;
91 }
92
93 // Returns the path of the session file.
94 - (NSString*)sessionFilePathForDirectory:(NSString*)directory {
95 return [directory stringByAppendingPathComponent:@"session.plist"];
96 }
97
98 // Do the work of saving on a background thread. Assumes |window| is threadsafe.
99 - (void)performSaveToDirectoryInBackground:(NSString*)directory {
100 DCHECK(directory);
101 DCHECK([pendingWindows_ objectForKey:directory] != nil);
102 UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication]
103 beginBackgroundTaskWithExpirationHandler:^{
104 }];
105 DCHECK(identifier != UIBackgroundTaskInvalid);
106
107 // 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.
109 SessionWindowIOS* localWindow =
110 [[pendingWindows_ objectForKey:directory] retain];
111 [pendingWindows_ removeObjectForKey:directory];
112
113 taskRunner_->PostTask(
114 FROM_HERE, base::BindBlock(^{
115 @try {
116 [self performSaveWindow:localWindow toDirectory:directory];
117 } @catch (NSException* e) {
118 // Do nothing.
119 }
120 [localWindow release];
121 [[UIApplication sharedApplication] endBackgroundTask:identifier];
122 }));
123 }
124
125 // Saves a SessionWindowIOS in a given directory. In case the directory doesn't
126 // exists it will be automatically created.
127 - (void)performSaveWindow:(SessionWindowIOS*)window
128 toDirectory:(NSString*)directory {
129 base::ThreadRestrictions::AssertIOAllowed();
130 NSFileManager* fileManager = [NSFileManager defaultManager];
131 BOOL isDir;
132 if (![fileManager fileExistsAtPath:directory isDirectory:&isDir]) {
133 NSError* error = nil;
134 BOOL result = [fileManager createDirectoryAtPath:directory
135 withIntermediateDirectories:YES
136 attributes:nil
137 error:&error];
138 DCHECK(result);
139 if (!result) {
140 DLOG(ERROR) << "Error creating destination dir: "
141 << base::SysNSStringToUTF8([error description]);
142 return;
143 }
144 } else {
145 DCHECK(isDir);
146 if (!isDir) {
147 DLOG(ERROR) << "Destination Directory already exists and is a file";
148 return;
149 }
150 }
151
152 NSString* filename = [self sessionFilePathForDirectory:directory];
153 if (filename) {
154 BOOL result = [NSKeyedArchiver archiveRootObject:window toFile:filename];
155 DCHECK(result);
156 if (!result)
157 DLOG(ERROR) << "Error writing session file to " << filename;
158 // Encrypt the session file (mostly for Incognito, but can't hurt to
159 // always do it).
160 NSDictionary* attributeDict =
161 [NSDictionary dictionaryWithObject:NSFileProtectionComplete
162 forKey:NSFileProtectionKey];
163 NSError* error = nil;
164 BOOL success = [[NSFileManager defaultManager] setAttributes:attributeDict
165 ofItemAtPath:filename
166 error:&error];
167 if (!success) {
168 DLOG(ERROR) << "Error encrypting session file"
169 << base::SysNSStringToUTF8([error description]);
170 }
171 }
172 }
173
174 - (void)saveWindow:(SessionWindowIOS*)window
175 forBrowserState:(ios::ChromeBrowserState*)browserState
176 immediately:(BOOL)immediately {
177 NSString* stashPath =
178 base::SysUTF8ToNSString(browserState->GetStatePath().value());
179 // If there's an existing session window for |stashPath|, clear it before it's
180 // replaced.
181 SessionWindowIOS* pendingSession = base::mac::ObjCCast<SessionWindowIOS>(
182 [pendingWindows_ objectForKey:stashPath]);
183 [pendingSession clearSessions];
184 // Set |window| as the pending save for |stashPath|.
185 [pendingWindows_ setObject:window forKey:stashPath];
186 if (immediately) {
187 [NSObject cancelPreviousPerformRequestsWithTarget:self];
188 [self performSaveToDirectoryInBackground:stashPath];
189 } else if (!pendingSession) {
190 // If there wasn't previously a delayed save pending for |stashPath}|,
191 // enqueue one now.
192 [self performSelector:@selector(performSaveToDirectoryInBackground:)
193 withObject:stashPath
194 afterDelay:kSaveDelay];
195 }
196 }
197
198 - (SessionWindowIOS*)loadWindowForBrowserState:
199 (ios::ChromeBrowserState*)browserState {
200 NSString* stashPath =
201 base::SysUTF8ToNSString(browserState->GetStatePath().value());
202 SessionWindowIOS* window =
203 [self loadWindowFromPath:[self sessionFilePathForDirectory:stashPath]
204 forBrowserState:browserState];
205 return window;
206 }
207
208 - (SessionWindowIOS*)loadWindowFromPath:(NSString*)path
209 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:[CRWSessionController class]
215 forClassName:@"SessionController"];
216 [SessionWindowUnarchiver setClass:[CRWSessionEntry class]
217 forClassName:@"SessionEntry"];
218 // TODO(crbug.com/661633): Remove this hack.
219 [SessionWindowUnarchiver setClass:[SessionWindowIOS class]
220 forClassName:@"SessionWindow"];
221 SessionWindowIOS* window = nil;
222 @try {
223 NSData* data = [NSData dataWithContentsOfFile:path];
224 if (data) {
225 base::scoped_nsobject<SessionWindowUnarchiver> unarchiver([
226 [SessionWindowUnarchiver alloc] initForReadingWithData:data
227 browserState:browserState]);
228 window = [[[unarchiver decodeObjectForKey:@"root"] retain] autorelease];
229 }
230 } @catch (NSException* exception) {
231 DLOG(ERROR) << "Error loading session.plist";
232 }
233 return window;
234 }
235
236 // Deletes the file containing the commands for the last session in the given
237 // browserState directory.
238 - (void)deleteLastSession:(NSString*)directory {
239 NSString* sessionFile = [self sessionFilePathForDirectory:directory];
240 taskRunner_->PostTask(
241 FROM_HERE, base::BindBlock(^{
242 base::ThreadRestrictions::AssertIOAllowed();
243 NSFileManager* fileManager = [NSFileManager defaultManager];
244 if (![fileManager fileExistsAtPath:sessionFile])
245 return;
246 if (![fileManager removeItemAtPath:sessionFile error:nil])
247 CHECK(false) << "Unable to delete session file.";
248 }));
249 }
250
251 @end
OLDNEW
« 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