Bug 709311 - Handle changed meta/global. r=rnewman, a=blocking-fennec

This commit is contained in:
Nick Alexander 2012-05-17 13:20:49 -07:00
Родитель 9a9d84392f
Коммит e1a6551162
9 изменённых файлов: 351 добавлений и 52 удалений

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -14,6 +14,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@ -49,6 +50,7 @@ import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
import org.mozilla.gecko.sync.stage.NoSuchStageException; import org.mozilla.gecko.sync.stage.NoSuchStageException;
import org.mozilla.gecko.sync.stage.PasswordsServerSyncStage; import org.mozilla.gecko.sync.stage.PasswordsServerSyncStage;
import org.mozilla.gecko.sync.stage.SyncClientsEngineStage; import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
import org.mozilla.gecko.sync.stage.UploadMetaGlobalStage;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -70,6 +72,11 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
private Context context; private Context context;
private ClientsDataDelegate clientsDelegate; private ClientsDataDelegate clientsDelegate;
/**
* Map from engine name to new settings for an updated meta/global record.
*/
public final Map<String, EngineSettings> enginesToUpdate = new HashMap<String, EngineSettings>();
/* /*
* Key accessors. * Key accessors.
*/ */
@ -218,6 +225,7 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
stages.put(Stage.syncHistory, new AndroidBrowserHistoryServerSyncStage(this)); stages.put(Stage.syncHistory, new AndroidBrowserHistoryServerSyncStage(this));
stages.put(Stage.syncFormHistory, new FormHistoryServerSyncStage(this)); stages.put(Stage.syncFormHistory, new FormHistoryServerSyncStage(this));
stages.put(Stage.uploadMetaGlobal, new UploadMetaGlobalStage(this));
stages.put(Stage.completed, new CompletedStage(this)); stages.put(Stage.completed, new CompletedStage(this));
this.stages = Collections.unmodifiableMap(stages); this.stages = Collections.unmodifiableMap(stages);
@ -355,6 +363,102 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
this.callback.handleSuccess(this); this.callback.handleSuccess(this);
} }
/**
* Record that an updated meta/global record should be uploaded with the given
* settings for the given engine.
*
* @param engineName engine to update.
* @param engineSettings new syncID and version.
*/
public void updateMetaGlobalWith(String engineName, EngineSettings engineSettings) {
enginesToUpdate.put(engineName, engineSettings);
}
public boolean hasUpdatedMetaGlobal() {
if (enginesToUpdate.isEmpty()) {
Logger.info(LOG_TAG, "Not uploading updated meta/global record since there are no engines requesting upload.");
return false;
}
if (Logger.logVerbose(LOG_TAG)) {
Logger.trace(LOG_TAG, "Uploading updated meta/global record since there are engines requesting upload: " +
Utils.toCommaSeparatedString(enginesToUpdate.keySet()));
}
return true;
}
public void updateMetaGlobalInPlace() {
ExtendedJSONObject engines = config.metaGlobal.getEngines();
for (Entry<String, EngineSettings> pair : enginesToUpdate.entrySet()) {
engines.put(pair.getKey(), pair.getValue().toJSONObject());
}
enginesToUpdate.clear();
}
/**
* Synchronously upload an updated meta/global.
* <p>
* All problems are logged and ignored.
*/
public void uploadUpdatedMetaGlobal() {
updateMetaGlobalInPlace();
Logger.debug(LOG_TAG, "Uploading updated meta/global record.");
final Object monitor = new Object();
Runnable doUpload = new Runnable() {
@Override
public void run() {
config.metaGlobal.upload(new MetaGlobalDelegate() {
@Override
public void handleSuccess(MetaGlobal global, SyncStorageResponse response) {
Logger.info(LOG_TAG, "Successfully uploaded updated meta/global record.");
synchronized (monitor) {
monitor.notify();
}
}
@Override
public void handleMissing(MetaGlobal global, SyncStorageResponse response) {
Logger.warn(LOG_TAG, "Got 404 missing uploading updated meta/global record; shouldn't happen. Ignoring.");
synchronized (monitor) {
monitor.notify();
}
}
@Override
public void handleFailure(SyncStorageResponse response) {
Logger.warn(LOG_TAG, "Failed to upload updated meta/global record; ignoring.");
synchronized (monitor) {
monitor.notify();
}
}
@Override
public void handleError(Exception e) {
Logger.warn(LOG_TAG, "Got exception trying to upload updated meta/global record; ignoring.", e);
synchronized (monitor) {
monitor.notify();
}
}
});
}
};
final Thread upload = new Thread(doUpload);
synchronized (monitor) {
try {
upload.start();
monitor.wait();
Logger.debug(LOG_TAG, "Uploaded updated meta/global record.");
} catch (InterruptedException e) {
Logger.error(LOG_TAG, "Uploading updated meta/global interrupted; continuing.");
}
}
}
public void abort(Exception e, String reason) { public void abort(Exception e, String reason) {
Logger.warn(LOG_TAG, "Aborting sync: " + reason, e); Logger.warn(LOG_TAG, "Aborting sync: " + reason, e);
uninstallAsHttpResponseObserver(); uninstallAsHttpResponseObserver();
@ -362,6 +466,12 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
if (existingBackoff > 0) { if (existingBackoff > 0) {
callback.requestBackoff(existingBackoff); callback.requestBackoff(existingBackoff);
} }
if (!(e instanceof HTTPFailureException)) {
// e is null, or we aborted for a non-HTTP reason; okay to upload new meta/global record.
if (this.hasUpdatedMetaGlobal()) {
this.uploadUpdatedMetaGlobal(); // Only logs errors; does not call abort.
}
}
this.callback.handleError(this, e); this.callback.handleError(this, e);
} }

Просмотреть файл

@ -94,8 +94,8 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
public void setFromRecord(CryptoRecord record) throws IllegalStateException, IOException, ParseException, NonObjectJSONException { public void setFromRecord(CryptoRecord record) throws IllegalStateException, IOException, ParseException, NonObjectJSONException {
Logger.info(LOG_TAG, "meta/global is " + record.payload.toJSONString()); Logger.info(LOG_TAG, "meta/global is " + record.payload.toJSONString());
this.storageVersion = (Long) record.payload.get("storageVersion"); this.storageVersion = (Long) record.payload.get("storageVersion");
this.engines = record.payload.getObject("engines");
this.syncID = (String) record.payload.get("syncID"); this.syncID = (String) record.payload.get("syncID");
setEngines(record.payload.getObject("engines"));
} }
public Long getStorageVersion() { public Long getStorageVersion() {
@ -111,6 +111,9 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
} }
public void setEngines(ExtendedJSONObject engines) { public void setEngines(ExtendedJSONObject engines) {
if (engines == null) {
engines = new ExtendedJSONObject();
}
this.engines = engines; this.engines = engines;
final int count = engines.size(); final int count = engines.size();
versions = new HashMap<String, Integer>(count); versions = new HashMap<String, Integer>(count);
@ -122,6 +125,7 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
recordEngineState(engineName, engineEntry); recordEngineState(engineName, engineEntry);
} catch (NonObjectJSONException e) { } catch (NonObjectJSONException e) {
Logger.error(LOG_TAG, "Engine field for " + engineName + " in meta/global is not an object."); Logger.error(LOG_TAG, "Engine field for " + engineName + " in meta/global is not an object.");
recordEngineState(engineName, new ExtendedJSONObject()); // Doesn't have a version or syncID, for example, so will be server wiped.
} }
} }
} }
@ -137,6 +141,22 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
if (engineEntry == null) { if (engineEntry == null) {
throw new IllegalArgumentException("engineEntry cannot be null."); throw new IllegalArgumentException("engineEntry cannot be null.");
} }
// Record syncID first, so that engines with bad versions are recorded.
try {
String syncID = engineEntry.getString("syncID");
if (syncID == null) {
Logger.warn(LOG_TAG, "No syncID for " + engineName + ". Recording exception.");
exceptions.put(engineName, new MetaGlobalMalformedSyncIDException());
}
syncIDs.put(engineName, syncID);
} catch (ClassCastException e) {
// Malformed syncID on the server. Wipe the server.
Logger.warn(LOG_TAG, "Malformed syncID " + engineEntry.get("syncID") +
" for " + engineName + ". Recording exception.");
exceptions.put(engineName, new MetaGlobalMalformedSyncIDException());
}
try { try {
Integer version = engineEntry.getIntegerSafely("version"); Integer version = engineEntry.getIntegerSafely("version");
Logger.trace(LOG_TAG, "Engine " + engineName + " has server version " + version); Logger.trace(LOG_TAG, "Engine " + engineName + " has server version " + version);
@ -156,20 +176,6 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
exceptions.put(engineName, new MetaGlobalMalformedVersionException()); exceptions.put(engineName, new MetaGlobalMalformedVersionException());
return; return;
} }
try {
String syncID = engineEntry.getString("syncID");
if (syncID == null) {
Logger.warn(LOG_TAG, "No syncID for " + engineName + ". Recording exception.");
exceptions.put(engineName, new MetaGlobalMalformedSyncIDException());
}
syncIDs.put(engineName, syncID);
} catch (ClassCastException e) {
// Malformed syncID on the server. Wipe the server.
Logger.warn(LOG_TAG, "Malformed syncID " + engineEntry.get("syncID") +
" for " + engineName + ". Recording exception.");
exceptions.put(engineName, new MetaGlobalException.MetaGlobalMalformedSyncIDException());
}
} }
/** /**
@ -201,18 +207,21 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
throw new IllegalArgumentException("engineSettings cannot be null."); throw new IllegalArgumentException("engineSettings cannot be null.");
} }
final String syncID = syncIDs.get(engineName); // First, see if we had a parsing problem.
if (syncID == null) {
throw new IllegalArgumentException("Unknown engine " + engineName);
}
final MetaGlobalException exception = exceptions.get(engineName); final MetaGlobalException exception = exceptions.get(engineName);
if (exception != null) { if (exception != null) {
throw exception; throw exception;
} }
final Integer version = versions.get(engineName); final String syncID = syncIDs.get(engineName);
if (syncID == null) {
// We have checked engineName against enabled engine names before this, so
// we should either have a syncID or an exception for this engine already.
throw new IllegalArgumentException("Unknown engine " + engineName);
}
// Since we don't have an exception, and we do have a syncID, we should have a version.
final Integer version = versions.get(engineName);
if (version > engineSettings.version) { if (version > engineSettings.version) {
// We're out of date. // We're out of date.
throw new MetaGlobalException.MetaGlobalStaleClientVersionException(version); throw new MetaGlobalException.MetaGlobalStaleClientVersionException(version);

Просмотреть файл

@ -44,7 +44,6 @@ import org.mozilla.gecko.sync.SyncConfiguration.ConfigurationBranch;
import org.mozilla.gecko.sync.repositories.RepositorySessionBundle; import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.util.Log;
public class SynchronizerConfiguration { public class SynchronizerConfiguration {
private static final String LOG_TAG = "SynczrConfiguration"; private static final String LOG_TAG = "SynczrConfiguration";
@ -63,14 +62,6 @@ public class SynchronizerConfiguration {
this.localBundle = localBundle; this.localBundle = localBundle;
} }
public String[] toStringValues() {
String[] out = new String[3];
out[0] = syncID;
out[1] = remoteBundle.toJSONString();
out[2] = localBundle.toJSONString();
return out;
}
// This should get partly shuffled back into SyncConfiguration, I think. // This should get partly shuffled back into SyncConfiguration, I think.
public void load(ConfigurationBranch config) throws NonObjectJSONException, IOException, ParseException { public void load(ConfigurationBranch config) throws NonObjectJSONException, IOException, ParseException {
if (config == null) { if (config == null) {
@ -89,7 +80,7 @@ public class SynchronizerConfiguration {
syncID = config.getString("syncID", null); syncID = config.getString("syncID", null);
remoteBundle = rB; remoteBundle = rB;
localBundle = lB; localBundle = lB;
Log.i(LOG_TAG, "Initialized SynchronizerConfiguration. syncID: " + syncID + ", remoteBundle: " + remoteBundle + ", localBundle: " + localBundle); Logger.debug(LOG_TAG, "Loaded SynchronizerConfiguration. syncID: " + syncID + ", remoteBundle: " + remoteBundle + ", localBundle: " + localBundle);
} }
public void persist(ConfigurationBranch config) { public void persist(ConfigurationBranch config) {
@ -105,5 +96,6 @@ public class SynchronizerConfiguration {
// Synchronous. // Synchronous.
editor.commit(); editor.commit();
Logger.debug(LOG_TAG, "Persisted SynchronizerConfiguration. syncID: " + syncID + ", remoteBundle: " + remoteBundle + ", localBundle: " + localBundle);
} }
} }

Просмотреть файл

@ -34,6 +34,8 @@ public interface GlobalSyncStage {
syncBookmarks("bookmarks"), syncBookmarks("bookmarks"),
syncHistory("history"), syncHistory("history"),
syncFormHistory("forms"), syncFormHistory("forms"),
uploadMetaGlobal,
completed; completed;
// Maintain a mapping from names ("bookmarks") to Stage enumerations (syncBookmarks). // Maintain a mapping from names ("bookmarks") to Stage enumerations (syncBookmarks).

Просмотреть файл

@ -9,6 +9,8 @@ import java.net.URISyntaxException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import org.json.simple.parser.ParseException; import org.json.simple.parser.ParseException;
import org.mozilla.gecko.sync.CredentialsSource;
import org.mozilla.gecko.sync.EngineSettings;
import org.mozilla.gecko.sync.GlobalSession; import org.mozilla.gecko.sync.GlobalSession;
import org.mozilla.gecko.sync.HTTPFailureException; import org.mozilla.gecko.sync.HTTPFailureException;
import org.mozilla.gecko.sync.Logger; import org.mozilla.gecko.sync.Logger;
@ -16,8 +18,14 @@ import org.mozilla.gecko.sync.MetaGlobalException;
import org.mozilla.gecko.sync.NoCollectionKeysSetException; import org.mozilla.gecko.sync.NoCollectionKeysSetException;
import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.NonObjectJSONException;
import org.mozilla.gecko.sync.SynchronizerConfiguration; import org.mozilla.gecko.sync.SynchronizerConfiguration;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.crypto.KeyBundle; import org.mozilla.gecko.sync.crypto.KeyBundle;
import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepository; import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepository;
import org.mozilla.gecko.sync.net.BaseResource;
import org.mozilla.gecko.sync.net.SyncStorageRequest;
import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
import org.mozilla.gecko.sync.net.SyncStorageResponse;
import org.mozilla.gecko.sync.repositories.InactiveSessionException; import org.mozilla.gecko.sync.repositories.InactiveSessionException;
import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException; import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
import org.mozilla.gecko.sync.repositories.RecordFactory; import org.mozilla.gecko.sync.repositories.RecordFactory;
@ -63,9 +71,30 @@ public abstract class ServerSyncStage implements
* @throws MetaGlobalException * @throws MetaGlobalException
*/ */
protected boolean isEnabled() throws MetaGlobalException { protected boolean isEnabled() throws MetaGlobalException {
// TODO: pass EngineSettings here to check syncID and storage version. EngineSettings engineSettings = null;
// Catch the subclasses of MetaGlobalException to trigger various resets and wipes. try {
return session.engineIsEnabled(this.getEngineName(), null); engineSettings = getEngineSettings();
} catch (Exception e) {
Logger.warn(LOG_TAG, "Unable to get engine settings for " + this + ": fetching config failed.", e);
// Fall through; null engineSettings will pass below.
}
// We catch the subclasses of MetaGlobalException to trigger various resets and wipes in execute().
return session.engineIsEnabled(this.getEngineName(), engineSettings);
}
protected EngineSettings getEngineSettings() throws NonObjectJSONException, IOException, ParseException {
Integer version = getStorageVersion();
if (version == null) {
Logger.warn(LOG_TAG, "null storage version for " + this + "; using version 0.");
version = new Integer(0);
}
SynchronizerConfiguration config = this.getConfig();
if (config == null) {
return new EngineSettings(null, version.intValue());
}
return new EngineSettings(config.syncID, version.intValue());
} }
protected abstract String getCollection(); protected abstract String getCollection();
@ -113,17 +142,24 @@ public abstract class ServerSyncStage implements
Synchronizer synchronizer = new Synchronizer(); Synchronizer synchronizer = new Synchronizer();
synchronizer.repositoryA = remote; synchronizer.repositoryA = remote;
synchronizer.repositoryB = this.getLocalRepository(); synchronizer.repositoryB = this.getLocalRepository();
synchronizer.load(getConfig());
SynchronizerConfiguration config = this.getConfig();
synchronizer.load(config);
// TODO: should wipe in either direction?
// TODO: syncID?!
return synchronizer; return synchronizer;
} }
/**
* Reset timestamps.
*/
@Override @Override
public void resetLocal() { public void resetLocal() {
resetLocal(null);
}
/**
* Reset timestamps and possibly set syncID.
* @param syncID if non-null, new syncID to persist.
*/
public void resetLocal(String syncID) {
// Clear both timestamps. // Clear both timestamps.
SynchronizerConfiguration config; SynchronizerConfiguration config;
try { try {
@ -133,10 +169,14 @@ public abstract class ServerSyncStage implements
return; return;
} }
if (syncID != null) {
config.syncID = syncID;
Logger.info(LOG_TAG, "Setting syncID for " + this + " to '" + syncID + "'.");
}
config.localBundle.setTimestamp(0L); config.localBundle.setTimestamp(0L);
config.remoteBundle.setTimestamp(0L); config.remoteBundle.setTimestamp(0L);
Logger.info(LOG_TAG, "Reset timestamps for " + this);
persistConfig(config); persistConfig(config);
Logger.info(LOG_TAG, "Reset timestamps for " + this);
} }
// Not thread-safe. Use with caution. // Not thread-safe. Use with caution.
@ -156,8 +196,8 @@ public abstract class ServerSyncStage implements
/** /**
* Synchronously wipe this stage by instantiating a local repository session * Synchronously wipe this stage by instantiating a local repository session
* and wiping that. * and wiping that.
* * <p>
* Logs and rethrows an exception on failure. * Logs and re-throws an exception on failure.
*/ */
@Override @Override
public void wipeLocal() throws Exception { public void wipeLocal() throws Exception {
@ -290,6 +330,105 @@ public abstract class ServerSyncStage implements
Logger.info(LOG_TAG, "Wiping stage complete."); Logger.info(LOG_TAG, "Wiping stage complete.");
} }
/**
* Asynchronously wipe collection on server.
*/
protected void wipeServer(final CredentialsSource credentials, final WipeServerDelegate wipeDelegate) {
SyncStorageRequest request;
try {
request = new SyncStorageRequest(session.config.collectionURI(getCollection()));
} catch (URISyntaxException ex) {
Logger.warn(LOG_TAG, "Invalid URI in wipeServer.");
wipeDelegate.onWipeFailed(ex);
return;
}
request.delegate = new SyncStorageRequestDelegate() {
@Override
public String ifUnmodifiedSince() {
return null;
}
@Override
public void handleRequestSuccess(SyncStorageResponse response) {
BaseResource.consumeEntity(response);
resetLocal();
wipeDelegate.onWiped(response.normalizedWeaveTimestamp());
}
@Override
public void handleRequestFailure(SyncStorageResponse response) {
Logger.warn(LOG_TAG, "Got request failure " + response.getStatusCode() + " in wipeServer.");
// Process HTTP failures here to pick up backoffs, etc.
session.interpretHTTPFailure(response.httpResponse());
BaseResource.consumeEntity(response); // The exception thrown should not need the body of the response.
wipeDelegate.onWipeFailed(new HTTPFailureException(response));
}
@Override
public void handleRequestError(Exception ex) {
Logger.warn(LOG_TAG, "Got exception in wipeServer.", ex);
wipeDelegate.onWipeFailed(ex);
}
@Override
public String credentials() {
return credentials.credentials();
}
};
request.delete();
}
/**
* Synchronously wipe the server.
* <p>
* Logs and re-throws an exception on failure.
*/
public void wipeServer() throws Exception {
final WipeWaiter monitor = new WipeWaiter();
final Runnable doWipe = new Runnable() {
@Override
public void run() {
wipeServer(session, new WipeServerDelegate() {
@Override
public void onWiped(long timestamp) {
synchronized (monitor) {
monitor.notify();
}
}
@Override
public void onWipeFailed(Exception e) {
synchronized (monitor) {
monitor.notify(e, false);
}
}
});
}
};
final Thread wiping = new Thread(doWipe);
synchronized (monitor) {
wiping.start();
try {
monitor.wait();
} catch (InterruptedException e) {
Logger.error(LOG_TAG, "Server wipe interrupted.");
}
}
if (!monitor.wipeSucceeded) {
Logger.error(LOG_TAG, "Failed to wipe server.");
throw monitor.error;
}
Logger.info(LOG_TAG, "Wiping server complete.");
}
@Override @Override
public void execute() throws NoSuchStageException { public void execute() throws NoSuchStageException {
final String name = getEngineName(); final String name = getEngineName();
@ -301,12 +440,36 @@ public abstract class ServerSyncStage implements
session.advance(); session.advance();
return; return;
} }
} catch (MetaGlobalException.MetaGlobalMalformedSyncIDException e) {
// Bad engine syncID. This should never happen. Wipe the server.
try {
session.updateMetaGlobalWith(name, new EngineSettings(Utils.generateGuid(), this.getStorageVersion()));
Logger.info(LOG_TAG, "Wiping server because malformed engine sync ID was found in meta/global.");
wipeServer();
Logger.info(LOG_TAG, "Wiped server after malformed engine sync ID found in meta/global.");
} catch (Exception ex) {
session.abort(ex, "Failed to wipe server after malformed engine sync ID found in meta/global.");
}
} catch (MetaGlobalException.MetaGlobalMalformedVersionException e) {
// Bad engine version. This should never happen. Wipe the server.
try {
session.updateMetaGlobalWith(name, new EngineSettings(Utils.generateGuid(), this.getStorageVersion()));
Logger.info(LOG_TAG, "Wiping server because malformed engine version was found in meta/global.");
wipeServer();
Logger.info(LOG_TAG, "Wiped server after malformed engine version found in meta/global.");
} catch (Exception ex) {
session.abort(ex, "Failed to wipe server after malformed engine version found in meta/global.");
}
} catch (MetaGlobalException.MetaGlobalStaleClientSyncIDException e) {
// Our syncID is wrong. Reset client and take the server syncID.
Logger.warn(LOG_TAG, "Remote engine syncID different from local engine syncID:" +
" resetting local engine and assuming remote engine syncID.");
this.resetLocal(e.serverSyncID);
} catch (MetaGlobalException e) { } catch (MetaGlobalException e) {
session.abort(e, "Inappropriate meta/global; refusing to execute " + name + " stage."); session.abort(e, "Inappropriate meta/global; refusing to execute " + name + " stage.");
return; return;
} }
Synchronizer synchronizer; Synchronizer synchronizer;
try { try {
synchronizer = this.getConfiguredSynchronizer(session); synchronizer = this.getConfiguredSynchronizer(session);
@ -336,11 +499,11 @@ public abstract class ServerSyncStage implements
public void onSynchronized(Synchronizer synchronizer) { public void onSynchronized(Synchronizer synchronizer) {
Logger.debug(LOG_TAG, "onSynchronized."); Logger.debug(LOG_TAG, "onSynchronized.");
SynchronizerConfiguration synchronizerConfiguration = synchronizer.save(); SynchronizerConfiguration newConfig = synchronizer.save();
if (synchronizerConfiguration != null) { if (newConfig != null) {
persistConfig(synchronizerConfiguration); persistConfig(newConfig);
} else { } else {
Logger.warn(LOG_TAG, "Didn't get configuration from synchronizer after success"); Logger.warn(LOG_TAG, "Didn't get configuration from synchronizer after success.");
} }
Logger.info(LOG_TAG, "Advancing session."); Logger.info(LOG_TAG, "Advancing session.");

Просмотреть файл

@ -0,0 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.sync.stage;
import org.mozilla.gecko.sync.GlobalSession;
public class UploadMetaGlobalStage extends AbstractNonRepositorySyncStage {
public static final String LOG_TAG = "UploadMGStage";
public UploadMetaGlobalStage(GlobalSession session) {
super(session);
}
@Override
public void execute() throws NoSuchStageException {
if (session.hasUpdatedMetaGlobal()) {
session.uploadUpdatedMetaGlobal();
}
session.advance();
}
}

Просмотреть файл

@ -28,6 +28,7 @@ import android.util.Log;
* updated bundle information. * updated bundle information.
*/ */
public class Synchronizer { public class Synchronizer {
protected String configSyncID; // Used to pass syncID from load() back into save().
/** /**
* I translate the fine-grained feedback of a SynchronizerSessionDelegate into * I translate the fine-grained feedback of a SynchronizerSessionDelegate into
@ -109,8 +110,7 @@ public class Synchronizer {
} }
public SynchronizerConfiguration save() { public SynchronizerConfiguration save() {
String syncID = null; // TODO: syncID. return new SynchronizerConfiguration(configSyncID, bundleA, bundleB);
return new SynchronizerConfiguration(syncID, bundleA, bundleB);
} }
/** /**
@ -123,6 +123,6 @@ public class Synchronizer {
public void load(SynchronizerConfiguration config) { public void load(SynchronizerConfiguration config) {
bundleA = config.remoteBundle; bundleA = config.remoteBundle;
bundleB = config.localBundle; bundleB = config.localBundle;
// TODO: syncID. configSyncID = config.syncID;
} }
} }

Просмотреть файл

@ -185,6 +185,7 @@ sync/stage/NoSyncIDException.java
sync/stage/PasswordsServerSyncStage.java sync/stage/PasswordsServerSyncStage.java
sync/stage/ServerSyncStage.java sync/stage/ServerSyncStage.java
sync/stage/SyncClientsEngineStage.java sync/stage/SyncClientsEngineStage.java
sync/stage/UploadMetaGlobalStage.java
sync/StubActivity.java sync/StubActivity.java
sync/syncadapter/SyncAdapter.java sync/syncadapter/SyncAdapter.java
sync/syncadapter/SyncService.java sync/syncadapter/SyncService.java
@ -205,7 +206,6 @@ sync/synchronizer/SynchronizerSessionDelegate.java
sync/synchronizer/UnbundleError.java sync/synchronizer/UnbundleError.java
sync/synchronizer/UnexpectedSessionException.java sync/synchronizer/UnexpectedSessionException.java
sync/SynchronizerConfiguration.java sync/SynchronizerConfiguration.java
sync/SynchronizerConfigurations.java
sync/ThreadPool.java sync/ThreadPool.java
sync/UnexpectedJSONException.java sync/UnexpectedJSONException.java
sync/UnknownSynchronizerConfigurationVersionException.java sync/UnknownSynchronizerConfigurationVersionException.java