- changed periodic sync scheduling to just creating pending
and changed the "get next operation to sync" logic just look at pending syncs, rather than them and periodic syncs - made syncoperation dup-detection ignore the initialization sync extra - made the sync dispatcher treat initialization syncs as just a regular sync request and also made it explicitly set or clear the initialization extra based on whether the sync adapter was in the syncable or unknown state - change the getNextSync logic to prioritize syncable "unknown" syncs above everything else (since they should be fast and are important) - make it reschedule completed initialization syncs if the sync adapter is now marked syncable - fix some logging in SyncStorageEngine - change SyncStorageEngine to not reuse authority ids when one is removed http://b/issue?id=2531359 http://b/issue?id=2429638 Change-Id: I79805b582da74f4f0b6193eafaff24c2371d51e8
This commit is contained in:
@ -398,10 +398,6 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
return minValue + random.nextInt((int)spread);
|
||||
}
|
||||
|
||||
public ActiveSyncContext getActiveSyncContext() {
|
||||
return mActiveSyncContext;
|
||||
}
|
||||
|
||||
public SyncStorageEngine getSyncStorageEngine() {
|
||||
return mSyncStorageEngine;
|
||||
}
|
||||
@ -412,11 +408,6 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
}
|
||||
}
|
||||
|
||||
public Account getSyncingAccount() {
|
||||
ActiveSyncContext activeSyncContext = mActiveSyncContext;
|
||||
return (activeSyncContext != null) ? activeSyncContext.mSyncOperation.account : null;
|
||||
}
|
||||
|
||||
private void initializeSyncAdapter(Account account, String authority) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "initializeSyncAdapter: " + account + ", authority " + authority);
|
||||
@ -425,7 +416,8 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
|
||||
mSyncAdapters.getServiceInfo(syncAdapterType);
|
||||
if (syncAdapterInfo == null) {
|
||||
Log.w(TAG, "can't find a sync adapter for " + syncAdapterType);
|
||||
Log.w(TAG, "can't find a sync adapter for " + syncAdapterType + ", removing");
|
||||
mSyncStorageEngine.removeAuthority(account, authority);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -466,6 +458,8 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// doesn't matter, we will retry again later
|
||||
Log.d(TAG, "error while initializing: " + mAccount + ", authority " + mAuthority,
|
||||
e);
|
||||
} finally {
|
||||
// give the sync adapter time to initialize before unbinding from it
|
||||
// TODO: change this API to not rely on this timing, http://b/2500805
|
||||
@ -602,16 +596,12 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
continue;
|
||||
}
|
||||
|
||||
// initialize the SyncAdapter if the isSyncable state is unknown
|
||||
if (isSyncable < 0) {
|
||||
initializeSyncAdapter(account, authority);
|
||||
continue;
|
||||
}
|
||||
|
||||
final boolean syncAutomatically = masterSyncAutomatically
|
||||
&& mSyncStorageEngine.getSyncAutomatically(account, authority);
|
||||
// always allow if the isSyncable state is unknown
|
||||
boolean syncAllowed =
|
||||
ignoreSettings || (backgroundDataUsageAllowed && syncAutomatically);
|
||||
(isSyncable < 0)
|
||||
|| ignoreSettings
|
||||
|| (backgroundDataUsageAllowed && masterSyncAutomatically
|
||||
&& mSyncStorageEngine.getSyncAutomatically(account, authority));
|
||||
if (!syncAllowed) {
|
||||
if (isLoggable) {
|
||||
Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
|
||||
@ -1061,7 +1051,7 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
pw.println(op.expedited);
|
||||
if (op.extras != null && op.extras.size() > 0) {
|
||||
sb.setLength(0);
|
||||
SyncOperation.extrasToStringBuilder(op.extras, sb);
|
||||
SyncOperation.extrasToStringBuilder(op.extras, sb, false /* asKey */);
|
||||
pw.print(" extras: "); pw.println(sb.toString());
|
||||
}
|
||||
}
|
||||
@ -1376,8 +1366,14 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
}
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
Long earliestFuturePollTime = null;
|
||||
try {
|
||||
waitUntilReadyToRun();
|
||||
// Always do this first so that we be sure that any periodic syncs that
|
||||
// are ready to run have been converted into pending syncs. This allows the
|
||||
// logic that considers the next steps to take based on the set of pending syncs
|
||||
// to also take into account the periodic syncs.
|
||||
earliestFuturePollTime = scheduleReadyPeriodicSyncs();
|
||||
switch (msg.what) {
|
||||
case SyncHandler.MESSAGE_SYNC_FINISHED:
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
@ -1486,48 +1482,90 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
}
|
||||
manageSyncNotification();
|
||||
manageErrorNotification();
|
||||
manageSyncAlarm();
|
||||
manageSyncAlarm(earliestFuturePollTime);
|
||||
mSyncTimeTracker.update();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSyncAllowed(Account account, String authority, boolean ignoreSettings,
|
||||
boolean backgroundDataUsageAllowed) {
|
||||
Account[] accounts = mAccounts;
|
||||
/**
|
||||
* Turn any periodic sync operations that are ready to run into pending sync operations.
|
||||
* @return the desired start time of the earliest future periodic sync operation,
|
||||
* in milliseconds since boot
|
||||
*/
|
||||
private Long scheduleReadyPeriodicSyncs() {
|
||||
final boolean backgroundDataUsageAllowed =
|
||||
getConnectivityManager().getBackgroundDataSetting();
|
||||
Long earliestFuturePollTime = null;
|
||||
if (!backgroundDataUsageAllowed || !mSyncStorageEngine.getMasterSyncAutomatically()) {
|
||||
return earliestFuturePollTime;
|
||||
}
|
||||
final long nowAbsolute = System.currentTimeMillis();
|
||||
ArrayList<SyncStorageEngine.AuthorityInfo> infos = mSyncStorageEngine.getAuthorities();
|
||||
for (SyncStorageEngine.AuthorityInfo info : infos) {
|
||||
// skip the sync if the account of this operation no longer exists
|
||||
if (!ArrayUtils.contains(mAccounts, info.account)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip the sync if the account of this operation no longer exists
|
||||
if (!ArrayUtils.contains(accounts, account)) {
|
||||
return false;
|
||||
if (!mSyncStorageEngine.getSyncAutomatically(info.account, info.authority)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mSyncStorageEngine.getIsSyncable(info.account, info.authority) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SyncStatusInfo status = mSyncStorageEngine.getOrCreateSyncStatus(info);
|
||||
for (int i = 0, N = info.periodicSyncs.size(); i < N; i++) {
|
||||
final Bundle extras = info.periodicSyncs.get(i).first;
|
||||
final Long periodInSeconds = info.periodicSyncs.get(i).second;
|
||||
// find when this periodic sync was last scheduled to run
|
||||
final long lastPollTimeAbsolute = status.getPeriodicSyncTime(i);
|
||||
// compute when this periodic sync should next run
|
||||
long nextPollTimeAbsolute = lastPollTimeAbsolute + periodInSeconds * 1000;
|
||||
// if it is ready to run then schedule it and mark it as having been scheduled
|
||||
if (nextPollTimeAbsolute <= nowAbsolute) {
|
||||
scheduleSyncOperation(
|
||||
new SyncOperation(info.account, SyncStorageEngine.SOURCE_PERIODIC,
|
||||
info.authority, extras, 0 /* delay */));
|
||||
status.setPeriodicSyncTime(i, nowAbsolute);
|
||||
} else {
|
||||
// it isn't ready to run, remember this time if it is earlier than
|
||||
// earliestFuturePollTime
|
||||
if (earliestFuturePollTime == null
|
||||
|| nextPollTimeAbsolute < earliestFuturePollTime) {
|
||||
earliestFuturePollTime = nextPollTimeAbsolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// skip the sync if it isn't manual and auto sync is disabled
|
||||
final boolean syncAutomatically =
|
||||
mSyncStorageEngine.getSyncAutomatically(account, authority)
|
||||
&& mSyncStorageEngine.getMasterSyncAutomatically();
|
||||
if (!(ignoreSettings || (backgroundDataUsageAllowed && syncAutomatically))) {
|
||||
return false;
|
||||
if (earliestFuturePollTime == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mSyncStorageEngine.getIsSyncable(account, authority) <= 0) {
|
||||
// if not syncable or if the syncable is unknown (< 0), don't allow
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// convert absolute time to elapsed time
|
||||
return SystemClock.elapsedRealtime()
|
||||
+ ((earliestFuturePollTime < nowAbsolute)
|
||||
? 0
|
||||
: (earliestFuturePollTime - nowAbsolute));
|
||||
}
|
||||
|
||||
private void runStateSyncing() {
|
||||
// if the sync timeout has been reached then cancel it
|
||||
|
||||
ActiveSyncContext activeSyncContext = mActiveSyncContext;
|
||||
|
||||
final long now = SystemClock.elapsedRealtime();
|
||||
if (now > activeSyncContext.mTimeoutStartTime + MAX_TIME_PER_SYNC) {
|
||||
SyncOperation nextSyncOperation;
|
||||
Pair<SyncOperation, Long> nextOpAndRunTime;
|
||||
synchronized (mSyncQueue) {
|
||||
nextSyncOperation = getNextReadyToRunSyncOperation(now);
|
||||
nextOpAndRunTime = mSyncQueue.nextOperation();
|
||||
}
|
||||
if (nextSyncOperation != null) {
|
||||
SyncOperation curOp = activeSyncContext.mSyncOperation;
|
||||
if (nextOpAndRunTime != null
|
||||
&& nextOpAndRunTime.second <= now
|
||||
&& !nextOpAndRunTime.first.account.equals(curOp.account)
|
||||
&& !nextOpAndRunTime.first.authority.equals(curOp.authority)) {
|
||||
Log.d(TAG, "canceling and rescheduling sync because it ran too long: "
|
||||
+ activeSyncContext.mSyncOperation);
|
||||
scheduleSyncOperation(new SyncOperation(activeSyncContext.mSyncOperation));
|
||||
@ -1574,27 +1612,48 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
// found that is runnable (not disabled, etc). If that one is ready to run then
|
||||
// start it, otherwise just get out.
|
||||
SyncOperation op;
|
||||
int syncableState;
|
||||
final boolean backgroundDataUsageAllowed =
|
||||
getConnectivityManager().getBackgroundDataSetting();
|
||||
final boolean masterSyncAutomatically = mSyncStorageEngine.getMasterSyncAutomatically();
|
||||
|
||||
synchronized (mSyncQueue) {
|
||||
final long now = SystemClock.elapsedRealtime();
|
||||
while (true) {
|
||||
op = getNextReadyToRunSyncOperation(now);
|
||||
if (op == null) {
|
||||
Pair<SyncOperation, Long> nextOpAndRunTime = mSyncQueue.nextOperation();
|
||||
if (nextOpAndRunTime == null || nextOpAndRunTime.second > now) {
|
||||
if (isLoggable) {
|
||||
Log.v(TAG, "runStateIdle: no more sync operations, returning");
|
||||
Log.v(TAG, "runStateIdle: no more ready sync operations, returning");
|
||||
}
|
||||
return;
|
||||
}
|
||||
op = nextOpAndRunTime.first;
|
||||
|
||||
// we are either going to run this sync or drop it so go ahead and remove it
|
||||
// from the queue now
|
||||
// we are either going to run this sync or drop it so go ahead and
|
||||
// remove it from the queue now
|
||||
mSyncQueue.remove(op);
|
||||
|
||||
final boolean ignoreSettings = op.extras
|
||||
.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
|
||||
if (!isSyncAllowed(op.account, op.authority, ignoreSettings,
|
||||
backgroundDataUsageAllowed)) {
|
||||
// drop the sync if the account of this operation no longer exists
|
||||
if (!ArrayUtils.contains(mAccounts, op.account)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// drop this sync request if it isn't syncable, intializing the sync adapter
|
||||
// if the syncable state is set to "unknown"
|
||||
syncableState = mSyncStorageEngine.getIsSyncable(op.account, op.authority);
|
||||
if (syncableState == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip the sync if it isn't manual and auto sync or
|
||||
// background data usage is disabled
|
||||
if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
|
||||
&& (syncableState > 0)
|
||||
&& (!masterSyncAutomatically
|
||||
|| !backgroundDataUsageAllowed
|
||||
|| !mSyncStorageEngine.getSyncAutomatically(
|
||||
op.account, op.authority))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1608,6 +1667,19 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
}
|
||||
}
|
||||
|
||||
// convert the op into an initialization sync if the syncable state is "unknown" and
|
||||
// op isn't already an initialization sync. If it is marked syncable then convert
|
||||
// this into a regular sync
|
||||
final boolean initializeIsSet =
|
||||
op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
|
||||
if (syncableState < 0 && !initializeIsSet) {
|
||||
op.extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
|
||||
op = new SyncOperation(op);
|
||||
} else if (syncableState > 0 && initializeIsSet) {
|
||||
op.extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
|
||||
op = new SyncOperation(op);
|
||||
}
|
||||
|
||||
// connect to the sync adapter
|
||||
SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type);
|
||||
RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
|
||||
@ -1643,74 +1715,6 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
// MESSAGE_SERVICE_CONNECTED or MESSAGE_SERVICE_DISCONNECTED message
|
||||
}
|
||||
|
||||
private SyncOperation getNextPeriodicSyncOperation() {
|
||||
final boolean backgroundDataUsageAllowed =
|
||||
getConnectivityManager().getBackgroundDataSetting();
|
||||
SyncStorageEngine.AuthorityInfo best = null;
|
||||
long bestPollTimeAbsolute = Long.MAX_VALUE;
|
||||
Bundle bestExtras = null;
|
||||
ArrayList<SyncStorageEngine.AuthorityInfo> infos = mSyncStorageEngine.getAuthorities();
|
||||
for (SyncStorageEngine.AuthorityInfo info : infos) {
|
||||
if (!isSyncAllowed(info.account, info.authority, false /* ignoreSettings */,
|
||||
backgroundDataUsageAllowed)) {
|
||||
continue;
|
||||
}
|
||||
SyncStatusInfo status = mSyncStorageEngine.getStatusByAccountAndAuthority(
|
||||
info.account, info.authority);
|
||||
int i = 0;
|
||||
for (Pair<Bundle, Long> periodicSync : info.periodicSyncs) {
|
||||
long lastPollTimeAbsolute = status != null ? status.getPeriodicSyncTime(i) : 0;
|
||||
final Bundle extras = periodicSync.first;
|
||||
final Long periodInSeconds = periodicSync.second;
|
||||
long nextPollTimeAbsolute = lastPollTimeAbsolute + periodInSeconds * 1000;
|
||||
if (nextPollTimeAbsolute < bestPollTimeAbsolute) {
|
||||
best = info;
|
||||
bestPollTimeAbsolute = nextPollTimeAbsolute;
|
||||
bestExtras = extras;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (best == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final long nowAbsolute = System.currentTimeMillis();
|
||||
final SyncOperation syncOperation = new SyncOperation(best.account,
|
||||
SyncStorageEngine.SOURCE_PERIODIC,
|
||||
best.authority, bestExtras, 0 /* delay */);
|
||||
syncOperation.earliestRunTime = SystemClock.elapsedRealtime()
|
||||
+ (bestPollTimeAbsolute - nowAbsolute);
|
||||
if (syncOperation.earliestRunTime < 0) {
|
||||
syncOperation.earliestRunTime = 0;
|
||||
}
|
||||
return syncOperation;
|
||||
}
|
||||
|
||||
public Pair<SyncOperation, Long> bestSyncOperationCandidate() {
|
||||
Pair<SyncOperation, Long> nextOpAndRunTime = mSyncQueue.nextOperation();
|
||||
SyncOperation nextOp = nextOpAndRunTime != null ? nextOpAndRunTime.first : null;
|
||||
Long nextRunTime = nextOpAndRunTime != null ? nextOpAndRunTime.second : null;
|
||||
SyncOperation pollOp = getNextPeriodicSyncOperation();
|
||||
if (nextOp != null
|
||||
&& (pollOp == null || nextOp.expedited
|
||||
|| nextRunTime <= pollOp.earliestRunTime)) {
|
||||
return nextOpAndRunTime;
|
||||
} else if (pollOp != null) {
|
||||
return Pair.create(pollOp, pollOp.earliestRunTime);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private SyncOperation getNextReadyToRunSyncOperation(long now) {
|
||||
Pair<SyncOperation, Long> nextOpAndRunTime = bestSyncOperationCandidate();
|
||||
return nextOpAndRunTime != null && nextOpAndRunTime.second <= now
|
||||
? nextOpAndRunTime.first
|
||||
: null;
|
||||
}
|
||||
|
||||
private void runBoundToSyncAdapter(ISyncAdapter syncAdapter) {
|
||||
mActiveSyncContext.mSyncAdapter = syncAdapter;
|
||||
final SyncOperation syncOperation = mActiveSyncContext.mSyncOperation;
|
||||
@ -1757,6 +1761,15 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
downstreamActivity = 0;
|
||||
upstreamActivity = 0;
|
||||
clearBackoffSetting(syncOperation);
|
||||
// if this was an initialization sync and the sync adapter is now
|
||||
// marked syncable then reschedule the sync. The next time it runs it
|
||||
// will be made into a regular sync.
|
||||
if (syncOperation.extras.getBoolean(
|
||||
ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
|
||||
&& mSyncStorageEngine.getIsSyncable(
|
||||
syncOperation.account, syncOperation.authority) > 0) {
|
||||
scheduleSyncOperation(new SyncOperation(syncOperation));
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
|
||||
// the operation failed so increase the backoff time
|
||||
@ -1919,7 +1932,7 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void manageSyncAlarm() {
|
||||
private void manageSyncAlarm(Long earliestFuturePollElapsedTime) {
|
||||
// in each of these cases the sync loop will be kicked, which will cause this
|
||||
// method to be called again
|
||||
if (!mDataConnectionIsConnected) return;
|
||||
@ -1935,8 +1948,16 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
ActiveSyncContext activeSyncContext = mActiveSyncContext;
|
||||
if (activeSyncContext == null) {
|
||||
synchronized (mSyncQueue) {
|
||||
Pair<SyncOperation, Long> candidate = bestSyncOperationCandidate();
|
||||
alarmTime = candidate != null ? candidate.second : null;
|
||||
final Pair<SyncOperation, Long> candidate = mSyncQueue.nextOperation();
|
||||
if (earliestFuturePollElapsedTime == null && candidate == null) {
|
||||
alarmTime = null;
|
||||
} else if (earliestFuturePollElapsedTime == null) {
|
||||
alarmTime = candidate.second;
|
||||
} else if (candidate == null) {
|
||||
alarmTime = earliestFuturePollElapsedTime;
|
||||
} else {
|
||||
alarmTime = Math.min(earliestFuturePollElapsedTime, candidate.second);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final long notificationTime =
|
||||
@ -2077,7 +2098,7 @@ public class SyncManager implements OnAccountsUpdateListener {
|
||||
SyncStorageEngine.EVENT_STOP, syncOperation.syncSource,
|
||||
syncOperation.account.name.hashCode());
|
||||
|
||||
mSyncStorageEngine.stopSyncEvent(rowId, syncOperation.extras, elapsedTime,
|
||||
mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
|
||||
resultMessage, downstreamActivity, upstreamActivity);
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ public class SyncOperation implements Comparable {
|
||||
sb.append("authority: ").append(authority);
|
||||
sb.append(" account: ").append(account);
|
||||
sb.append(" extras: ");
|
||||
extrasToStringBuilder(extras, sb);
|
||||
extrasToStringBuilder(extras, sb, false /* asKey */);
|
||||
sb.append(" syncSource: ").append(syncSource);
|
||||
sb.append(" when: ").append(earliestRunTime);
|
||||
sb.append(" expedited: ").append(expedited);
|
||||
@ -92,13 +92,19 @@ public class SyncOperation implements Comparable {
|
||||
sb.append("authority: ").append(authority);
|
||||
sb.append(" account: ").append(account);
|
||||
sb.append(" extras: ");
|
||||
extrasToStringBuilder(extras, sb);
|
||||
extrasToStringBuilder(extras, sb, true /* asKey */);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
|
||||
public static void extrasToStringBuilder(Bundle bundle, StringBuilder sb, boolean asKey) {
|
||||
sb.append("[");
|
||||
for (String key : bundle.keySet()) {
|
||||
// if we are writing this as a key don't consider whether this
|
||||
// is an initialization sync or not when computing the key since
|
||||
// we set this flag appropriately when dispatching the sync request.
|
||||
if (asKey && ContentResolver.SYNC_EXTRAS_INITIALIZE.equals(key)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(key).append("=").append(bundle.get(key)).append(" ");
|
||||
}
|
||||
sb.append("]");
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package android.content;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
import com.google.android.collect.Maps;
|
||||
|
||||
import android.util.Pair;
|
||||
@ -120,14 +121,16 @@ public class SyncQueue {
|
||||
|
||||
/**
|
||||
* Find the operation that should run next. Operations are sorted by their earliestRunTime,
|
||||
* prioritizing expedited operations. The earliestRunTime is adjusted by the sync adapter's
|
||||
* backoff and delayUntil times, if any.
|
||||
* prioritizing first those with a syncable state of "unknown" that aren't retries then
|
||||
* expedited operations.
|
||||
* The earliestRunTime is adjusted by the sync adapter's backoff and delayUntil times, if any.
|
||||
* @return the operation that should run next and when it should run. The time may be in
|
||||
* the future. It is expressed in milliseconds since boot.
|
||||
*/
|
||||
public Pair<SyncOperation, Long> nextOperation() {
|
||||
SyncOperation best = null;
|
||||
long bestRunTime = 0;
|
||||
boolean bestSyncableIsUnknownAndNotARetry = false;
|
||||
for (SyncOperation op : mOperationsMap.values()) {
|
||||
long opRunTime = op.earliestRunTime;
|
||||
if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
|
||||
@ -137,12 +140,23 @@ public class SyncQueue {
|
||||
Math.max(opRunTime, delayUntil),
|
||||
backoff != null ? backoff.first : 0);
|
||||
}
|
||||
// if the expedited state of both ops are the same then compare their runtime.
|
||||
// Otherwise the candidate is only better than the current best if the candidate
|
||||
// is expedited.
|
||||
// we know a sync is a retry if the intialization flag is set, since that will only
|
||||
// be set by the sync dispatching code, thus if it is set it must have already been
|
||||
// dispatched
|
||||
final boolean syncableIsUnknownAndNotARetry =
|
||||
!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
|
||||
&& mSyncStorageEngine.getIsSyncable(op.account, op.authority) < 0;
|
||||
// if the unsyncable state differs, make the current the best if it is unsyncable
|
||||
// else, if the expedited state differs, make the current the best if it is expedited
|
||||
// else, make the current the best if it is earlier than the best
|
||||
if (best == null
|
||||
|| (best.expedited == op.expedited ? opRunTime < bestRunTime : op.expedited)) {
|
||||
|| ((bestSyncableIsUnknownAndNotARetry == syncableIsUnknownAndNotARetry)
|
||||
? (best.expedited == op.expedited
|
||||
? opRunTime < bestRunTime
|
||||
: op.expedited)
|
||||
: syncableIsUnknownAndNotARetry)) {
|
||||
best = op;
|
||||
bestSyncableIsUnknownAndNotARetry = syncableIsUnknownAndNotARetry;
|
||||
bestRunTime = opRunTime;
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ import java.util.List;
|
||||
*/
|
||||
public class SyncStorageEngine extends Handler {
|
||||
private static final String TAG = "SyncManager";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG_FILE = false;
|
||||
|
||||
private static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
|
||||
@ -241,6 +240,8 @@ public class SyncStorageEngine extends Handler {
|
||||
private final RemoteCallbackList<ISyncStatusObserver> mChangeListeners
|
||||
= new RemoteCallbackList<ISyncStatusObserver>();
|
||||
|
||||
private int mNextAuthorityId = 0;
|
||||
|
||||
// We keep 4 weeks of stats.
|
||||
private final DayStats[] mDayStats = new DayStats[7*4];
|
||||
private final Calendar mCal;
|
||||
@ -301,7 +302,11 @@ public class SyncStorageEngine extends Handler {
|
||||
readStatusLocked();
|
||||
readPendingOperationsLocked();
|
||||
readStatisticsLocked();
|
||||
readLegacyAccountInfoLocked();
|
||||
readAndDeleteLegacyAccountInfoLocked();
|
||||
writeAccountInfoLocked();
|
||||
writeStatusLocked();
|
||||
writePendingOperationsLocked();
|
||||
writeStatisticsLocked();
|
||||
}
|
||||
|
||||
public static SyncStorageEngine newTestInstance(Context context) {
|
||||
@ -365,7 +370,9 @@ public class SyncStorageEngine extends Handler {
|
||||
mChangeListeners.finishBroadcast();
|
||||
}
|
||||
|
||||
if (DEBUG) Log.v(TAG, "reportChange " + which + " to: " + reports);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "reportChange " + which + " to: " + reports);
|
||||
}
|
||||
|
||||
if (reports != null) {
|
||||
int i = reports.size();
|
||||
@ -402,15 +409,19 @@ public class SyncStorageEngine extends Handler {
|
||||
}
|
||||
|
||||
public void setSyncAutomatically(Account account, String providerName, boolean sync) {
|
||||
boolean wasEnabled;
|
||||
Log.d(TAG, "setSyncAutomatically: " + account + ", provider " + providerName
|
||||
+ " -> " + sync);
|
||||
synchronized (mAuthorities) {
|
||||
AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
|
||||
wasEnabled = authority.enabled;
|
||||
if (authority.enabled == sync) {
|
||||
Log.d(TAG, "setSyncAutomatically: already set to " + sync + ", doing nothing");
|
||||
return;
|
||||
}
|
||||
authority.enabled = sync;
|
||||
writeAccountInfoLocked();
|
||||
}
|
||||
|
||||
if (!wasEnabled && sync) {
|
||||
if (sync) {
|
||||
ContentResolver.requestSync(account, providerName, new Bundle());
|
||||
}
|
||||
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
|
||||
@ -440,7 +451,6 @@ public class SyncStorageEngine extends Handler {
|
||||
}
|
||||
|
||||
public void setIsSyncable(Account account, String providerName, int syncable) {
|
||||
int oldState;
|
||||
if (syncable > 1) {
|
||||
syncable = 1;
|
||||
} else if (syncable < -1) {
|
||||
@ -449,12 +459,15 @@ public class SyncStorageEngine extends Handler {
|
||||
Log.d(TAG, "setIsSyncable: " + account + ", provider " + providerName + " -> " + syncable);
|
||||
synchronized (mAuthorities) {
|
||||
AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
|
||||
oldState = authority.syncable;
|
||||
if (authority.syncable == syncable) {
|
||||
Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
|
||||
return;
|
||||
}
|
||||
authority.syncable = syncable;
|
||||
writeAccountInfoLocked();
|
||||
}
|
||||
|
||||
if (oldState <= 0 && syncable > 0) {
|
||||
if (syncable > 0) {
|
||||
ContentResolver.requestSync(account, providerName, new Bundle());
|
||||
}
|
||||
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
|
||||
@ -550,49 +563,60 @@ public class SyncStorageEngine extends Handler {
|
||||
+ " -> period " + period + ", extras " + extras);
|
||||
}
|
||||
synchronized (mAuthorities) {
|
||||
AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
|
||||
if (add) {
|
||||
boolean alreadyPresent = false;
|
||||
for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
|
||||
Pair<Bundle, Long> syncInfo = authority.periodicSyncs.get(i);
|
||||
final Bundle existingExtras = syncInfo.first;
|
||||
if (equals(existingExtras, extras)) {
|
||||
if (syncInfo.second == period) {
|
||||
return;
|
||||
try {
|
||||
AuthorityInfo authority =
|
||||
getOrCreateAuthorityLocked(account, providerName, -1, false);
|
||||
if (add) {
|
||||
// add this periodic sync if one with the same extras doesn't already
|
||||
// exist in the periodicSyncs array
|
||||
boolean alreadyPresent = false;
|
||||
for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
|
||||
Pair<Bundle, Long> syncInfo = authority.periodicSyncs.get(i);
|
||||
final Bundle existingExtras = syncInfo.first;
|
||||
if (equals(existingExtras, extras)) {
|
||||
if (syncInfo.second == period) {
|
||||
return;
|
||||
}
|
||||
authority.periodicSyncs.set(i, Pair.create(extras, period));
|
||||
alreadyPresent = true;
|
||||
break;
|
||||
}
|
||||
authority.periodicSyncs.set(i, Pair.create(extras, period));
|
||||
alreadyPresent = true;
|
||||
break;
|
||||
}
|
||||
// if we added an entry to the periodicSyncs array also add an entry to
|
||||
// the periodic syncs status to correspond to it
|
||||
if (!alreadyPresent) {
|
||||
authority.periodicSyncs.add(Pair.create(extras, period));
|
||||
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
|
||||
status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0);
|
||||
}
|
||||
} else {
|
||||
// remove any periodic syncs that match the authority and extras
|
||||
SyncStatusInfo status = mSyncStatus.get(authority.ident);
|
||||
boolean changed = false;
|
||||
Iterator<Pair<Bundle, Long>> iterator = authority.periodicSyncs.iterator();
|
||||
int i = 0;
|
||||
while (iterator.hasNext()) {
|
||||
Pair<Bundle, Long> syncInfo = iterator.next();
|
||||
if (equals(syncInfo.first, extras)) {
|
||||
iterator.remove();
|
||||
changed = true;
|
||||
// if we removed an entry from the periodicSyncs array also
|
||||
// remove the corresponding entry from the status
|
||||
if (status != null) {
|
||||
status.removePeriodicSyncTime(i);
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!alreadyPresent) {
|
||||
authority.periodicSyncs.add(Pair.create(extras, period));
|
||||
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
|
||||
status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0);
|
||||
}
|
||||
} else {
|
||||
SyncStatusInfo status = mSyncStatus.get(authority.ident);
|
||||
boolean changed = false;
|
||||
Iterator<Pair<Bundle, Long>> iterator = authority.periodicSyncs.iterator();
|
||||
int i = 0;
|
||||
while (iterator.hasNext()) {
|
||||
Pair<Bundle, Long> syncInfo = iterator.next();
|
||||
if (equals(syncInfo.first, extras)) {
|
||||
iterator.remove();
|
||||
changed = true;
|
||||
if (status != null) {
|
||||
status.removePeriodicSyncTime(i);
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
writeAccountInfoLocked();
|
||||
writeStatusLocked();
|
||||
}
|
||||
writeAccountInfoLocked();
|
||||
writeStatusLocked();
|
||||
}
|
||||
|
||||
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
|
||||
@ -622,13 +646,14 @@ public class SyncStorageEngine extends Handler {
|
||||
}
|
||||
|
||||
public void setMasterSyncAutomatically(boolean flag) {
|
||||
boolean old;
|
||||
synchronized (mAuthorities) {
|
||||
old = mMasterSyncAutomatically;
|
||||
if (mMasterSyncAutomatically == flag) {
|
||||
return;
|
||||
}
|
||||
mMasterSyncAutomatically = flag;
|
||||
writeAccountInfoLocked();
|
||||
}
|
||||
if (!old && flag) {
|
||||
if (flag) {
|
||||
ContentResolver.requestSync(null, null, new Bundle());
|
||||
}
|
||||
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
|
||||
@ -651,7 +676,7 @@ public class SyncStorageEngine extends Handler {
|
||||
|
||||
public void removeAuthority(Account account, String authority) {
|
||||
synchronized (mAuthorities) {
|
||||
removeAuthorityLocked(account, authority);
|
||||
removeAuthorityLocked(account, authority, true /* doWrite */);
|
||||
}
|
||||
}
|
||||
|
||||
@ -692,10 +717,12 @@ public class SyncStorageEngine extends Handler {
|
||||
|
||||
public PendingOperation insertIntoPending(PendingOperation op) {
|
||||
synchronized (mAuthorities) {
|
||||
if (DEBUG) Log.v(TAG, "insertIntoPending: account=" + op.account
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "insertIntoPending: account=" + op.account
|
||||
+ " auth=" + op.authority
|
||||
+ " src=" + op.syncSource
|
||||
+ " extras=" + op.extras);
|
||||
}
|
||||
|
||||
AuthorityInfo authority = getOrCreateAuthorityLocked(op.account,
|
||||
op.authority,
|
||||
@ -721,10 +748,12 @@ public class SyncStorageEngine extends Handler {
|
||||
public boolean deleteFromPending(PendingOperation op) {
|
||||
boolean res = false;
|
||||
synchronized (mAuthorities) {
|
||||
if (DEBUG) Log.v(TAG, "deleteFromPending: account=" + op.account
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "deleteFromPending: account=" + op.account
|
||||
+ " auth=" + op.authority
|
||||
+ " src=" + op.syncSource
|
||||
+ " extras=" + op.extras);
|
||||
}
|
||||
if (mPendingOperations.remove(op)) {
|
||||
if (mPendingOperations.size() == 0
|
||||
|| mNumPendingFinished >= PENDING_FINISH_TO_WRITE) {
|
||||
@ -737,7 +766,7 @@ public class SyncStorageEngine extends Handler {
|
||||
AuthorityInfo authority = getAuthorityLocked(op.account, op.authority,
|
||||
"deleteFromPending");
|
||||
if (authority != null) {
|
||||
if (DEBUG) Log.v(TAG, "removing - " + authority);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "removing - " + authority);
|
||||
final int N = mPendingOperations.size();
|
||||
boolean morePending = false;
|
||||
for (int i=0; i<N; i++) {
|
||||
@ -750,7 +779,7 @@ public class SyncStorageEngine extends Handler {
|
||||
}
|
||||
|
||||
if (!morePending) {
|
||||
if (DEBUG) Log.v(TAG, "no more pending!");
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "no more pending!");
|
||||
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
|
||||
status.pending = false;
|
||||
}
|
||||
@ -767,7 +796,9 @@ public class SyncStorageEngine extends Handler {
|
||||
public int clearPending() {
|
||||
int num;
|
||||
synchronized (mAuthorities) {
|
||||
if (DEBUG) Log.v(TAG, "clearPending");
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "clearPending");
|
||||
}
|
||||
num = mPendingOperations.size();
|
||||
mPendingOperations.clear();
|
||||
final int N = mSyncStatus.size();
|
||||
@ -806,14 +837,16 @@ public class SyncStorageEngine extends Handler {
|
||||
*/
|
||||
public void doDatabaseCleanup(Account[] accounts) {
|
||||
synchronized (mAuthorities) {
|
||||
if (DEBUG) Log.w(TAG, "Updating for new accounts...");
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.w(TAG, "Updating for new accounts...");
|
||||
SparseArray<AuthorityInfo> removing = new SparseArray<AuthorityInfo>();
|
||||
Iterator<AccountInfo> accIt = mAccounts.values().iterator();
|
||||
while (accIt.hasNext()) {
|
||||
AccountInfo acc = accIt.next();
|
||||
if (!ArrayUtils.contains(accounts, acc.account)) {
|
||||
// This account no longer exists...
|
||||
if (DEBUG) Log.w(TAG, "Account removed: " + acc.account);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.w(TAG, "Account removed: " + acc.account);
|
||||
}
|
||||
for (AuthorityInfo auth : acc.authorities.values()) {
|
||||
removing.put(auth.ident, auth);
|
||||
}
|
||||
@ -859,11 +892,13 @@ public class SyncStorageEngine extends Handler {
|
||||
public void setActiveSync(SyncManager.ActiveSyncContext activeSyncContext) {
|
||||
synchronized (mAuthorities) {
|
||||
if (activeSyncContext != null) {
|
||||
if (DEBUG) Log.v(TAG, "setActiveSync: account="
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "setActiveSync: account="
|
||||
+ activeSyncContext.mSyncOperation.account
|
||||
+ " auth=" + activeSyncContext.mSyncOperation.authority
|
||||
+ " src=" + activeSyncContext.mSyncOperation.syncSource
|
||||
+ " extras=" + activeSyncContext.mSyncOperation.extras);
|
||||
}
|
||||
if (mCurrentSync != null) {
|
||||
Log.w(TAG, "setActiveSync called with existing active sync!");
|
||||
}
|
||||
@ -878,7 +913,7 @@ public class SyncStorageEngine extends Handler {
|
||||
authority.account, authority.authority,
|
||||
activeSyncContext.mStartTime);
|
||||
} else {
|
||||
if (DEBUG) Log.v(TAG, "setActiveSync: null");
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "setActiveSync: null");
|
||||
mCurrentSync = null;
|
||||
}
|
||||
}
|
||||
@ -900,8 +935,10 @@ public class SyncStorageEngine extends Handler {
|
||||
long now, int source) {
|
||||
long id;
|
||||
synchronized (mAuthorities) {
|
||||
if (DEBUG) Log.v(TAG, "insertStartSyncEvent: account=" + accountName
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "insertStartSyncEvent: account=" + accountName
|
||||
+ " auth=" + authorityName + " source=" + source);
|
||||
}
|
||||
AuthorityInfo authority = getAuthorityLocked(accountName, authorityName,
|
||||
"insertStartSyncEvent");
|
||||
if (authority == null) {
|
||||
@ -919,7 +956,7 @@ public class SyncStorageEngine extends Handler {
|
||||
mSyncHistory.remove(mSyncHistory.size()-1);
|
||||
}
|
||||
id = item.historyId;
|
||||
if (DEBUG) Log.v(TAG, "returning historyId " + id);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "returning historyId " + id);
|
||||
}
|
||||
|
||||
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS);
|
||||
@ -944,10 +981,12 @@ public class SyncStorageEngine extends Handler {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void stopSyncEvent(long historyId, Bundle extras, long elapsedTime, String resultMessage,
|
||||
public void stopSyncEvent(long historyId, long elapsedTime, String resultMessage,
|
||||
long downstreamActivity, long upstreamActivity) {
|
||||
synchronized (mAuthorities) {
|
||||
if (DEBUG) Log.v(TAG, "stopSyncEvent: historyId=" + historyId);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "stopSyncEvent: historyId=" + historyId);
|
||||
}
|
||||
SyncHistoryItem item = null;
|
||||
int i = mSyncHistory.size();
|
||||
while (i > 0) {
|
||||
@ -989,14 +1028,6 @@ public class SyncStorageEngine extends Handler {
|
||||
break;
|
||||
case SOURCE_PERIODIC:
|
||||
status.numSourcePeriodic++;
|
||||
AuthorityInfo authority = mAuthorities.get(item.authorityId);
|
||||
for (int periodicSyncIndex = 0;
|
||||
periodicSyncIndex < authority.periodicSyncs.size();
|
||||
periodicSyncIndex++) {
|
||||
if (equals(extras, authority.periodicSyncs.get(periodicSyncIndex).first)) {
|
||||
status.setPeriodicSyncTime(periodicSyncIndex, item.eventTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1261,18 +1292,14 @@ public class SyncStorageEngine extends Handler {
|
||||
AuthorityInfo authority = account.authorities.get(authorityName);
|
||||
if (authority == null) {
|
||||
if (ident < 0) {
|
||||
// Look for a new identifier for this authority.
|
||||
final int N = mAuthorities.size();
|
||||
ident = 0;
|
||||
for (int i=0; i<N; i++) {
|
||||
if (mAuthorities.valueAt(i).ident > ident) {
|
||||
break;
|
||||
}
|
||||
ident++;
|
||||
}
|
||||
ident = mNextAuthorityId;
|
||||
mNextAuthorityId++;
|
||||
doWrite = true;
|
||||
}
|
||||
if (DEBUG) Log.v(TAG, "created a new AuthorityInfo for " + accountName
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "created a new AuthorityInfo for " + accountName
|
||||
+ ", provider " + authorityName);
|
||||
}
|
||||
authority = new AuthorityInfo(accountName, authorityName, ident);
|
||||
account.authorities.put(authorityName, authority);
|
||||
mAuthorities.put(ident, authority);
|
||||
@ -1284,13 +1311,15 @@ public class SyncStorageEngine extends Handler {
|
||||
return authority;
|
||||
}
|
||||
|
||||
private void removeAuthorityLocked(Account account, String authorityName) {
|
||||
private void removeAuthorityLocked(Account account, String authorityName, boolean doWrite) {
|
||||
AccountInfo accountInfo = mAccounts.get(account);
|
||||
if (accountInfo != null) {
|
||||
final AuthorityInfo authorityInfo = accountInfo.authorities.remove(authorityName);
|
||||
if (authorityInfo != null) {
|
||||
mAuthorities.remove(authorityInfo.ident);
|
||||
writeAccountInfoLocked();
|
||||
if (doWrite) {
|
||||
writeAccountInfoLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1340,7 +1369,11 @@ public class SyncStorageEngine extends Handler {
|
||||
readStatusLocked();
|
||||
readPendingOperationsLocked();
|
||||
readStatisticsLocked();
|
||||
readLegacyAccountInfoLocked();
|
||||
readAndDeleteLegacyAccountInfoLocked();
|
||||
writeAccountInfoLocked();
|
||||
writeStatusLocked();
|
||||
writePendingOperationsLocked();
|
||||
writeStatisticsLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1348,7 +1381,7 @@ public class SyncStorageEngine extends Handler {
|
||||
* Read all account information back in to the initial engine state.
|
||||
*/
|
||||
private void readAccountInfoLocked() {
|
||||
boolean writeNeeded = false;
|
||||
int highestAuthorityId = -1;
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = mAccountInfoFile.openRead();
|
||||
@ -1370,11 +1403,14 @@ public class SyncStorageEngine extends Handler {
|
||||
} catch (NumberFormatException e) {
|
||||
version = 0;
|
||||
}
|
||||
if (version < ACCOUNTS_VERSION) {
|
||||
writeNeeded = true;
|
||||
String nextIdString = parser.getAttributeValue(null, "nextAuthorityId");
|
||||
try {
|
||||
int id = (nextIdString == null) ? 0 : Integer.parseInt(nextIdString);
|
||||
mNextAuthorityId = Math.max(mNextAuthorityId, id);
|
||||
} catch (NumberFormatException e) {
|
||||
// don't care
|
||||
}
|
||||
mMasterSyncAutomatically = listen == null
|
||||
|| Boolean.parseBoolean(listen);
|
||||
mMasterSyncAutomatically = listen == null || Boolean.parseBoolean(listen);
|
||||
eventType = parser.next();
|
||||
AuthorityInfo authority = null;
|
||||
Pair<Bundle, Long> periodicSync = null;
|
||||
@ -1385,6 +1421,9 @@ public class SyncStorageEngine extends Handler {
|
||||
if ("authority".equals(tagName)) {
|
||||
authority = parseAuthority(parser, version);
|
||||
periodicSync = null;
|
||||
if (authority.ident > highestAuthorityId) {
|
||||
highestAuthorityId = authority.ident;
|
||||
}
|
||||
}
|
||||
} else if (parser.getDepth() == 3) {
|
||||
if ("periodicSync".equals(tagName) && authority != null) {
|
||||
@ -1407,6 +1446,7 @@ public class SyncStorageEngine extends Handler {
|
||||
else Log.w(TAG, "Error reading accounts", e);
|
||||
return;
|
||||
} finally {
|
||||
mNextAuthorityId = Math.max(highestAuthorityId + 1, mNextAuthorityId);
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
@ -1415,13 +1455,7 @@ public class SyncStorageEngine extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
if (maybeMigrateSettingsForRenamedAuthorities()) {
|
||||
writeNeeded = true;
|
||||
}
|
||||
|
||||
if (writeNeeded) {
|
||||
writeAccountInfoLocked();
|
||||
}
|
||||
maybeMigrateSettingsForRenamedAuthorities();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1463,7 +1497,8 @@ public class SyncStorageEngine extends Handler {
|
||||
}
|
||||
|
||||
for (AuthorityInfo authorityInfo : authoritiesToRemove) {
|
||||
removeAuthorityLocked(authorityInfo.account, authorityInfo.authority);
|
||||
removeAuthorityLocked(authorityInfo.account, authorityInfo.authority,
|
||||
false /* doWrite */);
|
||||
writeNeeded = true;
|
||||
}
|
||||
|
||||
@ -1593,6 +1628,7 @@ public class SyncStorageEngine extends Handler {
|
||||
|
||||
out.startTag(null, "accounts");
|
||||
out.attribute(null, "version", Integer.toString(ACCOUNTS_VERSION));
|
||||
out.attribute(null, "nextAuthorityId", Integer.toString(mNextAuthorityId));
|
||||
if (!mMasterSyncAutomatically) {
|
||||
out.attribute(null, "listen-for-tickles", "false");
|
||||
}
|
||||
@ -1675,7 +1711,7 @@ public class SyncStorageEngine extends Handler {
|
||||
* erase it. Note that we don't deal with pending operations, active
|
||||
* sync, or history.
|
||||
*/
|
||||
private void readLegacyAccountInfoLocked() {
|
||||
private void readAndDeleteLegacyAccountInfoLocked() {
|
||||
// Look for old database to initialize from.
|
||||
File file = mContext.getDatabasePath("syncmanager.db");
|
||||
if (!file.exists()) {
|
||||
@ -1792,8 +1828,6 @@ public class SyncStorageEngine extends Handler {
|
||||
|
||||
db.close();
|
||||
|
||||
writeAccountInfoLocked();
|
||||
writeStatusLocked();
|
||||
(new File(path)).delete();
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class SyncStorageEngineTest extends AndroidTestCase {
|
||||
long historyId = engine.insertStartSyncEvent(
|
||||
account, authority, time0, SyncStorageEngine.SOURCE_LOCAL);
|
||||
long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
|
||||
engine.stopSyncEvent(historyId, new Bundle(), time1 - time0, "yay", 0, 0);
|
||||
engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user