Commit 5fbebad5 authored by Sylvain Defresne's avatar Sylvain Defresne Committed by Commit Bot

[ios] Change SessionServiceIOS API to avoid useless work.

If multiple call to -saveSession:directory:immediately: are made
in quick succession, the SessionIOS objects are created to be
immediately destroyed when the scheduled save is cancelled.

Change the SessionServiceIOS API to instead take a block creating
the SessionIOS instance and invoke it on the main thread, before
requesting that the data be serialised to the disk (by sending a
task on IO thread).

BUG=725539

Change-Id: I82b42d2b46baf03a7280e60185973c635dc164a2
Reviewed-on: https://chromium-review.googlesource.com/513929
Commit-Queue: Sylvain Defresne <sdefresne@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#476254}
parent daef9d44
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
@class SessionIOS; @class SessionIOS;
using SessionIOSFactory = SessionIOS* (^)();
// A singleton service for saving the current session. Can either save on a // A singleton service for saving the current session. Can either save on a
// delay or immediately. Saving is always performed on a separate thread. // delay or immediately. Saving is always performed on a separate thread.
@interface SessionServiceIOS : NSObject @interface SessionServiceIOS : NSObject
...@@ -24,12 +26,12 @@ ...@@ -24,12 +26,12 @@
(const scoped_refptr<base::SequencedTaskRunner>&)taskRunner (const scoped_refptr<base::SequencedTaskRunner>&)taskRunner
NS_DESIGNATED_INITIALIZER; NS_DESIGNATED_INITIALIZER;
// Saves the session represented by |session| to |directory|. If |immediately| // Saves the session returned by |factory| to |directory|. If |immediately|
// is NO, the save is done after a delay. If another call is pending, this one // is NO, the save is done after a delay. If another call is pending, this one
// is ignored. If YES, the save is done now, cancelling any pending calls. // is ignored. If YES, the save is done now, cancelling any pending calls.
// Either way, the save is done on a separate thread to avoid blocking the UI // Either way, the save is done on a separate thread to avoid blocking the UI
// thread. // thread.
- (void)saveSession:(SessionIOS*)sessionWindow - (void)saveSession:(SessionIOSFactory)factory
directory:(NSString*)directory directory:(NSString*)directory
immediately:(BOOL)immediately; immediately:(BOOL)immediately;
......
...@@ -74,7 +74,7 @@ NSString* const kRootObjectKey = @"root"; // Key for the root object. ...@@ -74,7 +74,7 @@ NSString* const kRootObjectKey = @"root"; // Key for the root object.
scoped_refptr<base::SequencedTaskRunner> _taskRunner; scoped_refptr<base::SequencedTaskRunner> _taskRunner;
// Maps session path to the pending session for the delayed save behaviour. // Maps session path to the pending session for the delayed save behaviour.
NSMutableDictionary<NSString*, SessionIOS*>* _pendingSessions; NSMutableDictionary<NSString*, SessionIOSFactory>* _pendingSessions;
} }
#pragma mark - NSObject overrides #pragma mark - NSObject overrides
...@@ -108,12 +108,12 @@ NSString* const kRootObjectKey = @"root"; // Key for the root object. ...@@ -108,12 +108,12 @@ NSString* const kRootObjectKey = @"root"; // Key for the root object.
return self; return self;
} }
- (void)saveSession:(SessionIOS*)session - (void)saveSession:(SessionIOSFactory)factory
directory:(NSString*)directory directory:(NSString*)directory
immediately:(BOOL)immediately { immediately:(BOOL)immediately {
NSString* sessionPath = [[self class] sessionPathForDirectory:directory]; NSString* sessionPath = [[self class] sessionPathForDirectory:directory];
BOOL hadPendingSession = [_pendingSessions objectForKey:sessionPath] != nil; BOOL hadPendingSession = [_pendingSessions objectForKey:sessionPath] != nil;
[_pendingSessions setObject:session forKey:sessionPath]; [_pendingSessions setObject:factory forKey:sessionPath];
if (immediately) { if (immediately) {
[NSObject cancelPreviousPerformRequestsWithTarget:self]; [NSObject cancelPreviousPerformRequestsWithTarget:self];
[self performSaveToPathInBackground:sessionPath]; [self performSaveToPathInBackground:sessionPath];
...@@ -194,8 +194,9 @@ NSString* const kRootObjectKey = @"root"; // Key for the root object. ...@@ -194,8 +194,9 @@ NSString* const kRootObjectKey = @"root"; // Key for the root object.
// Serialize to NSData on the main thread to avoid accessing potentially // Serialize to NSData on the main thread to avoid accessing potentially
// non-threadsafe objects on a background thread. // non-threadsafe objects on a background thread.
SessionIOS* session = [_pendingSessions objectForKey:sessionPath]; SessionIOSFactory factory = [_pendingSessions objectForKey:sessionPath];
[_pendingSessions removeObjectForKey:sessionPath]; [_pendingSessions removeObjectForKey:sessionPath];
SessionIOS* session = factory();
@try { @try {
NSData* sessionData = [NSKeyedArchiver archivedDataWithRootObject:session]; NSData* sessionData = [NSKeyedArchiver archivedDataWithRootObject:session];
......
...@@ -70,21 +70,24 @@ class SessionServiceTest : public PlatformTest { ...@@ -70,21 +70,24 @@ class SessionServiceTest : public PlatformTest {
return base::SysUTF8ToNSString(session_path.AsUTF8Unsafe()); return base::SysUTF8ToNSString(session_path.AsUTF8Unsafe());
} }
// Create a SessionIOS corresponding to |window_count| windows each with // Create a SessionIOSFactory creating a SessionIOS with |window_count|
// |tab_count| tabs. // windows each with |tab_count| tabs.
SessionIOS* CreateSession(NSUInteger window_count, NSUInteger tab_count) { SessionIOSFactory CreateSessionFactory(NSUInteger window_count,
NSMutableArray<SessionWindowIOS*>* windows = [NSMutableArray array]; NSUInteger tab_count) {
while (windows.count < window_count) { return ^{
NSMutableArray<CRWSessionStorage*>* tabs = [NSMutableArray array]; NSMutableArray<SessionWindowIOS*>* windows = [NSMutableArray array];
while (tabs.count < tab_count) { while (windows.count < window_count) {
[tabs addObject:[[CRWSessionStorage alloc] init]]; NSMutableArray<CRWSessionStorage*>* tabs = [NSMutableArray array];
while (tabs.count < tab_count) {
[tabs addObject:[[CRWSessionStorage alloc] init]];
}
[windows addObject:[[SessionWindowIOS alloc]
initWithSessions:[tabs copy]
selectedIndex:(tabs.count ? tabs.count - 1
: NSNotFound)]];
} }
[windows addObject:[[SessionWindowIOS alloc] return [[SessionIOS alloc] initWithWindows:[windows copy]];
initWithSessions:[tabs copy] };
selectedIndex:(tabs.count ? tabs.count - 1
: NSNotFound)]];
}
return [[SessionIOS alloc] initWithWindows:[windows copy]];
} }
SessionServiceIOS* session_service() { return session_service_; } SessionServiceIOS* session_service() { return session_service_; }
...@@ -106,7 +109,7 @@ TEST_F(SessionServiceTest, SessionPathForDirectory) { ...@@ -106,7 +109,7 @@ TEST_F(SessionServiceTest, SessionPathForDirectory) {
} }
TEST_F(SessionServiceTest, SaveSessionWindowToPath) { TEST_F(SessionServiceTest, SaveSessionWindowToPath) {
[session_service() saveSession:CreateSession(0u, 0u) [session_service() saveSession:CreateSessionFactory(0u, 0u)
directory:directory() directory:directory()
immediately:YES]; immediately:YES];
...@@ -125,7 +128,7 @@ TEST_F(SessionServiceTest, SaveSessionWindowToPathDirectoryExists) { ...@@ -125,7 +128,7 @@ TEST_F(SessionServiceTest, SaveSessionWindowToPathDirectoryExists) {
attributes:nil attributes:nil
error:nullptr]); error:nullptr]);
[session_service() saveSession:CreateSession(0u, 0u) [session_service() saveSession:CreateSessionFactory(0u, 0u)
directory:directory() directory:directory()
immediately:YES]; immediately:YES];
...@@ -145,7 +148,7 @@ TEST_F(SessionServiceTest, LoadSessionFromDirectoryNoFile) { ...@@ -145,7 +148,7 @@ TEST_F(SessionServiceTest, LoadSessionFromDirectoryNoFile) {
} }
TEST_F(SessionServiceTest, LoadSessionFromDirectory) { TEST_F(SessionServiceTest, LoadSessionFromDirectory) {
[session_service() saveSession:CreateSession(2u, 1u) [session_service() saveSession:CreateSessionFactory(2u, 1u)
directory:directory() directory:directory()
immediately:YES]; immediately:YES];
...@@ -164,7 +167,7 @@ TEST_F(SessionServiceTest, LoadSessionFromDirectory) { ...@@ -164,7 +167,7 @@ TEST_F(SessionServiceTest, LoadSessionFromDirectory) {
} }
TEST_F(SessionServiceTest, LoadSessionFromPath) { TEST_F(SessionServiceTest, LoadSessionFromPath) {
[session_service() saveSession:CreateSession(2u, 1u) [session_service() saveSession:CreateSessionFactory(2u, 1u)
directory:directory() directory:directory()
immediately:YES]; immediately:YES];
......
...@@ -19,11 +19,11 @@ ...@@ -19,11 +19,11 @@
return [super initWithTaskRunner:base::ThreadTaskRunnerHandle::Get()]; return [super initWithTaskRunner:base::ThreadTaskRunnerHandle::Get()];
} }
- (void)saveSession:(SessionIOS*)session - (void)saveSession:(SessionIOSFactory)factory
directory:(NSString*)directory directory:(NSString*)directory
immediately:(BOOL)immediately { immediately:(BOOL)immediately {
NSString* sessionPath = [[self class] sessionPathForDirectory:directory]; NSString* sessionPath = [[self class] sessionPathForDirectory:directory];
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:session]; NSData* data = [NSKeyedArchiver archivedDataWithRootObject:factory()];
if (self.performIO) if (self.performIO)
[self performSaveSessionData:data sessionPath:sessionPath]; [self performSaveSessionData:data sessionPath:sessionPath];
} }
......
...@@ -376,7 +376,11 @@ std::unique_ptr<web::WebState> CreateWebState( ...@@ -376,7 +376,11 @@ std::unique_ptr<web::WebState> CreateWebState(
return; return;
NSString* statePath = NSString* statePath =
base::SysUTF8ToNSString(_browserState->GetStatePath().AsUTF8Unsafe()); base::SysUTF8ToNSString(_browserState->GetStatePath().AsUTF8Unsafe());
[_sessionService saveSession:self.sessionForSaving __weak TabModel* weakSelf = self;
SessionIOSFactory sessionFactory = ^{
return weakSelf.sessionForSaving;
};
[_sessionService saveSession:sessionFactory
directory:statePath directory:statePath
immediately:immediately]; immediately:immediately];
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#import "ios/shared/chrome/browser/ui/browser_list/browser_list_session_service.h" #import "ios/shared/chrome/browser/ui/browser_list/browser_list_session_service.h"
#import "ios/web/public/web_state/web_state.h" #import "ios/web/public/web_state/web_state.h"
...@@ -54,6 +55,10 @@ class BrowserListSessionServiceImpl : public BrowserListSessionService { ...@@ -54,6 +55,10 @@ class BrowserListSessionServiceImpl : public BrowserListSessionService {
CreateWebStateCallback create_web_state_; CreateWebStateCallback create_web_state_;
std::unique_ptr<BrowserListObserver> observer_; std::unique_ptr<BrowserListObserver> observer_;
// Used to ensure that the block passed to SessionServiceIOS does not access
// this object once it has been destroyed.
base::WeakPtrFactory<BrowserListSessionServiceImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(BrowserListSessionServiceImpl); DISALLOW_COPY_AND_ASSIGN(BrowserListSessionServiceImpl);
}; };
......
...@@ -197,7 +197,8 @@ BrowserListSessionServiceImpl::BrowserListSessionServiceImpl( ...@@ -197,7 +197,8 @@ BrowserListSessionServiceImpl::BrowserListSessionServiceImpl(
: browser_list_(browser_list), : browser_list_(browser_list),
session_directory_([session_directory copy]), session_directory_([session_directory copy]),
session_service_(session_service), session_service_(session_service),
create_web_state_(create_web_state) { create_web_state_(create_web_state),
weak_factory_(this) {
DCHECK(browser_list_); DCHECK(browser_list_);
DCHECK(session_directory_); DCHECK(session_directory_);
DCHECK(session_service_); DCHECK(session_service_);
...@@ -269,15 +270,25 @@ void BrowserListSessionServiceImpl::ScheduleLastSessionDeletion() { ...@@ -269,15 +270,25 @@ void BrowserListSessionServiceImpl::ScheduleLastSessionDeletion() {
void BrowserListSessionServiceImpl::ScheduleSaveSession(bool immediately) { void BrowserListSessionServiceImpl::ScheduleSaveSession(bool immediately) {
DCHECK(browser_list_) << "ScheduleSaveSession called after Shutdown."; DCHECK(browser_list_) << "ScheduleSaveSession called after Shutdown.";
DCHECK_GE(browser_list_->count(), 0); DCHECK_GE(browser_list_->count(), 0);
const int count = browser_list_->count();
NSMutableArray<SessionWindowIOS*>* windows =
[NSMutableArray arrayWithCapacity:static_cast<NSUInteger>(count)];
for (int index = 0; index < count; ++index) {
Browser* browser = browser_list_->GetBrowserAtIndex(index);
[windows addObject:SerializeWebStateList(&browser->web_state_list())];
}
[session_service_ saveSession:[[SessionIOS alloc] initWithWindows:windows] base::WeakPtr<BrowserListSessionServiceImpl> weak_ptr =
weak_factory_.GetWeakPtr();
SessionIOSFactory session_factory = ^SessionIOS*() {
BrowserListSessionServiceImpl* service = weak_ptr.get();
if (!weak_ptr)
return nil;
const int count = service->browser_list_->count();
NSMutableArray<SessionWindowIOS*>* windows =
[NSMutableArray arrayWithCapacity:static_cast<NSUInteger>(count)];
for (int index = 0; index < count; ++index) {
Browser* browser = service->browser_list_->GetBrowserAtIndex(index);
[windows addObject:SerializeWebStateList(&browser->web_state_list())];
}
return [[SessionIOS alloc] initWithWindows:windows];
};
[session_service_ saveSession:session_factory
directory:session_directory_ directory:session_directory_
immediately:immediately]; immediately:immediately];
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment