Commit d4470ca3 authored by maxbogue's avatar maxbogue Committed by Commit bot

On Android, save the Directory when the app is backgrounded.

Because we don't know when the app will be killed, the current
time before Directory saves can result in lost data. This
change uses the app getting backgrounded as a signal that we
might be killed soon and triggers a Directory::SaveChanges().

BUG=395233

Review URL: https://codereview.chromium.org/551843003

Cr-Commit-Position: refs/heads/master@{#297547}
parent 8bac2728
......@@ -4,9 +4,13 @@
package org.chromium.chrome.browser.sync;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.ApplicationStatus.ActivityStateListener;
import org.chromium.base.CalledByNative;
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
......@@ -90,6 +94,16 @@ public class ProfileSyncService {
// been set up, but ProfileSyncService::Startup() won't be called until
// credentials are available.
mNativeProfileSyncServiceAndroid = nativeInit();
// When the application gets paused, tell sync to flush the directory to disk.
ApplicationStatus.registerStateListenerForAllActivities(new ActivityStateListener() {
@Override
public void onActivityStateChange(Activity activity, int newState) {
if (newState == ActivityState.PAUSED) {
flushDirectory();
}
}
});
}
@CalledByNative
......@@ -494,6 +508,13 @@ public class ProfileSyncService {
nativeDisableSync(mNativeProfileSyncServiceAndroid);
}
/**
* Flushes the sync directory.
*/
public void flushDirectory() {
nativeFlushDirectory(mNativeProfileSyncServiceAndroid);
}
/**
* Returns the time when the last sync cycle was completed.
*
......@@ -541,6 +562,7 @@ public class ProfileSyncService {
private native long nativeInit();
private native void nativeEnableSync(long nativeProfileSyncServiceAndroid);
private native void nativeDisableSync(long nativeProfileSyncServiceAndroid);
private native void nativeFlushDirectory(long nativeProfileSyncServiceAndroid);
private native void nativeSignInSync(long nativeProfileSyncServiceAndroid);
private native void nativeSignOutSync(long nativeProfileSyncServiceAndroid);
private native boolean nativeSetSyncSessionsId(
......
......@@ -9,6 +9,8 @@ import android.app.Activity;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.identity.UniqueIdentificationGenerator;
......@@ -101,6 +103,22 @@ public class SyncTest extends ChromeShellTestBase {
assertTrue("Couldn't get about info.", gotInfo);
}
@LargeTest
@Feature({"Sync"})
public void testFlushDirectoryDoesntBreakSync() throws Throwable {
setupTestAccountAndSignInToSync(FOREIGN_SESSION_TEST_MACHINE_ID);
final Activity activity = getActivity();
runTestOnUiThread(new Runnable() {
@Override
public void run() {
ApplicationStatus.onStateChangeForTesting(activity, ActivityState.PAUSED);
}
});
// TODO(pvalenzuela): When available, check that sync is still functional.
}
@LargeTest
@Feature({"Sync"})
public void testAboutSyncPageDisplaysCurrentSyncStatus() throws InterruptedException {
......
......@@ -185,6 +185,9 @@ class SyncBackendHost : public sync_driver::BackendDataTypeConfigurer {
virtual void GetModelSafeRoutingInfo(
syncer::ModelSafeRoutingInfo* out) const = 0;
// Send a message to the sync thread to persist the Directory to disk.
virtual void FlushDirectory() const = 0;
// Requests that the backend forward to the fronent any protocol events in
// its buffer and begin forwarding automatically from now on. Repeated calls
// to this function may result in the same events being emitted several
......
......@@ -239,6 +239,11 @@ class SyncBackendHostCore
base::Callback<void(const std::vector<syncer::ModelType>& type,
ScopedVector<base::ListValue>) > callback);
// Tell the sync manager to persist its state by writing to disk.
// Called on the sync thread, both by a timer and, on Android, when the
// application is backgrounded.
void SaveChanges();
private:
friend class base::RefCountedThreadSafe<SyncBackendHostCore>;
friend class SyncBackendHostForProfileSyncTest;
......@@ -251,13 +256,6 @@ class SyncBackendHostCore
// be run on; the host's |registrar_->sync_thread()|.
void StartSavingChanges();
// Invoked periodically to tell the syncapi to persist its state
// by writing to disk.
// This is called from the thread we were created on (which is sync thread),
// using a repeating timer that is kicked off as soon as the SyncManager
// tells us it completed initialization.
void SaveChanges();
// Name used for debugging.
const std::string name_;
......
......@@ -507,6 +507,12 @@ void SyncBackendHostImpl::GetModelSafeRoutingInfo(
}
}
void SyncBackendHostImpl::FlushDirectory() const {
DCHECK(initialized());
registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
base::Bind(&SyncBackendHostCore::SaveChanges, core_));
}
void SyncBackendHostImpl::RequestBufferedProtocolEventsAndEnableForwarding() {
registrar_->sync_thread()->message_loop()->PostTask(
FROM_HERE,
......
......@@ -127,6 +127,7 @@ class SyncBackendHostImpl
const syncer::BaseTransaction* trans) const OVERRIDE;
virtual void GetModelSafeRoutingInfo(
syncer::ModelSafeRoutingInfo* out) const OVERRIDE;
virtual void FlushDirectory() const OVERRIDE;
virtual void RequestBufferedProtocolEventsAndEnableForwarding() OVERRIDE;
virtual void DisableProtocolEventForwarding() OVERRIDE;
virtual void EnableDirectoryTypeDebugInfoForwarding() OVERRIDE;
......
......@@ -111,6 +111,8 @@ bool SyncBackendHostMock::IsCryptographerReady(
void SyncBackendHostMock::GetModelSafeRoutingInfo(
syncer::ModelSafeRoutingInfo* out) const {}
void SyncBackendHostMock::FlushDirectory() const {}
base::MessageLoop* SyncBackendHostMock::GetSyncLoopForTesting() {
return NULL;
}
......
......@@ -94,6 +94,8 @@ class SyncBackendHostMock : public SyncBackendHost {
virtual void GetModelSafeRoutingInfo(
syncer::ModelSafeRoutingInfo* out) const OVERRIDE;
virtual void FlushDirectory() const OVERRIDE;
virtual void RequestBufferedProtocolEventsAndEnableForwarding() OVERRIDE;
virtual void DisableProtocolEventForwarding() OVERRIDE;
......
......@@ -2707,3 +2707,10 @@ bool ProfileSyncService::NeedBackup() const {
base::Time ProfileSyncService::GetDeviceBackupTimeForTesting() const {
return device_info_sync_service_->GetLocalDeviceBackupTime();
}
void ProfileSyncService::FlushDirectory() const {
// backend_initialized_ implies backend_ isn't NULL and the manager exists.
// If sync is not initialized yet, we fail silently.
if (backend_initialized_)
backend_->FlushDirectory();
}
......@@ -789,6 +789,11 @@ class ProfileSyncService : public ProfileSyncServiceBase,
base::Time GetDeviceBackupTimeForTesting() const;
// This triggers a Directory::SaveChanges() call on the sync thread.
// It should be used to persist data to disk when the process might be
// killed in the near future.
void FlushDirectory() const;
protected:
// Helper to configure the priority data types.
void ConfigurePriorityDataTypes();
......
......@@ -141,6 +141,11 @@ void ProfileSyncServiceAndroid::SignOutSync(JNIEnv* env, jobject) {
sync_prefs_->SetStartSuppressed(false);
}
void ProfileSyncServiceAndroid::FlushDirectory(JNIEnv* env, jobject) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
sync_service_->FlushDirectory();
}
ScopedJavaLocalRef<jstring> ProfileSyncServiceAndroid::QuerySyncStatusSummary(
JNIEnv* env, jobject) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
......
......@@ -46,6 +46,9 @@ class ProfileSyncServiceAndroid : public ProfileSyncServiceObserver {
// Called from Java when the user signs out of Chrome
void SignOutSync(JNIEnv* env, jobject obj);
// Called from Java when we get a signal that the Directory should be saved.
void FlushDirectory(JNIEnv* env, jobject obj);
// Returns a string version of browser_sync::SyncBackendHost::StatusSummary
base::android::ScopedJavaLocalRef<jstring> QuerySyncStatusSummary(
JNIEnv* env, jobject obj);
......
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