summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorMatthew Williams <mjwilliams@google.com>2013-09-06 16:06:17 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-09-06 16:06:17 +0000
commitabc1d89950aec7efed2e39dee7b13453050d1d5a (patch)
treeff2b65dae93f8827f6e533b550bf6cb725eb1145 /services
parenta2bcee619d91c9ff4821a85c9ea72b6391219309 (diff)
parent56dbf8f23677d28615e61ef2fbb0e738cca02528 (diff)
downloadframeworks_base-abc1d89950aec7efed2e39dee7b13453050d1d5a.zip
frameworks_base-abc1d89950aec7efed2e39dee7b13453050d1d5a.tar.gz
frameworks_base-abc1d89950aec7efed2e39dee7b13453050d1d5a.tar.bz2
Merge "Fix broken javadocs"
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/content/ContentService.java315
-rw-r--r--services/java/com/android/server/content/SyncManager.java1133
-rw-r--r--services/java/com/android/server/content/SyncOperation.java246
-rw-r--r--services/java/com/android/server/content/SyncQueue.java134
-rw-r--r--services/java/com/android/server/content/SyncStorageEngine.java1370
-rw-r--r--services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java253
6 files changed, 2023 insertions, 1428 deletions
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index a56af08..ab20461 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -25,6 +25,8 @@ import android.content.Context;
import android.content.IContentService;
import android.content.ISyncStatusObserver;
import android.content.PeriodicSync;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.content.SyncAdapterType;
import android.content.SyncInfo;
import android.content.SyncRequest;
@@ -315,7 +317,6 @@ public final class ContentService extends IContentService.Stub {
}
}
- @Override
public void requestSync(Account account, String authority, Bundle extras) {
ContentResolver.validateSyncExtrasBundle(extras);
int userId = UserHandle.getCallingUserId();
@@ -345,61 +346,56 @@ public final class ContentService extends IContentService.Stub {
* Depending on the request, we enqueue to suit in the SyncManager.
* @param request
*/
- @Override
public void sync(SyncRequest request) {
Bundle extras = request.getBundle();
ContentResolver.validateSyncExtrasBundle(extras);
- long flextime = request.getSyncFlexTime();
- long runAtTime = request.getSyncRunTime();
int userId = UserHandle.getCallingUserId();
- int uId = Binder.getCallingUid();
-
+ int callerUid = Binder.getCallingUid();
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
+ if (syncManager == null) return;
+
+ long flextime = request.getSyncFlexTime();
+ long runAtTime = request.getSyncRunTime();
+ if (request.isPeriodic()) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ SyncStorageEngine.EndPoint info;
+ if (!request.hasAuthority()) {
+ // Extra permissions checking for sync service.
+ verifySignatureForPackage(callerUid,
+ request.getService().getPackageName(), "sync");
+ info = new SyncStorageEngine.EndPoint(request.getService(), userId);
+ } else {
+ info = new SyncStorageEngine.EndPoint(
+ request.getAccount(), request.getProvider(), userId);
+ }
+ if (runAtTime < 60) {
+ Slog.w(TAG, "Requested poll frequency of " + runAtTime
+ + " seconds being rounded up to 60 seconds.");
+ runAtTime = 60;
+ }
+ // Schedule periodic sync.
+ getSyncManager().getSyncStorageEngine()
+ .updateOrAddPeriodicSync(info, runAtTime, flextime, extras);
+ } else {
+ long beforeRuntimeMillis = (flextime) * 1000;
+ long runtimeMillis = runAtTime * 1000;
if (request.hasAuthority()) {
- // Sync Adapter registered with the system - old API.
- final Account account = request.getProviderInfo().first;
- final String provider = request.getProviderInfo().second;
- if (request.isPeriodic()) {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.WRITE_SYNC_SETTINGS,
- "no permission to write the sync settings");
- if (runAtTime < 60) {
- Slog.w(TAG, "Requested poll frequency of " + runAtTime
- + " seconds being rounded up to 60 seconds.");
- runAtTime = 60;
- }
- PeriodicSync syncToAdd =
- new PeriodicSync(account, provider, extras, runAtTime, flextime);
- getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
- } else {
- long beforeRuntimeMillis = (flextime) * 1000;
- long runtimeMillis = runAtTime * 1000;
- syncManager.scheduleSync(
- account, userId, uId, provider, extras,
- beforeRuntimeMillis, runtimeMillis,
- false /* onlyThoseWithUnknownSyncableState */);
- }
+ syncManager.scheduleSync(
+ request.getAccount(), userId, callerUid, request.getProvider(), extras,
+ beforeRuntimeMillis, runtimeMillis,
+ false /* onlyThoseWithUnknownSyncableState */);
} else {
- // Anonymous sync - new API.
- final ComponentName syncService = request.getService();
- if (request.isPeriodic()) {
- throw new RuntimeException("Periodic anonymous syncs not implemented yet.");
- } else {
- long beforeRuntimeMillis = (flextime) * 1000;
- long runtimeMillis = runAtTime * 1000;
- syncManager.scheduleSync(
- syncService, userId, uId, extras,
- beforeRuntimeMillis,
- runtimeMillis,
- false /* onlyThoseWithUnknownSyncableState */); // Empty function.
- throw new RuntimeException("One-off anonymous syncs not implemented yet.");
- }
+ syncManager.scheduleSync(
+ request.getService(), userId, callerUid, extras,
+ beforeRuntimeMillis,
+ runtimeMillis); // Empty function.
}
}
} finally {
@@ -410,11 +406,13 @@ public final class ContentService extends IContentService.Stub {
/**
* Clear all scheduled sync operations that match the uri and cancel the active sync
* if they match the authority and account, if they are present.
- * @param account filter the pending and active syncs to cancel using this account
- * @param authority filter the pending and active syncs to cancel using this authority
+ *
+ * @param account filter the pending and active syncs to cancel using this account, or null.
+ * @param authority filter the pending and active syncs to cancel using this authority, or
+ * null.
+ * @param cname cancel syncs running on this service, or null for provider/account.
*/
- @Override
- public void cancelSync(Account account, String authority) {
+ public void cancelSync(Account account, String authority, ComponentName cname) {
int userId = UserHandle.getCallingUserId();
// This makes it so that future permission checks will be in the context of this
@@ -423,14 +421,54 @@ public final class ContentService extends IContentService.Stub {
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.clearScheduledSyncOperations(account, userId, authority);
- syncManager.cancelActiveSync(account, userId, authority);
+ SyncStorageEngine.EndPoint info;
+ if (cname == null) {
+ info = new SyncStorageEngine.EndPoint(account, authority, userId);
+ } else {
+ info = new SyncStorageEngine.EndPoint(cname, userId);
+ }
+ syncManager.clearScheduledSyncOperations(info);
+ syncManager.cancelActiveSync(info, null /* all syncs for this adapter */);
}
} finally {
restoreCallingIdentity(identityToken);
}
}
+ public void cancelRequest(SyncRequest request) {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager == null) return;
+ int userId = UserHandle.getCallingUserId();
+ int callerUid = Binder.getCallingUid();
+
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncStorageEngine.EndPoint info;
+ Bundle extras = new Bundle(request.getBundle());
+ if (request.hasAuthority()) {
+ Account account = request.getAccount();
+ String provider = request.getProvider();
+ info = new SyncStorageEngine.EndPoint(account, provider, userId);
+ } else {
+ // Only allowed to manipulate syncs for a service which you own.
+ ComponentName service = request.getService();
+ verifySignatureForPackage(callerUid, service.getPackageName(), "cancel");
+ info = new SyncStorageEngine.EndPoint(service, userId);
+ }
+ if (request.isPeriodic()) {
+ // Remove periodic sync.
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ getSyncManager().getSyncStorageEngine().removePeriodicSync(info, extras);
+ }
+ // Cancel active syncs and clear pending syncs from the queue.
+ syncManager.cancelScheduledSyncOperation(info, extras);
+ syncManager.cancelActiveSync(info, extras);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
/**
* Get information about the SyncAdapters that are known to the system.
* @return an array of SyncAdapters that have registered with the system
@@ -459,8 +497,8 @@ public final class ContentService extends IContentService.Stub {
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getSyncAutomatically(
- account, userId, providerName);
+ return syncManager.getSyncStorageEngine()
+ .getSyncAutomatically(account, userId, providerName);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -478,18 +516,15 @@ public final class ContentService extends IContentService.Stub {
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.getSyncStorageEngine().setSyncAutomatically(
- account, userId, providerName, sync);
+ syncManager.getSyncStorageEngine()
+ .setSyncAutomatically(account, userId, providerName, sync);
}
} finally {
restoreCallingIdentity(identityToken);
}
}
- /**
- * Old API. Schedule periodic sync with default flex time.
- */
- @Override
+ /** Old API. Schedule periodic sync with default flex time. */
public void addPeriodicSync(Account account, String authority, Bundle extras,
long pollFrequency) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
@@ -501,21 +536,22 @@ public final class ContentService extends IContentService.Stub {
+ " seconds being rounded up to 60 seconds.");
pollFrequency = 60;
}
+ long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
long identityToken = clearCallingIdentity();
try {
- // Add default flex time to this sync.
- PeriodicSync syncToAdd =
- new PeriodicSync(account, authority, extras,
- pollFrequency,
- SyncStorageEngine.calculateDefaultFlexTime(pollFrequency));
- getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
+ SyncStorageEngine.EndPoint info =
+ new SyncStorageEngine.EndPoint(account, authority, userId);
+ getSyncManager().getSyncStorageEngine()
+ .updateOrAddPeriodicSync(info,
+ pollFrequency,
+ defaultFlex,
+ extras);
} finally {
restoreCallingIdentity(identityToken);
}
}
- @Override
public void removePeriodicSync(Account account, String authority, Bundle extras) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
@@ -523,32 +559,34 @@ public final class ContentService extends IContentService.Stub {
long identityToken = clearCallingIdentity();
try {
- PeriodicSync syncToRemove = new PeriodicSync(account, authority, extras,
- 0 /* Not read for removal */, 0 /* Not read for removal */);
- getSyncManager().getSyncStorageEngine().removePeriodicSync(syncToRemove, userId);
+ getSyncManager().getSyncStorageEngine()
+ .removePeriodicSync(
+ new SyncStorageEngine.EndPoint(account, authority, userId),
+ extras);
} finally {
restoreCallingIdentity(identityToken);
}
}
- /**
- * TODO: Implement.
- * @param request Sync to remove.
- */
- public void removeSync(SyncRequest request) {
-
- }
-
- @Override
- public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
+ public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
+ ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
int userId = UserHandle.getCallingUserId();
+ int callerUid = Binder.getCallingUid();
long identityToken = clearCallingIdentity();
try {
- return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
- account, userId, providerName);
+ if (cname == null) {
+ return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
+ new SyncStorageEngine.EndPoint(account, providerName, userId));
+ } else if (account == null && providerName == null) {
+ verifySignatureForPackage(callerUid, cname.getPackageName(), "getPeriodicSyncs");
+ return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
+ new SyncStorageEngine.EndPoint(cname, userId));
+ } else {
+ throw new IllegalArgumentException("Invalid authority specified");
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -572,7 +610,6 @@ public final class ContentService extends IContentService.Stub {
return -1;
}
- @Override
public void setIsSyncable(Account account, String providerName, int syncable) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
@@ -590,6 +627,43 @@ public final class ContentService extends IContentService.Stub {
}
}
+ public void setServiceActive(ComponentName cname, boolean active) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ verifySignatureForPackage(Binder.getCallingUid(), cname.getPackageName(), "setIsEnabled");
+
+ int userId = UserHandle.getCallingUserId();
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ int syncable = active ? 1 : 0;
+ syncManager.getSyncStorageEngine().setIsEnabled(
+ cname, userId, syncable);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public boolean isServiceActive(ComponentName cname) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
+ "no permission to read the sync settings");
+ verifySignatureForPackage(Binder.getCallingUid(), cname.getPackageName(), "getIsEnabled");
+
+ int userId = UserHandle.getCallingUserId();
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ return (syncManager.getIsTargetServiceActive(cname, userId) == 1);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ return false;
+ }
+
@Override
public boolean getMasterSyncAutomatically() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
@@ -625,17 +699,24 @@ public final class ContentService extends IContentService.Stub {
}
}
- public boolean isSyncActive(Account account, String authority) {
+ public boolean isSyncActive(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
int userId = UserHandle.getCallingUserId();
-
+ int callingUid = Binder.getCallingUid();
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
+ if (syncManager == null) {
+ return false;
+ }
+ if (cname == null) {
return syncManager.getSyncStorageEngine().isSyncActive(
- account, userId, authority);
+ new SyncStorageEngine.EndPoint(account, authority, userId));
+ } else if (account == null && authority == null) {
+ verifySignatureForPackage(callingUid, cname.getPackageName(), "isSyncActive");
+ return syncManager.getSyncStorageEngine().isSyncActive(
+ new SyncStorageEngine.EndPoint(cname, userId));
}
} finally {
restoreCallingIdentity(identityToken);
@@ -656,39 +737,55 @@ public final class ContentService extends IContentService.Stub {
}
}
- public SyncStatusInfo getSyncStatus(Account account, String authority) {
+ public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
int userId = UserHandle.getCallingUserId();
-
+ int callerUid = Binder.getCallingUid();
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getStatusByAccountAndAuthority(
- account, userId, authority);
+ if (syncManager == null) {
+ return null;
+ }
+ SyncStorageEngine.EndPoint info;
+ if (cname == null) {
+ info = new SyncStorageEngine.EndPoint(account, authority, userId);
+ } else if (account == null && authority == null) {
+ verifySignatureForPackage(callerUid, cname.getPackageName(), "getSyncStatus");
+ info = new SyncStorageEngine.EndPoint(cname, userId);
+ } else {
+ throw new IllegalArgumentException("Must call sync status with valid authority");
}
+ return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
} finally {
restoreCallingIdentity(identityToken);
}
- return null;
}
- public boolean isSyncPending(Account account, String authority) {
+ public boolean isSyncPending(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
int userId = UserHandle.getCallingUserId();
-
+ int callerUid = Binder.getCallingUid();
long identityToken = clearCallingIdentity();
+ SyncManager syncManager = getSyncManager();
+ if (syncManager == null) return false;
+
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- return syncManager.getSyncStorageEngine().isSyncPending(account, userId, authority);
+ SyncStorageEngine.EndPoint info;
+ if (cname == null) {
+ info = new SyncStorageEngine.EndPoint(account, authority, userId);
+ } else if (account == null && authority == null) {
+ verifySignatureForPackage(callerUid, cname.getPackageName(), "isSyncPending");
+ info = new SyncStorageEngine.EndPoint(cname, userId);
+ } else {
+ throw new IllegalArgumentException("Invalid authority specified");
}
+ return syncManager.getSyncStorageEngine().isSyncPending(info);
} finally {
restoreCallingIdentity(identityToken);
}
- return false;
}
public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
@@ -722,6 +819,30 @@ public final class ContentService extends IContentService.Stub {
}
/**
+ * Helper to verify that the provided package name shares the same cert as the caller.
+ * @param callerUid uid of the calling process.
+ * @param packageName package to verify against package of calling application.
+ * @param tag a tag to use when throwing an exception if the signatures don't
+ * match. Cannot be null.
+ * @return true if the calling application and the provided package are signed with the same
+ * certificate.
+ */
+ private boolean verifySignatureForPackage(int callerUid, String packageName, String tag) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ int serviceUid = pm.getApplicationInfo(packageName, 0).uid;
+ if (pm.checkSignatures(callerUid, serviceUid) == PackageManager.SIGNATURE_MATCH) {
+ return true;
+ } else {
+ throw new SecurityException(tag + ": Caller certificate does not match that for - "
+ + packageName);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException(tag + ": " + packageName + " package not found.");
+ }
+ }
+
+ /**
* Hide this class since it is not part of api,
* but current unittest framework requires it to be public
* @hide
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index a6b69a2..3802415 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -31,6 +31,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.ISyncAdapter;
import android.content.ISyncContext;
+import android.content.ISyncServiceAdapter;
import android.content.ISyncStatusObserver;
import android.content.Intent;
import android.content.IntentFilter;
@@ -200,8 +201,9 @@ public class SyncManager {
Log.v(TAG, "Internal storage is low.");
}
mStorageIsLow = true;
- cancelActiveSync(null /* any account */, UserHandle.USER_ALL,
- null /* any authority */);
+ cancelActiveSync(
+ SyncStorageEngine.EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
+ null /* any sync */);
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Internal storage is ok.");
@@ -219,19 +221,6 @@ public class SyncManager {
}
};
- private BroadcastReceiver mBackgroundDataSettingChanged = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (getConnectivityManager().getBackgroundDataSetting()) {
- scheduleSync(null /* account */, UserHandle.USER_ALL,
- SyncOperation.REASON_BACKGROUND_DATA_SETTINGS_CHANGED,
- null /* authority */,
- new Bundle(), 0 /* delay */, 0 /* delay */,
- false /* onlyThoseWithUnknownSyncableState */);
- }
- }
- };
-
private BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -276,16 +265,16 @@ public class SyncManager {
doDatabaseCleanup();
}
+ AccountAndUser[] accounts = mRunningAccounts;
for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
- if (!containsAccountAndUser(mRunningAccounts,
- currentSyncContext.mSyncOperation.account,
- currentSyncContext.mSyncOperation.userId)) {
+ if (!containsAccountAndUser(accounts,
+ currentSyncContext.mSyncOperation.target.account,
+ currentSyncContext.mSyncOperation.target.userId)) {
Log.d(TAG, "canceling sync since the account is no longer running");
sendSyncFinishedOrCanceledMessage(currentSyncContext,
null /* no result since this is a cancel */);
}
}
-
// we must do this since we don't bother scheduling alarms when
// the accounts are not set yet
sendCheckAlarmsMessage();
@@ -380,12 +369,17 @@ public class SyncManager {
mSyncStorageEngine = SyncStorageEngine.getSingleton();
mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
@Override
- public void onSyncRequest(Account account, int userId, int reason, String authority,
- Bundle extras) {
- scheduleSync(account, userId, reason, authority, extras,
- 0 /* no delay */,
- 0 /* no delay */,
- false);
+ public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras) {
+ if (info.target_provider) {
+ scheduleSync(info.account, info.userId, reason, info.provider, extras,
+ 0 /* no flex */,
+ 0 /* run immediately */,
+ false);
+ } else if (info.target_service) {
+ scheduleSync(info.service, info.userId, reason, extras,
+ 0 /* no flex */,
+ 0 /* run immediately */);
+ }
}
});
@@ -417,9 +411,6 @@ public class SyncManager {
context.registerReceiver(mBootCompletedReceiver, intentFilter);
}
- intentFilter = new IntentFilter(ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
- context.registerReceiver(mBackgroundDataSettingChanged, intentFilter);
-
intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
context.registerReceiver(mStorageIntentReceiver, intentFilter);
@@ -532,181 +523,106 @@ public class SyncManager {
}
}
+ /**
+ * TODO: Decide if restricted users have different sync options for the sync service (as is
+ * the case with sync adapters).
+ */
+ public int getIsTargetServiceActive(ComponentName cname, int userId) {
+ return mSyncStorageEngine.getIsTargetServiceActive(cname, userId);
+ }
+
private void ensureAlarmService() {
if (mAlarmService == null) {
- mAlarmService = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
}
}
/**
* Initiate a sync using the new anonymous service API.
- * TODO: Implement.
* @param cname SyncService component bound to in order to perform the sync.
* @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
* then all users' accounts are considered.
* @param uid Linux uid of the application that is performing the sync.
* @param extras a Map of SyncAdapter-specific information to control
* syncs of a specific provider. Can be null.
- * @param beforeRunTimeMillis
- * @param runtimeMillis
+ * @param beforeRunTimeMillis milliseconds before <code>runtimeMillis</code> that this sync may
+ * be run.
+ * @param runtimeMillis milliseconds from now by which this sync must be run.
*/
public void scheduleSync(ComponentName cname, int userId, int uid, Bundle extras,
- long beforeRunTimeMillis, long runtimeMillis,
- boolean onlyThoseWithUnknownSyncableState) {
-/**
+ long beforeRunTimeMillis, long runtimeMillis) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
-
- final boolean backgroundDataUsageAllowed = !mBootCompleted ||
- getConnectivityManager().getBackgroundDataSetting();
-
- if (extras == null) {
- extras = new Bundle();
- }
if (isLoggable) {
- Log.e(TAG, requestedAccount + " " + extras.toString() + " " + requestedAuthority);
+ Log.d(TAG, "one off sync for: " + cname + " " + extras.toString());
}
+
Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
if (expedited) {
runtimeMillis = -1; // this means schedule at the front of the queue
}
- AccountAndUser[] accounts;
- if (requestedAccount != null && userId != UserHandle.USER_ALL) {
- accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
- } else {
- // if the accounts aren't configured yet then we can't support an account-less
- // sync request
- accounts = mRunningAccounts;
- if (accounts.length == 0) {
- if (isLoggable) {
- Log.v(TAG, "scheduleSync: no accounts configured, dropping");
- }
- return;
- }
- }
-
- final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
- final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
- if (manualSync) {
- extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
- extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
- }
final boolean ignoreSettings =
extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
-
- int source;
- if (uploadOnly) {
- source = SyncStorageEngine.SOURCE_LOCAL;
- } else if (manualSync) {
- source = SyncStorageEngine.SOURCE_USER;
- } else if (requestedAuthority == null) {
- source = SyncStorageEngine.SOURCE_POLL;
- } else {
- // this isn't strictly server, since arbitrary callers can (and do) request
- // a non-forced two-way sync on a specific url
- source = SyncStorageEngine.SOURCE_SERVER;
+ int source = SyncStorageEngine.SOURCE_SERVICE;
+ int isEnabled = getIsTargetServiceActive(cname, userId);
+ // Only schedule this sync if
+ // - we've explicitly been told to ignore settings.
+ // - global sync is enabled for this user.
+ boolean syncAllowed =
+ ignoreSettings
+ || mSyncStorageEngine.getMasterSyncAutomatically(userId);
+ if (!syncAllowed) {
+ if (isLoggable) {
+ Log.d(TAG, "scheduleSync: sync of " + cname + " not allowed, dropping request.");
+ }
+ return;
}
-
- for (AccountAndUser account : accounts) {
- // Compile a list of authorities that have sync adapters.
- // For each authority sync each account that matches a sync adapter.
- final HashSet<String> syncableAuthorities = new HashSet<String>();
- for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
- mSyncAdapters.getAllServices(account.userId)) {
- syncableAuthorities.add(syncAdapter.type.authority);
+ if (isEnabled == 0) {
+ if (isLoggable) {
+ Log.d(TAG, "scheduleSync: " + cname + " is not enabled, dropping request");
+ }
+ return;
+ }
+ SyncStorageEngine.EndPoint info = new SyncStorageEngine.EndPoint(cname, userId);
+ Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(info);
+ long delayUntil = mSyncStorageEngine.getDelayUntilTime(info);
+ final long backoffTime = backoff != null ? backoff.first : 0;
+ if (isEnabled < 0) {
+ // Initialisation sync.
+ Bundle newExtras = new Bundle();
+ newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+ if (isLoggable) {
+ Log.v(TAG, "schedule initialisation Sync:"
+ + ", delay until " + delayUntil
+ + ", run now "
+ + ", source " + source
+ + ", sync service " + cname
+ + ", extras " + newExtras);
}
-
- // if the url was specified then replace the list of authorities
- // with just this authority or clear it if this authority isn't
- // syncable
- if (requestedAuthority != null) {
- final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
- syncableAuthorities.clear();
- if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
+ scheduleSyncOperation(
+ new SyncOperation(cname, userId, uid, source, newExtras,
+ 0 /* runtime */,
+ 0 /* flextime */,
+ backoffTime,
+ delayUntil));
+ } else {
+ if (isLoggable) {
+ Log.v(TAG, "schedule Sync:"
+ + ", delay until " + delayUntil
+ + ", run by " + runtimeMillis
+ + ", flex " + beforeRunTimeMillis
+ + ", source " + source
+ + ", sync service " + cname
+ + ", extras " + extras);
}
+ scheduleSyncOperation(
+ new SyncOperation(cname, userId, uid, source, extras,
+ runtimeMillis /* runtime */,
+ beforeRunTimeMillis /* flextime */,
+ backoffTime,
+ delayUntil));
+ }
- for (String authority : syncableAuthorities) {
- int isSyncable = getIsSyncable(account.account, account.userId,
- authority);
- if (isSyncable == 0) {
- continue;
- }
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
- syncAdapterInfo = mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(authority, account.account.type), account.userId);
- if (syncAdapterInfo == null) {
- continue;
- }
- final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
- final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
- if (isSyncable < 0 && isAlwaysSyncable) {
- mSyncStorageEngine.setIsSyncable(account.account, account.userId, authority, 1);
- isSyncable = 1;
- }
- if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
- continue;
- }
- if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
- continue;
- }
-
- // always allow if the isSyncable state is unknown
- boolean syncAllowed =
- (isSyncable < 0)
- || ignoreSettings
- || (backgroundDataUsageAllowed
- && mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
- && mSyncStorageEngine.getSyncAutomatically(account.account,
- account.userId, authority));
- if (!syncAllowed) {
- if (isLoggable) {
- Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
- + " is not allowed, dropping request");
- }
- continue;
- }
-
- Pair<Long, Long> backoff = mSyncStorageEngine
- .getBackoff(account.account, account.userId, authority);
- long delayUntil = mSyncStorageEngine.getDelayUntilTime(account.account,
- account.userId, authority);
- final long backoffTime = backoff != null ? backoff.first : 0;
- if (isSyncable < 0) {
- // Initialisation sync.
- Bundle newExtras = new Bundle();
- newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
- if (isLoggable) {
- Log.v(TAG, "schedule initialisation Sync:"
- + ", delay until " + delayUntil
- + ", run by " + 0
- + ", source " + source
- + ", account " + account
- + ", authority " + authority
- + ", extras " + newExtras);
- }
- scheduleSyncOperation(
- new SyncOperation(account.account, account.userId, reason, source,
- authority, newExtras, 0 /* immediate , 0 /* No flex time,
- backoffTime, delayUntil, allowParallelSyncs));
- }
- if (!onlyThoseWithUnkownSyncableState) {
- if (isLoggable) {
- Log.v(TAG, "scheduleSync:"
- + " delay until " + delayUntil
- + " run by " + runtimeMillis
- + " flex " + beforeRuntimeMillis
- + ", source " + source
- + ", account " + account
- + ", authority " + authority
- + ", extras " + extras);
- }
- scheduleSyncOperation(
- new SyncOperation(account.account, account.userId, reason, source,
- authority, extras, runtimeMillis, beforeRuntimeMillis,
- backoffTime, delayUntil, allowParallelSyncs));
- }
- }
- }*/
}
/**
@@ -755,9 +671,6 @@ public class SyncManager {
long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
- final boolean backgroundDataUsageAllowed = !mBootCompleted ||
- getConnectivityManager().getBackgroundDataSetting();
-
if (extras == null) {
extras = new Bundle();
}
@@ -774,8 +687,6 @@ public class SyncManager {
if (requestedAccount != null && userId != UserHandle.USER_ALL) {
accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
} else {
- // if the accounts aren't configured yet then we can't support an account-less
- // sync request
accounts = mRunningAccounts;
if (accounts.length == 0) {
if (isLoggable) {
@@ -850,12 +761,10 @@ public class SyncManager {
continue;
}
- // always allow if the isSyncable state is unknown
boolean syncAllowed =
- (isSyncable < 0)
+ (isSyncable < 0) // always allow if the isSyncable state is unknown
|| ignoreSettings
- || (backgroundDataUsageAllowed
- && mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
+ || (mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
&& mSyncStorageEngine.getSyncAutomatically(account.account,
account.userId, authority));
if (!syncAllowed) {
@@ -865,11 +774,12 @@ public class SyncManager {
}
continue;
}
-
- Pair<Long, Long> backoff = mSyncStorageEngine
- .getBackoff(account.account, account.userId, authority);
- long delayUntil = mSyncStorageEngine.getDelayUntilTime(account.account,
- account.userId, authority);
+ SyncStorageEngine.EndPoint info =
+ new SyncStorageEngine.EndPoint(
+ account.account, authority, account.userId);
+ Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(info);
+ long delayUntil =
+ mSyncStorageEngine.getDelayUntilTime(info);
final long backoffTime = backoff != null ? backoff.first : 0;
if (isSyncable < 0) {
// Initialisation sync.
@@ -879,6 +789,7 @@ public class SyncManager {
Log.v(TAG, "schedule initialisation Sync:"
+ ", delay until " + delayUntil
+ ", run by " + 0
+ + ", flex " + 0
+ ", source " + source
+ ", account " + account
+ ", authority " + authority
@@ -954,13 +865,12 @@ public class SyncManager {
mSyncHandler.sendMessage(msg);
}
- private void sendCancelSyncsMessage(final Account account, final int userId,
- final String authority) {
+ private void sendCancelSyncsMessage(final SyncStorageEngine.EndPoint info, Bundle extras) {
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_CANCEL");
Message msg = mSyncHandler.obtainMessage();
msg.what = SyncHandler.MESSAGE_CANCEL;
- msg.obj = Pair.create(account, authority);
- msg.arg1 = userId;
+ msg.setData(extras);
+ msg.obj = info;
mSyncHandler.sendMessage(msg);
}
@@ -983,10 +893,11 @@ public class SyncManager {
}
private void clearBackoffSetting(SyncOperation op) {
- mSyncStorageEngine.setBackoff(op.account, op.userId, op.authority,
- SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
+ mSyncStorageEngine.setBackoff(op.target,
+ SyncStorageEngine.NOT_IN_BACKOFF_MODE,
+ SyncStorageEngine.NOT_IN_BACKOFF_MODE);
synchronized (mSyncQueue) {
- mSyncQueue.onBackoffChanged(op.account, op.userId, op.authority, 0);
+ mSyncQueue.onBackoffChanged(op.target, 0);
}
}
@@ -996,7 +907,7 @@ public class SyncManager {
final long now = SystemClock.elapsedRealtime();
final Pair<Long, Long> previousSettings =
- mSyncStorageEngine.getBackoff(op.account, op.userId, op.authority);
+ mSyncStorageEngine.getBackoff(op.target);
long newDelayInMs = -1;
if (previousSettings != null) {
// don't increase backoff before current backoff is expired. This will happen for op's
@@ -1027,14 +938,12 @@ public class SyncManager {
final long backoff = now + newDelayInMs;
- mSyncStorageEngine.setBackoff(op.account, op.userId, op.authority,
- backoff, newDelayInMs);
-
+ mSyncStorageEngine.setBackoff(op.target, backoff, newDelayInMs);
op.backoff = backoff;
op.updateEffectiveRunTime();
synchronized (mSyncQueue) {
- mSyncQueue.onBackoffChanged(op.account, op.userId, op.authority, backoff);
+ mSyncQueue.onBackoffChanged(op.target, backoff);
}
}
@@ -1047,20 +956,20 @@ public class SyncManager {
} else {
newDelayUntilTime = 0;
}
- mSyncStorageEngine
- .setDelayUntilTime(op.account, op.userId, op.authority, newDelayUntilTime);
+ mSyncStorageEngine.setDelayUntilTime(op.target, newDelayUntilTime);
synchronized (mSyncQueue) {
- mSyncQueue.onDelayUntilTimeChanged(op.account, op.authority, newDelayUntilTime);
+ mSyncQueue.onDelayUntilTimeChanged(op.target, newDelayUntilTime);
}
}
/**
* Cancel the active sync if it matches the authority and account.
- * @param account limit the cancelations to syncs with this account, if non-null
- * @param authority limit the cancelations to syncs with this authority, if non-null
+ * @param info object containing info about which syncs to cancel. The authority can
+ * have null account/provider info to specify all accounts/providers.
+ * @param extras if non-null, specifies the exact sync to remove.
*/
- public void cancelActiveSync(Account account, int userId, String authority) {
- sendCancelSyncsMessage(account, userId, authority);
+ public void cancelActiveSync(SyncStorageEngine.EndPoint info, Bundle extras) {
+ sendCancelSyncsMessage(info, extras);
}
/**
@@ -1089,24 +998,40 @@ public class SyncManager {
/**
* Remove scheduled sync operations.
- * @param account limit the removals to operations with this account, if non-null
- * @param authority limit the removals to operations with this authority, if non-null
+ * @param info limit the removals to operations that match this authority. The authority can
+ * have null account/provider info to specify all accounts/providers.
*/
- public void clearScheduledSyncOperations(Account account, int userId, String authority) {
+ public void clearScheduledSyncOperations(SyncStorageEngine.EndPoint info) {
synchronized (mSyncQueue) {
- mSyncQueue.remove(account, userId, authority);
+ mSyncQueue.remove(info, null /* all operations */);
}
- mSyncStorageEngine.setBackoff(account, userId, authority,
+ mSyncStorageEngine.setBackoff(info,
SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
}
+ /**
+ * Remove a specified sync, if it exists.
+ * @param info Authority for which the sync is to be removed.
+ * @param extras extras bundle to uniquely identify sync.
+ */
+ public void cancelScheduledSyncOperation(SyncStorageEngine.EndPoint info, Bundle extras) {
+ synchronized (mSyncQueue) {
+ mSyncQueue.remove(info, extras);
+ }
+ // Reset the back-off if there are no more syncs pending.
+ if (!mSyncStorageEngine.isSyncPending(info)) {
+ mSyncStorageEngine.setBackoff(info,
+ SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
+ }
+ }
+
void maybeRescheduleSync(SyncResult syncResult, SyncOperation operation) {
boolean isLoggable = Log.isLoggable(TAG, Log.DEBUG);
if (isLoggable) {
Log.d(TAG, "encountered error(s) during the sync: " + syncResult + ", " + operation);
}
- operation = new SyncOperation(operation);
+ operation = new SyncOperation(operation, 0L /* newRunTimeFromNow */);
// The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
// request. Retries of the request will always honor the backoff, so clear the
@@ -1115,25 +1040,29 @@ public class SyncManager {
operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
}
- // If this sync aborted because the internal sync loop retried too many times then
- // don't reschedule. Otherwise we risk getting into a retry loop.
- // If the operation succeeded to some extent then retry immediately.
- // If this was a two-way sync then retry soft errors with an exponential backoff.
- // If this was an upward sync then schedule a two-way sync immediately.
- // Otherwise do not reschedule.
if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)) {
- Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
- + operation);
+ if (isLoggable) {
+ Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
+ + operation);
+ }
} else if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)
&& !syncResult.syncAlreadyInProgress) {
+ // If this was an upward sync then schedule a two-way sync immediately.
operation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
- Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
- + "encountered an error: " + operation);
+ if (isLoggable) {
+ Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
+ + "encountered an error: " + operation);
+ }
scheduleSyncOperation(operation);
} else if (syncResult.tooManyRetries) {
- Log.d(TAG, "not retrying sync operation because it retried too many times: "
- + operation);
+ // If this sync aborted because the internal sync loop retried too many times then
+ // don't reschedule. Otherwise we risk getting into a retry loop.
+ if (isLoggable) {
+ Log.d(TAG, "not retrying sync operation because it retried too many times: "
+ + operation);
+ }
} else if (syncResult.madeSomeProgress()) {
+ // If the operation succeeded to some extent then retry immediately.
if (isLoggable) {
Log.d(TAG, "retrying sync operation because even though it had an error "
+ "it achieved some success");
@@ -1146,19 +1075,18 @@ public class SyncManager {
}
scheduleSyncOperation(
new SyncOperation(
- operation.account, operation.userId,
- operation.reason,
- operation.syncSource,
- operation.authority, operation.extras,
- DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000, operation.flexTime,
- operation.backoff, operation.delayUntil, operation.allowParallelSyncs));
+ operation,
+ DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000 /* newRunTimeFromNow */)
+ );
} else if (syncResult.hasSoftError()) {
+ // If this was a two-way sync then retry soft errors with an exponential backoff.
if (isLoggable) {
Log.d(TAG, "retrying sync operation because it encountered a soft error: "
+ operation);
}
scheduleSyncOperation(operation);
} else {
+ // Otherwise do not reschedule.
Log.d(TAG, "not retrying sync operation because the error is a hard error: "
+ operation);
}
@@ -1191,9 +1119,12 @@ public class SyncManager {
updateRunningAccounts();
cancelActiveSync(
- null /* any account */,
- userId,
- null /* any authority */);
+ new SyncStorageEngine.EndPoint(
+ null /* any account */,
+ null /* any authority */,
+ userId),
+ null /* any sync. */
+ );
}
private void onUserRemoved(int userId) {
@@ -1202,7 +1133,7 @@ public class SyncManager {
// Clean up the storage engine database
mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId);
synchronized (mSyncQueue) {
- mSyncQueue.removeUser(userId);
+ mSyncQueue.removeUserLocked(userId);
}
}
@@ -1214,6 +1145,7 @@ public class SyncManager {
final SyncOperation mSyncOperation;
final long mHistoryRowId;
ISyncAdapter mSyncAdapter;
+ ISyncServiceAdapter mSyncServiceAdapter;
final long mStartTime;
long mTimeoutStartTime;
boolean mBound;
@@ -1239,10 +1171,10 @@ public class SyncManager {
mSyncOperation = syncOperation;
mHistoryRowId = historyRowId;
mSyncAdapter = null;
+ mSyncServiceAdapter = null;
mStartTime = SystemClock.elapsedRealtime();
mTimeoutStartTime = mStartTime;
- mSyncWakeLock = mSyncHandler.getSyncWakeLock(
- mSyncOperation.account, mSyncOperation.authority);
+ mSyncWakeLock = mSyncHandler.getSyncWakeLock(mSyncOperation);
mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterUid));
mSyncWakeLock.acquire();
}
@@ -1269,7 +1201,12 @@ public class SyncManager {
public void onServiceConnected(ComponentName name, IBinder service) {
Message msg = mSyncHandler.obtainMessage();
msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
- msg.obj = new ServiceConnectionData(this, ISyncAdapter.Stub.asInterface(service));
+ if (mSyncOperation.target.target_provider) {
+ msg.arg1 = SyncOperation.SYNC_TARGET_ADAPTER;
+ } else {
+ msg.arg1 = SyncOperation.SYNC_TARGET_SERVICE;
+ }
+ msg.obj = new ServiceConnectionData(this, service);
mSyncHandler.sendMessage(msg);
}
@@ -1280,13 +1217,13 @@ public class SyncManager {
mSyncHandler.sendMessage(msg);
}
- boolean bindToSyncAdapter(RegisteredServicesCache.ServiceInfo info, int userId) {
+ boolean bindToSyncAdapter(ComponentName serviceComponent, int userId) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "bindToSyncAdapter: " + info.componentName + ", connection " + this);
+ Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);
}
Intent intent = new Intent();
intent.setAction("android.content.SyncAdapter");
- intent.setComponent(info.componentName);
+ intent.setComponent(serviceComponent);
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.sync_binding_label);
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
@@ -1296,7 +1233,7 @@ public class SyncManager {
final boolean bindResult = mContext.bindServiceAsUser(intent, this,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
| Context.BIND_ALLOW_OOM_MANAGEMENT,
- new UserHandle(mSyncOperation.userId));
+ new UserHandle(mSyncOperation.target.userId));
if (!bindResult) {
mBound = false;
}
@@ -1319,7 +1256,6 @@ public class SyncManager {
mSyncWakeLock.setWorkSource(null);
}
- @Override
public String toString() {
StringBuilder sb = new StringBuilder();
toString(sb);
@@ -1458,11 +1394,14 @@ public class SyncManager {
int row = table.getNumRows();
Pair<AuthorityInfo, SyncStatusInfo> syncAuthoritySyncStatus =
mSyncStorageEngine.getCopyOfAuthorityWithSyncStatus(
- account.account, account.userId, syncAdapterType.type.authority);
+ new SyncStorageEngine.EndPoint(
+ account.account,
+ syncAdapterType.type.authority,
+ account.userId));
SyncStorageEngine.AuthorityInfo settings = syncAuthoritySyncStatus.first;
SyncStatusInfo status = syncAuthoritySyncStatus.second;
- String authority = settings.authority;
+ String authority = settings.base.provider;
if (authority.length() > 50) {
authority = authority.substring(authority.length() - 50);
}
@@ -1583,14 +1522,25 @@ public class SyncManager {
int maxAuthority = 0;
int maxAccount = 0;
for (SyncStorageEngine.SyncHistoryItem item : items) {
- SyncStorageEngine.AuthorityInfo authority
+ SyncStorageEngine.AuthorityInfo authorityInfo
= mSyncStorageEngine.getAuthority(item.authorityId);
final String authorityName;
final String accountKey;
- if (authority != null) {
- authorityName = authority.authority;
- accountKey = authority.account.name + "/" + authority.account.type
- + " u" + authority.userId;
+ if (authorityInfo != null) {
+ if (authorityInfo.base.target_provider) {
+ authorityName = authorityInfo.base.provider;
+ accountKey = authorityInfo.base.account.name + "/"
+ + authorityInfo.base.account.type
+ + " u" + authorityInfo.base.userId;
+ } else if (authorityInfo.base.target_service) {
+ authorityName = authorityInfo.base.service.getPackageName() + "/"
+ + authorityInfo.base.service.getClassName()
+ + " u" + authorityInfo.base.userId;
+ accountKey = "no account";
+ } else {
+ authorityName = "Unknown";
+ accountKey = "Unknown";
+ }
} else {
authorityName = "Unknown";
accountKey = "Unknown";
@@ -1711,14 +1661,25 @@ public class SyncManager {
final PackageManager pm = mContext.getPackageManager();
for (int i = 0; i < N; i++) {
SyncStorageEngine.SyncHistoryItem item = items.get(i);
- SyncStorageEngine.AuthorityInfo authority
+ SyncStorageEngine.AuthorityInfo authorityInfo
= mSyncStorageEngine.getAuthority(item.authorityId);
final String authorityName;
final String accountKey;
- if (authority != null) {
- authorityName = authority.authority;
- accountKey = authority.account.name + "/" + authority.account.type
- + " u" + authority.userId;
+ if (authorityInfo != null) {
+ if (authorityInfo.base.target_provider) {
+ authorityName = authorityInfo.base.provider;
+ accountKey = authorityInfo.base.account.name + "/"
+ + authorityInfo.base.account.type
+ + " u" + authorityInfo.base.userId;
+ } else if (authorityInfo.base.target_service) {
+ authorityName = authorityInfo.base.service.getPackageName() + "/"
+ + authorityInfo.base.service.getClassName()
+ + " u" + authorityInfo.base.userId;
+ accountKey = "none";
+ } else {
+ authorityName = "Unknown";
+ accountKey = "Unknown";
+ }
} else {
authorityName = "Unknown";
accountKey = "Unknown";
@@ -1777,14 +1738,25 @@ public class SyncManager {
if (extras == null || extras.size() == 0) {
continue;
}
- final SyncStorageEngine.AuthorityInfo authority
+ final SyncStorageEngine.AuthorityInfo authorityInfo
= mSyncStorageEngine.getAuthority(item.authorityId);
final String authorityName;
final String accountKey;
- if (authority != null) {
- authorityName = authority.authority;
- accountKey = authority.account.name + "/" + authority.account.type
- + " u" + authority.userId;
+ if (authorityInfo != null) {
+ if (authorityInfo.base.target_provider) {
+ authorityName = authorityInfo.base.provider;
+ accountKey = authorityInfo.base.account.name + "/"
+ + authorityInfo.base.account.type
+ + " u" + authorityInfo.base.userId;
+ } else if (authorityInfo.base.target_service) {
+ authorityName = authorityInfo.base.service.getPackageName() + "/"
+ + authorityInfo.base.service.getClassName()
+ + " u" + authorityInfo.base.userId;
+ accountKey = "none";
+ } else {
+ authorityName = "Unknown";
+ accountKey = "Unknown";
+ }
} else {
authorityName = "Unknown";
accountKey = "Unknown";
@@ -1928,10 +1900,11 @@ public class SyncManager {
class ServiceConnectionData {
public final ActiveSyncContext activeSyncContext;
- public final ISyncAdapter syncAdapter;
- ServiceConnectionData(ActiveSyncContext activeSyncContext, ISyncAdapter syncAdapter) {
+ public final IBinder adapter;
+
+ ServiceConnectionData(ActiveSyncContext activeSyncContext, IBinder adapter) {
this.activeSyncContext = activeSyncContext;
- this.syncAdapter = syncAdapter;
+ this.adapter = adapter;
}
}
@@ -1951,8 +1924,7 @@ public class SyncManager {
public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
private Long mAlarmScheduleTime = null;
public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
- private final HashMap<Pair<Account, String>, PowerManager.WakeLock> mWakeLocks =
- Maps.newHashMap();
+ private final HashMap<String, PowerManager.WakeLock> mWakeLocks = Maps.newHashMap();
private volatile CountDownLatch mReadyToRunLatch = new CountDownLatch(1);
@@ -1966,12 +1938,11 @@ public class SyncManager {
}
}
- private PowerManager.WakeLock getSyncWakeLock(Account account, String authority) {
- final Pair<Account, String> wakeLockKey = Pair.create(account, authority);
+ private PowerManager.WakeLock getSyncWakeLock(SyncOperation operation) {
+ final String wakeLockKey = operation.wakeLockKey();
PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
if (wakeLock == null) {
- final String name = SYNC_WAKE_LOCK_PREFIX + "/" + authority + "/" + account.type
- + "/" + account.name;
+ final String name = SYNC_WAKE_LOCK_PREFIX + operation.wakeLockName();
wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
wakeLock.setReferenceCounted(false);
mWakeLocks.put(wakeLockKey, wakeLock);
@@ -2020,7 +1991,6 @@ public class SyncManager {
super(looper);
}
- @Override
public void handleMessage(Message msg) {
long earliestFuturePollTime = Long.MAX_VALUE;
long nextPendingSyncTime = Long.MAX_VALUE;
@@ -2038,12 +2008,13 @@ public class SyncManager {
earliestFuturePollTime = scheduleReadyPeriodicSyncs();
switch (msg.what) {
case SyncHandler.MESSAGE_CANCEL: {
- Pair<Account, String> payload = (Pair<Account, String>) msg.obj;
+ SyncStorageEngine.EndPoint payload = (SyncStorageEngine.EndPoint) msg.obj;
+ Bundle extras = msg.peekData();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CANCEL: "
- + payload.first + ", " + payload.second);
+ + payload + " bundle: " + extras);
}
- cancelActiveSyncLocked(payload.first, msg.arg1, payload.second);
+ cancelActiveSyncLocked(payload, extras);
nextPendingSyncTime = maybeStartNextSyncLocked();
break;
}
@@ -2052,35 +2023,39 @@ public class SyncManager {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_SYNC_FINISHED");
}
- SyncHandlerMessagePayload payload = (SyncHandlerMessagePayload)msg.obj;
+ SyncHandlerMessagePayload payload = (SyncHandlerMessagePayload) msg.obj;
if (!isSyncStillActive(payload.activeSyncContext)) {
Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
+ "sync is no longer active: "
+ payload.activeSyncContext);
break;
}
- runSyncFinishedOrCanceledLocked(payload.syncResult, payload.activeSyncContext);
+ runSyncFinishedOrCanceledLocked(payload.syncResult,
+ payload.activeSyncContext);
// since a sync just finished check if it is time to start a new sync
nextPendingSyncTime = maybeStartNextSyncLocked();
break;
case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
- ServiceConnectionData msgData = (ServiceConnectionData)msg.obj;
+ ServiceConnectionData msgData = (ServiceConnectionData) msg.obj;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
+ msgData.activeSyncContext);
}
// check that this isn't an old message
if (isSyncStillActive(msgData.activeSyncContext)) {
- runBoundToSyncAdapter(msgData.activeSyncContext, msgData.syncAdapter);
+ runBoundToAdapter(
+ msgData.activeSyncContext,
+ msgData.adapter,
+ msg.arg1 /* target */);
}
break;
}
case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
final ActiveSyncContext currentSyncContext =
- ((ServiceConnectionData)msg.obj).activeSyncContext;
+ ((ServiceConnectionData) msg.obj).activeSyncContext;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
+ currentSyncContext);
@@ -2089,12 +2064,15 @@ public class SyncManager {
if (isSyncStillActive(currentSyncContext)) {
// cancel the sync if we have a syncadapter, which means one is
// outstanding
- if (currentSyncContext.mSyncAdapter != null) {
- try {
+ try {
+ if (currentSyncContext.mSyncAdapter != null) {
currentSyncContext.mSyncAdapter.cancelSync(currentSyncContext);
- } catch (RemoteException e) {
- // we don't need to retry this in this case
+ } else if (currentSyncContext.mSyncServiceAdapter != null) {
+ currentSyncContext.mSyncServiceAdapter
+ .cancelSync(currentSyncContext);
}
+ } catch (RemoteException e) {
+ // We don't need to retry this in this case.
}
// pretend that the sync failed with an IOException,
@@ -2139,9 +2117,46 @@ public class SyncManager {
}
}
+ private boolean isDispatchable(SyncStorageEngine.EndPoint target) {
+ final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+ if (target.target_provider) {
+ // skip the sync if the account of this operation no longer exists
+ AccountAndUser[] accounts = mRunningAccounts;
+ if (!containsAccountAndUser(
+ accounts, target.account, target.userId)) {
+ return false;
+ }
+ if (!mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
+ || !mSyncStorageEngine.getSyncAutomatically(
+ target.account,
+ target.userId,
+ target.provider)) {
+ if (isLoggable) {
+ Log.v(TAG, " Not scheduling periodic operation: sync turned off.");
+ }
+ return false;
+ }
+ if (getIsSyncable(target.account, target.userId, target.provider)
+ == 0) {
+ if (isLoggable) {
+ Log.v(TAG, " Not scheduling periodic operation: isSyncable == 0.");
+ }
+ return false;
+ }
+ } else if (target.target_service) {
+ if (getIsTargetServiceActive(target.service, target.userId) == 0) {
+ if (isLoggable) {
+ Log.v(TAG, " Not scheduling periodic operation: isEnabled == 0.");
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* 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,
+ * @return the desired start time of the earliest future periodic sync operation,
* in milliseconds since boot
*/
private long scheduleReadyPeriodicSyncs() {
@@ -2149,14 +2164,7 @@ public class SyncManager {
if (isLoggable) {
Log.v(TAG, "scheduleReadyPeriodicSyncs");
}
- final boolean backgroundDataUsageAllowed =
- getConnectivityManager().getBackgroundDataSetting();
long earliestFuturePollTime = Long.MAX_VALUE;
- if (!backgroundDataUsageAllowed) {
- return earliestFuturePollTime;
- }
-
- AccountAndUser[] accounts = mRunningAccounts;
final long nowAbsolute = System.currentTimeMillis();
final long shiftedNowAbsolute = (0 < nowAbsolute - mSyncRandomOffsetMillis)
@@ -2167,23 +2175,8 @@ public class SyncManager {
for (Pair<AuthorityInfo, SyncStatusInfo> info : infos) {
final AuthorityInfo authorityInfo = info.first;
final SyncStatusInfo status = info.second;
- // skip the sync if the account of this operation no longer
- // exists
- if (!containsAccountAndUser(
- accounts, authorityInfo.account, authorityInfo.userId)) {
- continue;
- }
-
- if (!mSyncStorageEngine.getMasterSyncAutomatically(authorityInfo.userId)
- || !mSyncStorageEngine.getSyncAutomatically(
- authorityInfo.account, authorityInfo.userId,
- authorityInfo.authority)) {
- continue;
- }
-
- if (getIsSyncable(
- authorityInfo.account, authorityInfo.userId, authorityInfo.authority)
- == 0) {
+
+ if (!isDispatchable(authorityInfo.base)) {
continue;
}
@@ -2211,7 +2204,7 @@ public class SyncManager {
boolean runEarly = remainingMillis <= flexInMillis
&& timeSinceLastRunMillis > periodInMillis - flexInMillis;
if (isLoggable) {
- Log.v(TAG, "sync: " + i + " for " + authorityInfo.authority + "."
+ Log.v(TAG, "sync: " + i + " for " + authorityInfo.base + "."
+ " period: " + (periodInMillis)
+ " flex: " + (flexInMillis)
+ " remaining: " + (remainingMillis)
@@ -2231,41 +2224,49 @@ public class SyncManager {
* future, sync now and reinitialize. This can happen for
* example if the user changed the time, synced and changed
* back.
- * Case 3: If we failed to sync at the last scheduled
- * time.
+ * Case 3: If we failed to sync at the last scheduled time.
* Case 4: This sync is close enough to the time that we can schedule it.
*/
- if (runEarly // Case 4
- || remainingMillis == periodInMillis // Case 1
+ if (remainingMillis == periodInMillis // Case 1
|| lastPollTimeAbsolute > nowAbsolute // Case 2
- || timeSinceLastRunMillis >= periodInMillis) { // Case 3
+ || timeSinceLastRunMillis >= periodInMillis // Case 3
+ || runEarly) { // Case 4
// Sync now
-
- final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
- authorityInfo.account, authorityInfo.userId,
- authorityInfo.authority);
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
- syncAdapterInfo = mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(
- authorityInfo.authority, authorityInfo.account.type),
- authorityInfo.userId);
- if (syncAdapterInfo == null) {
- continue;
- }
+ SyncStorageEngine.EndPoint target = authorityInfo.base;
+ final Pair<Long, Long> backoff =
+ mSyncStorageEngine.getBackoff(target);
mSyncStorageEngine.setPeriodicSyncTime(authorityInfo.ident,
authorityInfo.periodicSyncs.get(i), nowAbsolute);
- scheduleSyncOperation(
- new SyncOperation(authorityInfo.account, authorityInfo.userId,
- SyncOperation.REASON_PERIODIC,
- SyncStorageEngine.SOURCE_PERIODIC,
- authorityInfo.authority, extras,
- 0 /* runtime */, 0 /* flex */,
- backoff != null ? backoff.first : 0,
- mSyncStorageEngine.getDelayUntilTime(
- authorityInfo.account, authorityInfo.userId,
- authorityInfo.authority),
- syncAdapterInfo.type.allowParallelSyncs()));
-
+
+ if (target.target_provider) {
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType>
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(
+ target.provider, target.account.type),
+ target.userId);
+ if (syncAdapterInfo == null) {
+ continue;
+ }
+ scheduleSyncOperation(
+ new SyncOperation(target.account, target.userId,
+ SyncOperation.REASON_PERIODIC,
+ SyncStorageEngine.SOURCE_PERIODIC,
+ target.provider, extras,
+ 0 /* runtime */, 0 /* flex */,
+ backoff != null ? backoff.first : 0,
+ mSyncStorageEngine.getDelayUntilTime(target),
+ syncAdapterInfo.type.allowParallelSyncs()));
+ } else if (target.target_service) {
+ scheduleSyncOperation(
+ new SyncOperation(target.service, target.userId,
+ SyncOperation.REASON_PERIODIC,
+ SyncStorageEngine.SOURCE_PERIODIC,
+ extras,
+ 0 /* runtime */,
+ 0 /* flex */,
+ backoff != null ? backoff.first : 0,
+ mSyncStorageEngine.getDelayUntilTime(target)));
+ }
}
// Compute when this periodic sync should next run.
long nextPollTimeAbsolute;
@@ -2312,8 +2313,7 @@ public class SyncManager {
// If the accounts aren't known yet then we aren't ready to run. We will be kicked
// when the account lookup request does complete.
- AccountAndUser[] accounts = mRunningAccounts;
- if (accounts == INITIAL_ACCOUNTS_ARRAY) {
+ if (mRunningAccounts == INITIAL_ACCOUNTS_ARRAY) {
if (isLoggable) {
Log.v(TAG, "maybeStartNextSync: accounts not known, skipping");
}
@@ -2323,9 +2323,6 @@ public class SyncManager {
// Otherwise consume SyncOperations from the head of the SyncQueue until one is
// found that is runnable (not disabled, etc). If that one is ready to run then
// start it, otherwise just get out.
- final boolean backgroundDataUsageAllowed =
- getConnectivityManager().getBackgroundDataSetting();
-
final long now = SystemClock.elapsedRealtime();
// will be set to the next time that a sync should be considered for running
@@ -2347,40 +2344,23 @@ public class SyncManager {
while (operationIterator.hasNext()) {
final SyncOperation op = operationIterator.next();
- // Drop the sync if the account of this operation no longer exists.
- if (!containsAccountAndUser(accounts, op.account, op.userId)) {
- operationIterator.remove();
- mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+ // If the user is not running, skip the request.
+ if (!activityManager.isUserRunning(op.target.userId)) {
+ final UserInfo userInfo = mUserManager.getUserInfo(op.target.userId);
+ if (userInfo == null) {
+ removedUsers.add(op.target.userId);
+ }
if (isLoggable) {
- Log.v(TAG, " Dropping sync operation: account doesn't exist.");
+ Log.v(TAG, " Dropping all sync operations for + "
+ + op.target.userId + ": user not running.");
}
continue;
}
-
- // Drop this sync request if it isn't syncable.
- int syncableState = getIsSyncable(
- op.account, op.userId, op.authority);
- if (syncableState == 0) {
+ if (!isOperationValidLocked(op)) {
operationIterator.remove();
mSyncStorageEngine.deleteFromPending(op.pendingOperation);
- if (isLoggable) {
- Log.v(TAG, " Dropping sync operation: isSyncable == 0.");
- }
continue;
}
-
- // If the user is not running, drop the request.
- if (!activityManager.isUserRunning(op.userId)) {
- final UserInfo userInfo = mUserManager.getUserInfo(op.userId);
- if (userInfo == null) {
- removedUsers.add(op.userId);
- }
- if (isLoggable) {
- Log.v(TAG, " Dropping sync operation: user not running.");
- }
- continue;
- }
-
// If the next run time is in the future, even given the flexible scheduling,
// return the time.
if (op.effectiveRunTime - op.flexTime > now) {
@@ -2388,42 +2368,16 @@ public class SyncManager {
nextReadyToRunTime = op.effectiveRunTime;
}
if (isLoggable) {
- Log.v(TAG, " Dropping sync operation: Sync too far in future.");
+ Log.v(TAG, " Not running sync operation: Sync too far in future."
+ + "effective: " + op.effectiveRunTime + " flex: " + op.flexTime
+ + " now: " + now);
}
continue;
}
- // TODO: change this behaviour for non-registered syncs.
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
- syncAdapterInfo = mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
-
- // only proceed if network is connected for requesting UID
- final boolean uidNetworkConnected;
- if (syncAdapterInfo != null) {
- final NetworkInfo networkInfo = getConnectivityManager()
- .getActiveNetworkInfoForUid(syncAdapterInfo.uid);
- uidNetworkConnected = networkInfo != null && networkInfo.isConnected();
- } else {
- uidNetworkConnected = false;
- }
-
- // skip the sync if it isn't manual, and auto sync or
- // background data usage is disabled or network is
- // disconnected for the target UID.
- if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
- && (syncableState > 0)
- && (!mSyncStorageEngine.getMasterSyncAutomatically(op.userId)
- || !backgroundDataUsageAllowed
- || !uidNetworkConnected
- || !mSyncStorageEngine.getSyncAutomatically(
- op.account, op.userId, op.authority))) {
- operationIterator.remove();
- mSyncStorageEngine.deleteFromPending(op.pendingOperation);
- continue;
- }
-
+ // Add this sync to be run.
operations.add(op);
}
+
for (Integer user : removedUsers) {
// if it's still removed
if (mUserManager.getUserInfo(user) == null) {
@@ -2465,13 +2419,9 @@ public class SyncManager {
}
}
}
- if (activeOp.account.type.equals(candidate.account.type)
- && activeOp.authority.equals(candidate.authority)
- && activeOp.userId == candidate.userId
- && (!activeOp.allowParallelSyncs
- || activeOp.account.name.equals(candidate.account.name))) {
+ if (activeOp.isConflict(candidate)) {
conflict = activeSyncContext;
- // don't break out since we want to do a full count of the varieties
+ // don't break out since we want to do a full count of the varieties.
} else {
if (candidateIsInitialization == activeOp.isInitialization()
&& activeSyncContext.mStartTime + MAX_TIME_PER_SYNC < now) {
@@ -2521,8 +2471,8 @@ public class SyncManager {
// is null. Reschedule the active sync and start the candidate.
toReschedule = oldestNonExpeditedRegular;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "canceling and rescheduling sync since an expedited is ready to run, "
- + oldestNonExpeditedRegular);
+ Log.v(TAG, "canceling and rescheduling sync since an expedited is ready to"
+ + " run, " + oldestNonExpeditedRegular);
}
} else if (longRunning != null
&& (candidateIsInitialization
@@ -2551,7 +2501,113 @@ public class SyncManager {
}
return nextReadyToRunTime;
- }
+ }
+
+ /**
+ * Determine if a sync is no longer valid and should be dropped from the sync queue and its
+ * pending op deleted.
+ * @param op operation for which the sync is to be scheduled.
+ */
+ private boolean isOperationValidLocked(SyncOperation op) {
+ final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+ int targetUid;
+ int state;
+ final SyncStorageEngine.EndPoint target = op.target;
+ boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId);
+ if (target.target_provider) {
+ // Drop the sync if the account of this operation no longer exists.
+ AccountAndUser[] accounts = mRunningAccounts;
+ if (!containsAccountAndUser(accounts, target.account, target.userId)) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: account doesn't exist.");
+ }
+ return false;
+ }
+ // Drop this sync request if it isn't syncable.
+ state = getIsSyncable(target.account, target.userId, target.provider);
+ if (state == 0) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: isSyncable == 0.");
+ }
+ return false;
+ }
+ syncEnabled = syncEnabled && mSyncStorageEngine.getSyncAutomatically(
+ target.account, target.userId, target.provider);
+
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(
+ target.provider, target.account.type), target.userId);
+ if (syncAdapterInfo != null) {
+ targetUid = syncAdapterInfo.uid;
+ } else {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: No sync adapter registered"
+ + "for: " + target);
+ }
+ return false;
+ }
+ } else if (target.target_service) {
+ state = getIsTargetServiceActive(target.service, target.userId);
+ if (state == 0) {
+ // TODO: Change this to not drop disabled syncs - keep them in the pending queue.
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: isActive == 0.");
+ }
+ return false;
+ }
+ try {
+ targetUid = mContext.getPackageManager()
+ .getServiceInfo(target.service, 0)
+ .applicationInfo
+ .uid;
+ } catch (PackageManager.NameNotFoundException e) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: No service registered for: "
+ + target.service);
+ }
+ return false;
+ }
+ } else {
+ Log.e(TAG, "Unknown target for Sync Op: " + target);
+ return false;
+ }
+
+ // We ignore system settings that specify the sync is invalid if:
+ // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
+ // or
+ // 2) it's an initialisation sync - we just need to connect to it.
+ final boolean ignoreSystemConfiguration =
+ op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
+ || (state < 0);
+
+ // Sync not enabled.
+ if (!syncEnabled && !ignoreSystemConfiguration) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: disallowed by settings/network.");
+ }
+ return false;
+ }
+ // Network down.
+ final NetworkInfo networkInfo = getConnectivityManager()
+ .getActiveNetworkInfoForUid(targetUid);
+ final boolean uidNetworkConnected = networkInfo != null && networkInfo.isConnected();
+ if (!uidNetworkConnected && !ignoreSystemConfiguration) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: disallowed by settings/network.");
+ }
+ return false;
+ }
+ // Metered network.
+ if (op.isNotAllowedOnMetered() && getConnectivityManager().isActiveNetworkMetered()
+ && !ignoreSystemConfiguration) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: not allowed on metered network.");
+ }
+ return false;
+ }
+ return true;
+ }
private boolean dispatchSyncOperation(SyncOperation op) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2561,27 +2617,48 @@ public class SyncManager {
Log.v(TAG, syncContext.toString());
}
}
-
- // connect to the sync adapter
- SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type);
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
- syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, op.userId);
- if (syncAdapterInfo == null) {
- Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
- + ", removing settings for it");
- mSyncStorageEngine.removeAuthority(op.account, op.userId, op.authority);
- return false;
+ // Connect to the sync adapter.
+ int targetUid;
+ ComponentName targetComponent;
+ final SyncStorageEngine.EndPoint info = op.target;
+ if (info.target_provider) {
+ SyncAdapterType syncAdapterType =
+ SyncAdapterType.newKey(info.provider, info.account.type);
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, info.userId);
+ if (syncAdapterInfo == null) {
+ Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
+ + ", removing settings for it");
+ mSyncStorageEngine.removeAuthority(info);
+ return false;
+ }
+ targetUid = syncAdapterInfo.uid;
+ targetComponent = syncAdapterInfo.componentName;
+ } else {
+ // TODO: Store the uid of the service as part of the authority info in order to
+ // avoid this call?
+ try {
+ targetUid = mContext.getPackageManager()
+ .getServiceInfo(info.service, 0)
+ .applicationInfo
+ .uid;
+ targetComponent = info.service;
+ } catch(PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "Can't find a service for " + info.service
+ + ", removing settings for it");
+ mSyncStorageEngine.removeAuthority(info);
+ return false;
+ }
}
-
ActiveSyncContext activeSyncContext =
- new ActiveSyncContext(op, insertStartSyncEvent(op), syncAdapterInfo.uid);
+ new ActiveSyncContext(op, insertStartSyncEvent(op), targetUid);
activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext);
mActiveSyncContexts.add(activeSyncContext);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext);
}
- if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo, op.userId)) {
- Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo);
+ if (!activeSyncContext.bindToSyncAdapter(targetComponent, info.userId)) {
+ Log.e(TAG, "Bind attempt failed - target: " + targetComponent);
closeActiveSyncContext(activeSyncContext);
return false;
}
@@ -2589,47 +2666,54 @@ public class SyncManager {
return true;
}
- private void runBoundToSyncAdapter(final ActiveSyncContext activeSyncContext,
- ISyncAdapter syncAdapter) {
- activeSyncContext.mSyncAdapter = syncAdapter;
+ private void runBoundToAdapter(final ActiveSyncContext activeSyncContext,
+ IBinder syncAdapter, int target) {
final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
try {
activeSyncContext.mIsLinkedToDeath = true;
- syncAdapter.asBinder().linkToDeath(activeSyncContext, 0);
-
- syncAdapter.startSync(activeSyncContext, syncOperation.authority,
- syncOperation.account, syncOperation.extras);
+ syncAdapter.linkToDeath(activeSyncContext, 0);
+
+ if (syncOperation.target.target_provider) {
+ activeSyncContext.mSyncAdapter = ISyncAdapter.Stub.asInterface(syncAdapter);
+ activeSyncContext.mSyncAdapter
+ .startSync(activeSyncContext, syncOperation.target.provider,
+ syncOperation.target.account, syncOperation.extras);
+ } else if (syncOperation.target.target_service) {
+ activeSyncContext.mSyncServiceAdapter =
+ ISyncServiceAdapter.Stub.asInterface(syncAdapter);
+ activeSyncContext.mSyncServiceAdapter
+ .startSync(activeSyncContext, syncOperation.extras);
+ }
} catch (RemoteException remoteExc) {
Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc);
closeActiveSyncContext(activeSyncContext);
increaseBackoffSetting(syncOperation);
- scheduleSyncOperation(new SyncOperation(syncOperation));
+ scheduleSyncOperation(
+ new SyncOperation(syncOperation, 0L /* newRunTimeFromNow */));
} catch (RuntimeException exc) {
closeActiveSyncContext(activeSyncContext);
Log.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
}
}
- private void cancelActiveSyncLocked(Account account, int userId, String authority) {
+ /**
+ * Cancel the sync for the provided authority that matches the given bundle. Info here
+ * can have null fields to indicate all the active syncs for that field.
+ */
+ private void cancelActiveSyncLocked(SyncStorageEngine.EndPoint info, Bundle extras) {
ArrayList<ActiveSyncContext> activeSyncs =
new ArrayList<ActiveSyncContext>(mActiveSyncContexts);
for (ActiveSyncContext activeSyncContext : activeSyncs) {
if (activeSyncContext != null) {
- // if an account was specified then only cancel the sync if it matches
- if (account != null) {
- if (!account.equals(activeSyncContext.mSyncOperation.account)) {
- continue;
- }
- }
- // if an authority was specified then only cancel the sync if it matches
- if (authority != null) {
- if (!authority.equals(activeSyncContext.mSyncOperation.authority)) {
- continue;
- }
+ final SyncStorageEngine.EndPoint opInfo =
+ activeSyncContext.mSyncOperation.target;
+ if (!opInfo.matches(info)) {
+ continue;
}
- // check if the userid matches
- if (userId != UserHandle.USER_ALL
- && userId != activeSyncContext.mSyncOperation.userId) {
+ if (extras != null &&
+ !syncExtrasEquals(activeSyncContext.mSyncOperation.extras,
+ extras,
+ false /* no config settings */)) {
continue;
}
runSyncFinishedOrCanceledLocked(null /* no result since this is a cancel */,
@@ -2642,16 +2726,19 @@ public class SyncManager {
ActiveSyncContext activeSyncContext) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+ final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
+ final SyncStorageEngine.EndPoint info = syncOperation.target;
+
if (activeSyncContext.mIsLinkedToDeath) {
- activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
+ if (info.target_provider) {
+ activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
+ } else {
+ activeSyncContext.mSyncServiceAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
+ }
activeSyncContext.mIsLinkedToDeath = false;
}
closeActiveSyncContext(activeSyncContext);
-
- final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
-
final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
-
String historyMessage;
int downstreamActivity;
int upstreamActivity;
@@ -2693,6 +2780,12 @@ public class SyncManager {
} catch (RemoteException e) {
// we don't need to retry this in this case
}
+ } else if (activeSyncContext.mSyncServiceAdapter != null) {
+ try {
+ activeSyncContext.mSyncServiceAdapter.cancelSync(activeSyncContext);
+ } catch (RemoteException e) {
+ // we don't need to retry this in this case
+ }
}
historyMessage = SyncStorageEngine.MESG_CANCELED;
downstreamActivity = 0;
@@ -2702,24 +2795,35 @@ public class SyncManager {
stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
upstreamActivity, downstreamActivity, elapsedTime);
- if (syncResult != null && syncResult.tooManyDeletions) {
- installHandleTooManyDeletesNotification(syncOperation.account,
- syncOperation.authority, syncResult.stats.numDeletes,
- syncOperation.userId);
+ // Check for full-resync and schedule it after closing off the last sync.
+ if (info.target_provider) {
+ if (syncResult != null && syncResult.tooManyDeletions) {
+ installHandleTooManyDeletesNotification(info.account,
+ info.provider, syncResult.stats.numDeletes,
+ info.userId);
+ } else {
+ mNotificationMgr.cancelAsUser(null,
+ info.account.hashCode() ^ info.provider.hashCode(),
+ new UserHandle(info.userId));
+ }
+ if (syncResult != null && syncResult.fullSyncRequested) {
+ scheduleSyncOperation(
+ new SyncOperation(info.account, info.userId,
+ syncOperation.reason,
+ syncOperation.syncSource, info.provider, new Bundle(),
+ 0 /* delay */, 0 /* flex */,
+ syncOperation.backoff, syncOperation.delayUntil,
+ syncOperation.allowParallelSyncs));
+ }
} else {
- mNotificationMgr.cancelAsUser(null,
- syncOperation.account.hashCode() ^ syncOperation.authority.hashCode(),
- new UserHandle(syncOperation.userId));
- }
-
- if (syncResult != null && syncResult.fullSyncRequested) {
- scheduleSyncOperation(
- new SyncOperation(syncOperation.account, syncOperation.userId,
- syncOperation.reason,
- syncOperation.syncSource, syncOperation.authority, new Bundle(),
- 0 /* delay */, 0 /* flex */,
- syncOperation.backoff, syncOperation.delayUntil,
- syncOperation.allowParallelSyncs));
+ if (syncResult != null && syncResult.fullSyncRequested) {
+ scheduleSyncOperation(
+ new SyncOperation(info.service, info.userId,
+ syncOperation.reason,
+ syncOperation.syncSource, new Bundle(),
+ 0 /* delay */, 0 /* flex */,
+ syncOperation.backoff, syncOperation.delayUntil));
+ }
}
// no need to schedule an alarm, as that will be done by our caller.
}
@@ -2728,7 +2832,7 @@ public class SyncManager {
activeSyncContext.close();
mActiveSyncContexts.remove(activeSyncContext);
mSyncStorageEngine.removeActiveSync(activeSyncContext.mSyncInfo,
- activeSyncContext.mSyncOperation.userId);
+ activeSyncContext.mSyncOperation.target.userId);
}
/**
@@ -2991,26 +3095,16 @@ public class SyncManager {
}
public long insertStartSyncEvent(SyncOperation syncOperation) {
- final int source = syncOperation.syncSource;
final long now = System.currentTimeMillis();
-
- EventLog.writeEvent(2720, syncOperation.authority,
- SyncStorageEngine.EVENT_START, source,
- syncOperation.account.name.hashCode());
-
- return mSyncStorageEngine.insertStartSyncEvent(
- syncOperation.account, syncOperation.userId, syncOperation.reason,
- syncOperation.authority,
- now, source, syncOperation.isInitialization(), syncOperation.extras
- );
+ EventLog.writeEvent(2720,
+ syncOperation.toEventLog(SyncStorageEngine.EVENT_START));
+ return mSyncStorageEngine.insertStartSyncEvent(syncOperation, now);
}
public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
int upstreamActivity, int downstreamActivity, long elapsedTime) {
- EventLog.writeEvent(2720, syncOperation.authority,
- SyncStorageEngine.EVENT_STOP, syncOperation.syncSource,
- syncOperation.account.name.hashCode());
-
+ EventLog.writeEvent(2720,
+ syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
resultMessage, downstreamActivity, upstreamActivity);
}
@@ -3025,6 +3119,79 @@ public class SyncManager {
return false;
}
+ /**
+ * Sync extra comparison function.
+ * @param b1 bundle to compare
+ * @param b2 other bundle to compare
+ * @param includeSyncSettings if false, ignore system settings in bundle.
+ */
+ public static boolean syncExtrasEquals(Bundle b1, Bundle b2, boolean includeSyncSettings) {
+ if (b1 == b2) {
+ return true;
+ }
+ if (includeSyncSettings && b1.size() != b2.size()) {
+ return false;
+ }
+ for (String key : b1.keySet()) {
+ if (!includeSyncSettings && isSyncSetting(key)) {
+ continue;
+ }
+ if (!b2.containsKey(key)) {
+ return false;
+ }
+ if (!b1.get(key).equals(b2.get(key))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return true if the provided key is used by the SyncManager in scheduling the sync.
+ */
+ private static boolean isSyncSetting(String key) {
+ if (key.equals(ContentResolver.SYNC_EXTRAS_EXPEDITED)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_MANUAL)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_UPLOAD)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_PRIORITY)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_INITIALIZE)) {
+ return true;
+ }
+ return false;
+ }
+
static class PrintTable {
private ArrayList<Object[]> mTable = Lists.newArrayList();
private final int mCols;
diff --git a/services/java/com/android/server/content/SyncOperation.java b/services/java/com/android/server/content/SyncOperation.java
index ce1dde4..eef20b2 100644
--- a/services/java/com/android/server/content/SyncOperation.java
+++ b/services/java/com/android/server/content/SyncOperation.java
@@ -20,10 +20,9 @@ import android.accounts.Account;
import android.content.pm.PackageManager;
import android.content.ComponentName;
import android.content.ContentResolver;
-import android.content.SyncRequest;
import android.os.Bundle;
import android.os.SystemClock;
-import android.util.Pair;
+import android.util.Log;
/**
* Value type that represents a sync operation.
@@ -32,10 +31,13 @@ import android.util.Pair;
* {@hide}
*/
public class SyncOperation implements Comparable {
+ public static final String TAG = "SyncManager";
+
public static final int REASON_BACKGROUND_DATA_SETTINGS_CHANGED = -1;
public static final int REASON_ACCOUNTS_UPDATED = -2;
public static final int REASON_SERVICE_CHANGED = -3;
public static final int REASON_PERIODIC = -4;
+ /** Sync started because it has just been set to isSyncable. */
public static final int REASON_IS_SYNCABLE = -5;
/** Sync started because it has just been set to sync automatically. */
public static final int REASON_SYNC_AUTO = -6;
@@ -54,19 +56,21 @@ public class SyncOperation implements Comparable {
"UserStart",
};
- /** Account info to identify a SyncAdapter registered with the system. */
- public final Account account;
- /** Authority info to identify a SyncAdapter registered with the system. */
- public final String authority;
- /** Service to which this operation will bind to perform the sync. */
- public final ComponentName service;
- public final int userId;
+ public static final int SYNC_TARGET_UNKNOWN = 0;
+ public static final int SYNC_TARGET_ADAPTER = 1;
+ public static final int SYNC_TARGET_SERVICE = 2;
+
+ /** Identifying info for the authority for this operation. */
+ public final SyncStorageEngine.EndPoint target;
+ /** Why this sync was kicked off. {@link #REASON_NAMES} */
public final int reason;
+ /** Where this sync was initiated. */
public int syncSource;
public final boolean allowParallelSyncs;
public Bundle extras;
public final String key;
public boolean expedited;
+ /** Bare-bones version of this operation that is persisted across reboots. */
public SyncStorageEngine.PendingOperation pendingOperation;
/** Elapsed real time in millis at which to run this sync. */
public long latestRunTime;
@@ -79,25 +83,56 @@ public class SyncOperation implements Comparable {
* Depends on max(backoff, latestRunTime, and delayUntil).
*/
public long effectiveRunTime;
- /** Amount of time before {@link effectiveRunTime} from which this sync can run. */
+ /** Amount of time before {@link #effectiveRunTime} from which this sync can run. */
public long flexTime;
- public SyncOperation(Account account, int userId, int reason, int source, String authority,
+ public SyncOperation(Account account, int userId, int reason, int source, String provider,
Bundle extras, long runTimeFromNow, long flexTime, long backoff,
long delayUntil, boolean allowParallelSyncs) {
- this.service = null;
- this.account = account;
- this.authority = authority;
- this.userId = userId;
+ this.target = new SyncStorageEngine.EndPoint(account, provider, userId);
this.reason = reason;
- this.syncSource = source;
this.allowParallelSyncs = allowParallelSyncs;
+ this.key = initialiseOperation(this.target, source, extras, runTimeFromNow, flexTime,
+ backoff, delayUntil);
+ }
+
+ public SyncOperation(ComponentName service, int userId, int reason, int source,
+ Bundle extras, long runTimeFromNow, long flexTime, long backoff,
+ long delayUntil) {
+ this.target = new SyncStorageEngine.EndPoint(service, userId);
+ // Default to true for sync service. The service itself decides how to handle this.
+ this.allowParallelSyncs = true;
+ this.reason = reason;
+ this.key =
+ initialiseOperation(this.target,
+ source, extras, runTimeFromNow, flexTime, backoff, delayUntil);
+ }
+
+ /** Used to reschedule a sync at a new point in time. */
+ SyncOperation(SyncOperation other, long newRunTimeFromNow) {
+ this.target = other.target;
+ this.reason = other.reason;
+ this.expedited = other.expedited;
+ this.allowParallelSyncs = other.allowParallelSyncs;
+ // re-use old flex, but only
+ long newFlexTime = Math.min(other.flexTime, newRunTimeFromNow);
+ this.key =
+ initialiseOperation(this.target,
+ other.syncSource, other.extras,
+ newRunTimeFromNow /* runTimeFromNow*/,
+ newFlexTime /* flexTime */,
+ other.backoff,
+ 0L /* delayUntil */);
+ }
+
+ private String initialiseOperation(SyncStorageEngine.EndPoint info, int source, Bundle extras,
+ long runTimeFromNow, long flexTime, long backoff, long delayUntil) {
+ this.syncSource = source;
this.extras = new Bundle(extras);
cleanBundle(this.extras);
this.delayUntil = delayUntil;
this.backoff = backoff;
final long now = SystemClock.elapsedRealtime();
- // Checks the extras bundle. Must occur after we set the internal bundle.
if (runTimeFromNow < 0 || isExpedited()) {
this.expedited = true;
this.latestRunTime = now;
@@ -108,41 +143,11 @@ public class SyncOperation implements Comparable {
this.flexTime = flexTime;
}
updateEffectiveRunTime();
- this.key = toKey();
+ return toKey(info, extras);
}
- public SyncOperation(SyncRequest request, int userId, int reason, int source, long backoff,
- long delayUntil, boolean allowParallelSyncs) {
- if (request.hasAuthority()) {
- Pair<Account, String> providerInfo = request.getProviderInfo();
- this.account = providerInfo.first;
- this.authority = providerInfo.second;
- this.service = null;
- } else {
- this.service = request.getService();
- this.account = null;
- this.authority = null;
- }
- this.userId = userId;
- this.reason = reason;
- this.syncSource = source;
- this.allowParallelSyncs = allowParallelSyncs;
- this.extras = new Bundle(extras);
- cleanBundle(this.extras);
- this.delayUntil = delayUntil;
- this.backoff = backoff;
- final long now = SystemClock.elapsedRealtime();
- if (request.isExpedited()) {
- this.expedited = true;
- this.latestRunTime = now;
- this.flexTime = 0;
- } else {
- this.expedited = false;
- this.latestRunTime = now + (request.getSyncRunTime() * 1000);
- this.flexTime = request.getSyncFlexTime() * 1000;
- }
- updateEffectiveRunTime();
- this.key = toKey();
+ public boolean matchesAuthority(SyncOperation other) {
+ return this.target.matches(other.target);
}
/**
@@ -159,11 +164,7 @@ public class SyncOperation implements Comparable {
removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS);
removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_EXPEDITED);
removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_ALLOW_METERED);
-
- // Remove Config data.
- bundle.remove(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD);
- bundle.remove(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD);
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISALLOW_METERED);
}
private void removeFalseExtra(Bundle bundle, String extraName) {
@@ -172,22 +173,24 @@ public class SyncOperation implements Comparable {
}
}
- /** Only used to immediately reschedule a sync. */
- SyncOperation(SyncOperation other) {
- this.service = other.service;
- this.account = other.account;
- this.authority = other.authority;
- this.userId = other.userId;
- this.reason = other.reason;
- this.syncSource = other.syncSource;
- this.extras = new Bundle(other.extras);
- this.expedited = other.expedited;
- this.latestRunTime = SystemClock.elapsedRealtime();
- this.flexTime = 0L;
- this.backoff = other.backoff;
- this.allowParallelSyncs = other.allowParallelSyncs;
- this.updateEffectiveRunTime();
- this.key = toKey();
+ /**
+ * Determine whether if this sync operation is running, the provided operation would conflict
+ * with it.
+ * Parallel syncs allow multiple accounts to be synced at the same time.
+ */
+ public boolean isConflict(SyncOperation toRun) {
+ final SyncStorageEngine.EndPoint other = toRun.target;
+ if (target.target_provider) {
+ return target.account.type.equals(other.account.type)
+ && target.provider.equals(other.provider)
+ && target.userId == other.userId
+ && (!allowParallelSyncs
+ || target.account.name.equals(other.account.name));
+ } else {
+ // Ops that target a service default to allow parallel syncs, which is handled by the
+ // service returning SYNC_IN_PROGRESS if they don't.
+ return target.service.equals(other.service) && !allowParallelSyncs;
+ }
}
@Override
@@ -196,18 +199,26 @@ public class SyncOperation implements Comparable {
}
public String dump(PackageManager pm, boolean useOneLine) {
- StringBuilder sb = new StringBuilder()
- .append(account.name)
+ StringBuilder sb = new StringBuilder();
+ if (target.target_provider) {
+ sb.append(target.account.name)
.append(" u")
- .append(userId).append(" (")
- .append(account.type)
+ .append(target.userId).append(" (")
+ .append(target.account.type)
.append(")")
.append(", ")
- .append(authority)
- .append(", ")
- .append(SyncStorageEngine.SOURCES[syncSource])
- .append(", latestRunTime ")
- .append(latestRunTime);
+ .append(target.provider)
+ .append(", ");
+ } else if (target.target_service) {
+ sb.append(target.service.getPackageName())
+ .append(" u")
+ .append(target.userId).append(" (")
+ .append(target.service.getClassName()).append(")")
+ .append(", ");
+ }
+ sb.append(SyncStorageEngine.SOURCES[syncSource])
+ .append(", currentRunTime ")
+ .append(effectiveRunTime);
if (expedited) {
sb.append(", EXPEDITED");
}
@@ -245,10 +256,6 @@ public class SyncOperation implements Comparable {
}
}
- public boolean isMetered() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_ALLOW_METERED, false);
- }
-
public boolean isInitialization() {
return extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
}
@@ -261,28 +268,39 @@ public class SyncOperation implements Comparable {
return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false);
}
+ public boolean isNotAllowedOnMetered() {
+ return extras.getBoolean(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED, false);
+ }
+
/** Changed in V3. */
- private String toKey() {
+ public static String toKey(SyncStorageEngine.EndPoint info, Bundle extras) {
StringBuilder sb = new StringBuilder();
- if (service == null) {
- sb.append("authority: ").append(authority);
- sb.append(" account {name=" + account.name + ", user=" + userId + ", type=" + account.type
+ if (info.target_provider) {
+ sb.append("provider: ").append(info.provider);
+ sb.append(" account {name=" + info.account.name
+ + ", user="
+ + info.userId
+ + ", type="
+ + info.account.type
+ "}");
- } else {
+ } else if (info.target_service) {
sb.append("service {package=" )
- .append(service.getPackageName())
+ .append(info.service.getPackageName())
.append(" user=")
- .append(userId)
+ .append(info.userId)
.append(", class=")
- .append(service.getClassName())
+ .append(info.service.getClassName())
.append("}");
+ } else {
+ Log.v(TAG, "Converting SyncOperaton to key, invalid target: " + info.toString());
+ return "";
}
sb.append(" extras: ");
extrasToStringBuilder(extras, sb);
return sb.toString();
}
- public static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
+ private static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
sb.append("[");
for (String key : bundle.keySet()) {
sb.append(key).append("=").append(bundle.get(key)).append(" ");
@@ -290,6 +308,31 @@ public class SyncOperation implements Comparable {
sb.append("]");
}
+ public String wakeLockKey() {
+ if (target.target_provider) {
+ return target.account.name + "/" + target.account.type + ":" + target.provider;
+ } else if (target.target_service) {
+ return target.service.getPackageName() + "/" + target.service.getClassName();
+ } else {
+ Log.wtf(TAG, "Invalid target getting wakelock for operation - " + key);
+ return null;
+ }
+ }
+
+ public String wakeLockName() {
+ if (target.target_provider) {
+ return "/" + target.provider
+ + "/" + target.account.type
+ + "/" + target.account.name;
+ } else if (target.target_service) {
+ return "/" + target.service.getPackageName()
+ + "/" + target.service.getClassName();
+ } else {
+ Log.wtf(TAG, "Invalid target getting wakelock name for operation - " + key);
+ return null;
+ }
+ }
+
/**
* Update the effective run time of this Operation based on latestRunTime (specified at
* creation time of sync), delayUntil (specified by SyncAdapter), or backoff (specified by
@@ -325,4 +368,21 @@ public class SyncOperation implements Comparable {
return 0;
}
}
+
+ // TODO: Test this to make sure that casting to object doesn't lose the type info for EventLog.
+ public Object[] toEventLog(int event) {
+ Object[] logArray = new Object[4];
+ logArray[1] = event;
+ logArray[2] = syncSource;
+ if (target.target_provider) {
+ logArray[0] = target.provider;
+ logArray[3] = target.account.name.hashCode();
+ } else if (target.target_service) {
+ logArray[0] = target.service.getPackageName();
+ logArray[3] = target.service.hashCode();
+ } else {
+ Log.wtf(TAG, "sync op with invalid target: " + key);
+ }
+ return logArray;
+ }
}
diff --git a/services/java/com/android/server/content/SyncQueue.java b/services/java/com/android/server/content/SyncQueue.java
index 6f3fe6e..da7efba 100644
--- a/services/java/com/android/server/content/SyncQueue.java
+++ b/services/java/com/android/server/content/SyncQueue.java
@@ -16,12 +16,11 @@
package com.android.server.content;
-import android.accounts.Account;
import android.content.pm.PackageManager;
-import android.content.pm.RegisteredServicesCache;
import android.content.SyncAdapterType;
import android.content.SyncAdaptersCache;
import android.content.pm.RegisteredServicesCache.ServiceInfo;
+import android.os.Bundle;
import android.os.SystemClock;
import android.text.format.DateUtils;
import android.util.Log;
@@ -60,25 +59,51 @@ public class SyncQueue {
public void addPendingOperations(int userId) {
for (SyncStorageEngine.PendingOperation op : mSyncStorageEngine.getPendingOperations()) {
- if (op.userId != userId) continue;
-
- final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
- op.account, op.userId, op.authority);
- final ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
- if (syncAdapterInfo == null) {
- Log.w(TAG, "Missing sync adapter info for authority " + op.authority + ", userId "
- + op.userId);
- continue;
+ final SyncStorageEngine.EndPoint info = op.authority;
+ if (info.userId != userId) continue;
+
+ final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(info);
+ SyncOperation operationToAdd;
+ if (info.target_provider) {
+ final ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(info.provider, info.account.type), info.userId);
+ if (syncAdapterInfo == null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.w(TAG, "Missing sync adapter info for authority " + op.authority);
+ }
+ continue;
+ }
+ operationToAdd = new SyncOperation(
+ info.account, info.userId, op.reason, op.syncSource, info.provider,
+ op.extras,
+ 0 /* delay */,
+ 0 /* flex */,
+ backoff != null ? backoff.first : 0,
+ mSyncStorageEngine.getDelayUntilTime(info),
+ syncAdapterInfo.type.allowParallelSyncs());
+ operationToAdd.expedited = op.expedited;
+ operationToAdd.pendingOperation = op;
+ add(operationToAdd, op);
+ } else if (info.target_service) {
+ try {
+ mPackageManager.getServiceInfo(info.service, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.w(TAG, "Missing sync servce for authority " + op.authority);
+ }
+ continue;
+ }
+ operationToAdd = new SyncOperation(
+ info.service, info.userId, op.reason, op.syncSource,
+ op.extras,
+ 0 /* delay */,
+ 0 /* flex */,
+ backoff != null ? backoff.first : 0,
+ mSyncStorageEngine.getDelayUntilTime(info));
+ operationToAdd.expedited = op.expedited;
+ operationToAdd.pendingOperation = op;
+ add(operationToAdd, op);
}
- SyncOperation syncOperation = new SyncOperation(
- op.account, op.userId, op.reason, op.syncSource, op.authority, op.extras,
- 0 /* delay */, 0 /* flex */, backoff != null ? backoff.first : 0,
- mSyncStorageEngine.getDelayUntilTime(op.account, op.userId, op.authority),
- syncAdapterInfo.type.allowParallelSyncs());
- syncOperation.expedited = op.expedited;
- syncOperation.pendingOperation = op;
- add(syncOperation, op);
}
}
@@ -119,12 +144,8 @@ public class SyncQueue {
operation.pendingOperation = pop;
// Don't update the PendingOp if one already exists. This really is just a placeholder,
// no actual scheduling info is placed here.
- // TODO: Change this to support service components.
if (operation.pendingOperation == null) {
- pop = new SyncStorageEngine.PendingOperation(
- operation.account, operation.userId, operation.reason, operation.syncSource,
- operation.authority, operation.extras, operation.expedited);
- pop = mSyncStorageEngine.insertIntoPending(pop);
+ pop = mSyncStorageEngine.insertIntoPending(operation);
if (pop == null) {
throw new IllegalStateException("error adding pending sync operation "
+ operation);
@@ -136,17 +157,16 @@ public class SyncQueue {
return true;
}
- public void removeUser(int userId) {
+ public void removeUserLocked(int userId) {
ArrayList<SyncOperation> opsToRemove = new ArrayList<SyncOperation>();
for (SyncOperation op : mOperationsMap.values()) {
- if (op.userId == userId) {
+ if (op.target.userId == userId) {
opsToRemove.add(op);
}
}
-
- for (SyncOperation op : opsToRemove) {
- remove(op);
- }
+ for (SyncOperation op : opsToRemove) {
+ remove(op);
+ }
}
/**
@@ -154,8 +174,15 @@ public class SyncQueue {
* @param operation the operation to remove
*/
public void remove(SyncOperation operation) {
+ boolean isLoggable = Log.isLoggable(TAG, Log.DEBUG);
SyncOperation operationToRemove = mOperationsMap.remove(operation.key);
+ if (isLoggable) {
+ Log.d(TAG, "Attempting to remove: " + operation.key);
+ }
if (operationToRemove == null) {
+ if (isLoggable) {
+ Log.d(TAG, "Could not find: " + operation.key);
+ }
return;
}
if (!mSyncStorageEngine.deleteFromPending(operationToRemove.pendingOperation)) {
@@ -164,41 +191,58 @@ public class SyncQueue {
}
}
- public void onBackoffChanged(Account account, int userId, String providerName, long backoff) {
- // for each op that matches the account and provider update its
+ /** Reset backoffs for all operations in the queue. */
+ public void clearBackoffs() {
+ for (SyncOperation op : mOperationsMap.values()) {
+ op.backoff = 0L;
+ op.updateEffectiveRunTime();
+ }
+ }
+
+ public void onBackoffChanged(SyncStorageEngine.EndPoint target, long backoff) {
+ // For each op that matches the authority of the changed op, update its
// backoff and effectiveStartTime
for (SyncOperation op : mOperationsMap.values()) {
- if (op.account.equals(account) && op.authority.equals(providerName)
- && op.userId == userId) {
+ if (op.target.matches(target)) {
op.backoff = backoff;
op.updateEffectiveRunTime();
}
}
}
- public void onDelayUntilTimeChanged(Account account, String providerName, long delayUntil) {
- // for each op that matches the account and provider update its
- // delayUntilTime and effectiveStartTime
+ public void onDelayUntilTimeChanged(SyncStorageEngine.EndPoint target, long delayUntil) {
+ // for each op that matches the authority info of the provided op, change the delay time.
for (SyncOperation op : mOperationsMap.values()) {
- if (op.account.equals(account) && op.authority.equals(providerName)) {
+ if (op.target.matches(target)) {
op.delayUntil = delayUntil;
op.updateEffectiveRunTime();
}
}
}
- public void remove(Account account, int userId, String authority) {
+ /**
+ * Remove all of the SyncOperations associated with a given target.
+ *
+ * @param info target object provided here can have null Account/provider. This is the case
+ * where you want to remove all ops associated with a provider (null Account) or all ops
+ * associated with an account (null provider).
+ * @param extras option bundle to include to further specify which operation to remove. If this
+ * bundle contains sync settings flags, they are ignored.
+ */
+ public void remove(final SyncStorageEngine.EndPoint info, Bundle extras) {
Iterator<Map.Entry<String, SyncOperation>> entries = mOperationsMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, SyncOperation> entry = entries.next();
SyncOperation syncOperation = entry.getValue();
- if (account != null && !syncOperation.account.equals(account)) {
- continue;
- }
- if (authority != null && !syncOperation.authority.equals(authority)) {
+ final SyncStorageEngine.EndPoint opInfo = syncOperation.target;
+ if (!opInfo.matches(info)) {
continue;
}
- if (userId != syncOperation.userId) {
+ if (extras != null
+ && !SyncManager.syncExtrasEquals(
+ syncOperation.extras,
+ extras,
+ false /* no config flags*/)) {
continue;
}
entries.remove();
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index 1b9ed98..6cc3d8a 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.ISyncStatusObserver;
import android.content.PeriodicSync;
import android.content.SyncInfo;
+import android.content.SyncRequest;
import android.content.SyncStatusInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
@@ -36,10 +37,12 @@ import android.os.Message;
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
+import android.util.ArrayMap;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
@@ -71,7 +74,6 @@ import java.util.TimeZone;
public class SyncStorageEngine extends Handler {
private static final String TAG = "SyncManager";
- private static final boolean DEBUG = false;
private static final String TAG_FILE = "SyncManagerFile";
private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId";
@@ -108,10 +110,7 @@ public class SyncStorageEngine extends Handler {
/** Enum value for a local-initiated sync. */
public static final int SOURCE_LOCAL = 1;
- /**
- * Enum value for a poll-based sync (e.g., upon connection to
- * network)
- */
+ /** Enum value for a poll-based sync (e.g., upon connection to network) */
public static final int SOURCE_POLL = 2;
/** Enum value for a user-initiated sync. */
@@ -119,6 +118,9 @@ public class SyncStorageEngine extends Handler {
/** Enum value for a periodic sync. */
public static final int SOURCE_PERIODIC = 4;
+
+ /** Enum value for a sync started for a service. */
+ public static final int SOURCE_SERVICE = 5;
public static final long NOT_IN_BACKOFF_MODE = -1;
@@ -128,7 +130,8 @@ public class SyncStorageEngine extends Handler {
"LOCAL",
"POLL",
"USER",
- "PERIODIC" };
+ "PERIODIC",
+ "SERVICE"};
// The MESG column will contain one of these or one of the Error types.
public static final String MESG_SUCCESS = "success";
@@ -156,41 +159,53 @@ public class SyncStorageEngine extends Handler {
}
public static class PendingOperation {
- final Account account;
- final int userId;
+ final EndPoint authority;
final int reason;
final int syncSource;
- final String authority;
final Bundle extras; // note: read-only.
- final ComponentName serviceName;
final boolean expedited;
- int authorityId;
+ final int authorityId;
+ // No longer used.
+ // Keep around for sake up updating from pending.bin to pending.xml
byte[] flatExtras;
- PendingOperation(Account account, int userId, int reason, int source,
- String authority, Bundle extras, boolean expedited) {
- this.account = account;
- this.userId = userId;
+ PendingOperation(AuthorityInfo authority, int reason, int source,
+ Bundle extras, boolean expedited) {
+ this.authority = authority.base;
this.syncSource = source;
this.reason = reason;
- this.authority = authority;
this.extras = extras != null ? new Bundle(extras) : extras;
this.expedited = expedited;
- this.authorityId = -1;
- this.serviceName = null;
+ this.authorityId = authority.ident;
}
PendingOperation(PendingOperation other) {
- this.account = other.account;
- this.userId = other.userId;
this.reason = other.reason;
this.syncSource = other.syncSource;
this.authority = other.authority;
this.extras = other.extras;
this.authorityId = other.authorityId;
this.expedited = other.expedited;
- this.serviceName = other.serviceName;
+ }
+
+ /**
+ * Considered equal if they target the same sync adapter (A {@link android.content.SyncService}
+ * is considered an adapter), for the same userId.
+ * @param other PendingOperation to compare.
+ * @return true if the two pending ops are the same.
+ */
+ public boolean equals(PendingOperation other) {
+ return authority.matches(other.authority);
+ }
+
+ public String toString() {
+ return "service=" + authority.service
+ + " user=" + authority.userId
+ + " auth=" + authority
+ + " account=" + authority.account
+ + " src=" + syncSource
+ + " extras=" + extras;
}
}
@@ -204,17 +219,93 @@ public class SyncStorageEngine extends Handler {
}
}
- public static class AuthorityInfo {
+ /** Bare bones representation of a sync target. */
+ public static class EndPoint {
+ public final static EndPoint USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL =
+ new EndPoint(null, null, UserHandle.USER_ALL);
final ComponentName service;
final Account account;
final int userId;
- final String authority;
+ final String provider;
+ final boolean target_service;
+ final boolean target_provider;
+
+ public EndPoint(ComponentName service, int userId) {
+ this.service = service;
+ this.userId = userId;
+ this.account = null;
+ this.provider = null;
+ this.target_service = true;
+ this.target_provider = false;
+ }
+
+ public EndPoint(Account account, String provider, int userId) {
+ this.account = account;
+ this.provider = provider;
+ this.userId = userId;
+ this.service = null;
+ this.target_service = false;
+ this.target_provider = true;
+ }
+
+ /**
+ * An Authority for a sync matches if it targets the same sync adapter for the same user.
+ * If the authority is for a provider/account pair and the account or provider is null, it
+ * matches by default.
+ */
+ public boolean matches(EndPoint other) {
+ if (userId != other.userId
+ && userId != UserHandle.USER_ALL
+ && other.userId != UserHandle.USER_ALL) {
+ return false;
+ }
+ if (target_service && other.target_service) {
+ return service.equals(other.service);
+ } else if (target_provider && other.target_provider) {
+ boolean accountsMatch;
+ if (account == null || other.account == null) {
+ accountsMatch = true;
+ } else {
+ accountsMatch = account.equals(other.account);
+ }
+ boolean providersMatch;
+ if (provider == null || other.provider == null) {
+ providersMatch = true;
+ } else {
+ providersMatch = provider.equals(other.provider);
+ }
+ return accountsMatch && providersMatch;
+ }
+ return false;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (target_provider) {
+ sb.append(account == null ? "ALL ACCS" : account.name)
+ .append("/")
+ .append(provider == null ? "ALL PDRS" : provider);
+ } else if (target_service) {
+ sb.append(service.getPackageName());
+ } else {
+ sb.append("invalid target");
+ }
+ return sb.toString();
+ }
+ }
+
+ public static class AuthorityInfo {
+ final EndPoint base;
final int ident;
boolean enabled;
int syncable;
+ /** Time at which this sync will run, taking into account backoff. */
long backoffTime;
+ /** Amount of delay due to backoff. */
long backoffDelay;
+ /** Offset to add to any requests coming to this authority. */
long delayUntil;
+
final ArrayList<PeriodicSync> periodicSyncs;
/**
@@ -224,10 +315,7 @@ public class SyncStorageEngine extends Handler {
* @param toCopy AuthorityInfo to be copied.
*/
AuthorityInfo(AuthorityInfo toCopy) {
- account = toCopy.account;
- userId = toCopy.userId;
- authority = toCopy.authority;
- service = toCopy.service;
+ base = toCopy.base;
ident = toCopy.ident;
enabled = toCopy.enabled;
syncable = toCopy.syncable;
@@ -241,56 +329,42 @@ public class SyncStorageEngine extends Handler {
}
}
- /**
- * Create an authority with one periodic sync scheduled with an empty bundle and syncing
- * every day. An empty bundle is considered equal to any other bundle see
- * {@link PeriodicSync.syncExtrasEquals}.
- * @param account Account that this authority syncs.
- * @param userId which user this sync is registered for.
- * @param userId user for which this authority is registered.
- * @param ident id of this authority.
- */
- AuthorityInfo(Account account, int userId, String authority, int ident) {
- this.account = account;
- this.userId = userId;
- this.authority = authority;
- this.service = null;
- this.ident = ident;
- enabled = SYNC_ENABLED_DEFAULT;
+ AuthorityInfo(EndPoint info, int id) {
+ base = info;
+ ident = id;
+ enabled = info.target_provider ?
+ SYNC_ENABLED_DEFAULT : true;
+ // Service is active by default,
+ if (info.target_service) {
+ this.syncable = 1;
+ }
+ periodicSyncs = new ArrayList<PeriodicSync>();
+ defaultInitialisation();
+ }
+
+ private void defaultInitialisation() {
syncable = -1; // default to "unknown"
backoffTime = -1; // if < 0 then we aren't in backoff mode
backoffDelay = -1; // if < 0 then we aren't in backoff mode
- periodicSyncs = new ArrayList<PeriodicSync>();
- // Old version adds one periodic sync a day.
- periodicSyncs.add(new PeriodicSync(account, authority,
- new Bundle(),
- DEFAULT_POLL_FREQUENCY_SECONDS,
- calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS)));
+ PeriodicSync defaultSync;
+ // Old version is one sync a day. Empty bundle gets replaced by any addPeriodicSync()
+ // call.
+ if (base.target_provider) {
+ defaultSync =
+ new PeriodicSync(base.account, base.provider,
+ new Bundle(),
+ DEFAULT_POLL_FREQUENCY_SECONDS,
+ calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS));
+ periodicSyncs.add(defaultSync);
+ }
+
}
/**
- * Create an authority with one periodic sync scheduled with an empty bundle and syncing
- * every day using a sync service.
- * @param cname sync service identifier.
- * @param userId user for which this authority is registered.
- * @param ident id of this authority.
+ * Two AuthorityInfos are considered equal if they have the same authority.
*/
- AuthorityInfo(ComponentName cname, int userId, int ident) {
- this.account = null;
- this.userId = userId;
- this.authority = null;
- this.service = cname;
- this.ident = ident;
- // Sync service is always enabled.
- enabled = true;
- syncable = -1; // default to "unknown"
- backoffTime = -1; // if < 0 then we aren't in backoff mode
- backoffDelay = -1; // if < 0 then we aren't in backoff mode
- periodicSyncs = new ArrayList<PeriodicSync>();
- periodicSyncs.add(new PeriodicSync(account, authority,
- new Bundle(),
- DEFAULT_POLL_FREQUENCY_SECONDS,
- calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS)));
+ public boolean equals(EndPoint other) {
+ return base.matches(other);
}
}
@@ -322,16 +396,9 @@ public class SyncStorageEngine extends Handler {
}
interface OnSyncRequestListener {
- /**
- * Called when a sync is needed on an account(s) due to some change in state.
- * @param account
- * @param userId
- * @param reason
- * @param authority
- * @param extras
- */
- public void onSyncRequest(Account account, int userId, int reason, String authority,
- Bundle extras);
+
+ /** Called when a sync is needed on an account(s) due to some change in state. */
+ public void onSyncRequest(EndPoint info, int reason, Bundle extras);
}
// Primary list of all syncable authorities. Also our global lock.
@@ -357,8 +424,8 @@ public class SyncStorageEngine extends Handler {
= new RemoteCallbackList<ISyncStatusObserver>();
/** Reverse mapping for component name -> <userid -> authority id>. */
- private final HashMap<ComponentName, SparseArray<AuthorityInfo>> mServices =
- new HashMap<ComponentName, SparseArray<AuthorityInfo>>();
+ private final ArrayMap<ComponentName, SparseArray<AuthorityInfo>> mServices =
+ new ArrayMap<ComponentName, SparseArray<AuthorityInfo>>();
private int mNextAuthorityId = 0;
@@ -501,7 +568,7 @@ public class SyncStorageEngine extends Handler {
* @return amount of seconds before syncTimeSeconds that the sync can occur.
* I.e.
* earliest_sync_time = syncTimeSeconds - calculateDefaultFlexTime(syncTimeSeconds)
- * The flex time is capped at a percentage of the {@link DEFAULT_POLL_FREQUENCY_SECONDS}.
+ * The flex time is capped at a percentage of the {@link #DEFAULT_POLL_FREQUENCY_SECONDS}.
*/
public static long calculateDefaultFlexTime(long syncTimeSeconds) {
if (syncTimeSeconds < DEFAULT_MIN_FLEX_ALLOWED_SECS) {
@@ -535,7 +602,7 @@ public class SyncStorageEngine extends Handler {
mChangeListeners.finishBroadcast();
}
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "reportChange " + which + " to: " + reports);
}
@@ -555,7 +622,8 @@ public class SyncStorageEngine extends Handler {
public boolean getSyncAutomatically(Account account, int userId, String providerName) {
synchronized (mAuthorities) {
if (account != null) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
+ AuthorityInfo authority = getAuthorityLocked(
+ new EndPoint(account, providerName, userId),
"getSyncAutomatically");
return authority != null && authority.enabled;
}
@@ -563,10 +631,9 @@ public class SyncStorageEngine extends Handler {
int i = mAuthorities.size();
while (i > 0) {
i--;
- AuthorityInfo authority = mAuthorities.valueAt(i);
- if (authority.authority.equals(providerName)
- && authority.userId == userId
- && authority.enabled) {
+ AuthorityInfo authorityInfo = mAuthorities.valueAt(i);
+ if (authorityInfo.base.matches(new EndPoint(account, providerName, userId))
+ && authorityInfo.enabled) {
return true;
}
}
@@ -576,15 +643,18 @@ public class SyncStorageEngine extends Handler {
public void setSyncAutomatically(Account account, int userId, String providerName,
boolean sync) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "setSyncAutomatically: " + /* account + */" provider " + providerName
+ ", user " + userId + " -> " + sync);
}
synchronized (mAuthorities) {
- AuthorityInfo authority = getOrCreateAuthorityLocked(account, userId, providerName, -1,
- false);
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(
+ new EndPoint(account, providerName, userId),
+ -1 /* ident */,
+ false);
if (authority.enabled == sync) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "setSyncAutomatically: already set to " + sync + ", doing nothing");
}
return;
@@ -603,8 +673,9 @@ public class SyncStorageEngine extends Handler {
public int getIsSyncable(Account account, int userId, String providerName) {
synchronized (mAuthorities) {
if (account != null) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
- "getIsSyncable");
+ AuthorityInfo authority = getAuthorityLocked(
+ new EndPoint(account, providerName, userId),
+ "get authority syncable");
if (authority == null) {
return -1;
}
@@ -614,9 +685,10 @@ public class SyncStorageEngine extends Handler {
int i = mAuthorities.size();
while (i > 0) {
i--;
- AuthorityInfo authority = mAuthorities.valueAt(i);
- if (authority.authority.equals(providerName)) {
- return authority.syncable;
+ AuthorityInfo authorityInfo = mAuthorities.valueAt(i);
+ if (authorityInfo.base != null
+ && authorityInfo.base.provider.equals(providerName)) {
+ return authorityInfo.syncable;
}
}
return -1;
@@ -624,103 +696,163 @@ public class SyncStorageEngine extends Handler {
}
public void setIsSyncable(Account account, int userId, String providerName, int syncable) {
+ synchronized (mAuthorities) {
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(
+ new EndPoint(account, providerName, userId),
+ -1 /* ident */,
+ false);
+ setSyncableLocked(authority, syncable);
+ }
+ }
+
+ public int getIsTargetServiceActive(ComponentName cname, int userId) {
+ synchronized (mAuthorities) {
+ if (cname != null) {
+ AuthorityInfo authority = getAuthorityLocked(
+ new EndPoint(cname, userId),
+ "get service enabled");
+ if (authority == null) {
+ return -1;
+ }
+ return authority.syncable;
+ }
+ return -1;
+ }
+ }
+
+ public void setIsEnabled(ComponentName cname, int userId, int syncable) {
+ synchronized (mAuthorities) {
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(
+ new EndPoint(cname, userId), -1, false);
+ setSyncableLocked(authority, syncable);
+ }
+ }
+
+ /**
+ * An enabled sync service and a syncable provider's adapter both get resolved to the same
+ * persisted variable - namely the "syncable" attribute for an AuthorityInfo in accounts.xml.
+ * @param aInfo
+ * @param syncable
+ */
+ private void setSyncableLocked(AuthorityInfo aInfo, int syncable) {
if (syncable > 1) {
syncable = 1;
} else if (syncable < -1) {
syncable = -1;
}
- if (DEBUG) {
- Log.d(TAG, "setIsSyncable: " + account + ", provider " + providerName
- + ", user " + userId + " -> " + syncable);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "setIsSyncable: " + aInfo.toString() + " -> " + syncable);
}
- synchronized (mAuthorities) {
- AuthorityInfo authority =
- getOrCreateAuthorityLocked(account, userId, providerName, -1, false);
- if (authority.syncable == syncable) {
- if (DEBUG) {
- Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
- }
- return;
+
+ if (aInfo.syncable == syncable) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
}
- authority.syncable = syncable;
- writeAccountInfoLocked();
+ return;
}
+ aInfo.syncable = syncable;
+ writeAccountInfoLocked();
if (syncable > 0) {
- requestSync(account, userId, SyncOperation.REASON_IS_SYNCABLE, providerName,
- new Bundle());
+ requestSync(aInfo, SyncOperation.REASON_IS_SYNCABLE, new Bundle());
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- public Pair<Long, Long> getBackoff(Account account, int userId, String providerName) {
+ public Pair<Long, Long> getBackoff(EndPoint info) {
synchronized (mAuthorities) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
- "getBackoff");
- if (authority == null || authority.backoffTime < 0) {
- return null;
+ AuthorityInfo authority = getAuthorityLocked(info, "getBackoff");
+ if (authority != null) {
+ return Pair.create(authority.backoffTime, authority.backoffDelay);
}
- return Pair.create(authority.backoffTime, authority.backoffDelay);
+ return null;
}
}
- public void setBackoff(Account account, int userId, String providerName,
- long nextSyncTime, long nextDelay) {
- if (DEBUG) {
- Log.v(TAG, "setBackoff: " + account + ", provider " + providerName
- + ", user " + userId
+ /**
+ * Update the backoff for the given endpoint. The endpoint may be for a provider/account and
+ * the account or provider info be null, which signifies all accounts or providers.
+ */
+ public void setBackoff(EndPoint info, long nextSyncTime, long nextDelay) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "setBackoff: " + info
+ " -> nextSyncTime " + nextSyncTime + ", nextDelay " + nextDelay);
}
- boolean changed = false;
+ boolean changed;
synchronized (mAuthorities) {
- if (account == null || providerName == null) {
- for (AccountInfo accountInfo : mAccounts.values()) {
- if (account != null && !account.equals(accountInfo.accountAndUser.account)
- && userId != accountInfo.accountAndUser.userId) {
- continue;
- }
- for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
- if (providerName != null
- && !providerName.equals(authorityInfo.authority)) {
- continue;
- }
- if (authorityInfo.backoffTime != nextSyncTime
- || authorityInfo.backoffDelay != nextDelay) {
- authorityInfo.backoffTime = nextSyncTime;
- authorityInfo.backoffDelay = nextDelay;
- changed = true;
- }
- }
- }
+ if (info.target_provider
+ && (info.account == null || info.provider == null)) {
+ // Do more work for a provider sync if the provided info has specified all
+ // accounts/providers.
+ changed = setBackoffLocked(
+ info.account /* may be null */,
+ info.userId,
+ info.provider /* may be null */,
+ nextSyncTime, nextDelay);
} else {
- AuthorityInfo authority =
- getOrCreateAuthorityLocked(account, userId, providerName, -1 /* ident */,
- true);
- if (authority.backoffTime == nextSyncTime && authority.backoffDelay == nextDelay) {
- return;
+ AuthorityInfo authorityInfo =
+ getOrCreateAuthorityLocked(info, -1 /* ident */, true);
+ if (authorityInfo.backoffTime == nextSyncTime
+ && authorityInfo.backoffDelay == nextDelay) {
+ changed = false;
+ } else {
+ authorityInfo.backoffTime = nextSyncTime;
+ authorityInfo.backoffDelay = nextDelay;
+ changed = true;
}
- authority.backoffTime = nextSyncTime;
- authority.backoffDelay = nextDelay;
- changed = true;
}
}
-
if (changed) {
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
}
+ /**
+ * Either set backoff for a specific authority, or set backoff for all the
+ * accounts on a specific adapter/all adapters.
+ *
+ * @param account account for which to set backoff. Null to specify all accounts.
+ * @param userId id of the user making this request.
+ * @param providerName provider for which to set backoff. Null to specify all providers.
+ */
+ private boolean setBackoffLocked(Account account, int userId, String providerName,
+ long nextSyncTime, long nextDelay) {
+ boolean changed = false;
+ for (AccountInfo accountInfo : mAccounts.values()) {
+ if (account != null && !account.equals(accountInfo.accountAndUser.account)
+ && userId != accountInfo.accountAndUser.userId) {
+ continue;
+ }
+ for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
+ if (providerName != null
+ && !providerName.equals(authorityInfo.base.provider)) {
+ continue;
+ }
+ if (authorityInfo.backoffTime != nextSyncTime
+ || authorityInfo.backoffDelay != nextDelay) {
+ authorityInfo.backoffTime = nextSyncTime;
+ authorityInfo.backoffDelay = nextDelay;
+ changed = true;
+ }
+ }
+ }
+ return changed;
+ }
+
public void clearAllBackoffs(SyncQueue syncQueue) {
boolean changed = false;
synchronized (mAuthorities) {
synchronized (syncQueue) {
+ // Clear backoff for all sync adapters.
for (AccountInfo accountInfo : mAccounts.values()) {
for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
|| authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "clearAllBackoffs:"
- + " authority:" + authorityInfo.authority
+ + " authority:" + authorityInfo.base
+ " account:" + accountInfo.accountAndUser.account.name
+ " user:" + accountInfo.accountAndUser.userId
+ " backoffTime was: " + authorityInfo.backoffTime
@@ -728,12 +860,23 @@ public class SyncStorageEngine extends Handler {
}
authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
- syncQueue.onBackoffChanged(accountInfo.accountAndUser.account,
- accountInfo.accountAndUser.userId, authorityInfo.authority, 0);
changed = true;
}
}
}
+ // Clear backoff for all sync services.
+ for (ComponentName service : mServices.keySet()) {
+ SparseArray<AuthorityInfo> aInfos = mServices.get(service);
+ for (int i = 0; i < aInfos.size(); i++) {
+ AuthorityInfo authorityInfo = aInfos.valueAt(i);
+ if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
+ || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
+ authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
+ authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
+ }
+ }
+ }
+ syncQueue.clearBackoffs();
}
}
@@ -742,142 +885,158 @@ public class SyncStorageEngine extends Handler {
}
}
- public void setDelayUntilTime(Account account, int userId, String providerName,
- long delayUntil) {
- if (DEBUG) {
- Log.v(TAG, "setDelayUntil: " + account + ", provider " + providerName
- + ", user " + userId + " -> delayUntil " + delayUntil);
- }
+ public long getDelayUntilTime(EndPoint info) {
synchronized (mAuthorities) {
- AuthorityInfo authority = getOrCreateAuthorityLocked(
- account, userId, providerName, -1 /* ident */, true);
- if (authority.delayUntil == delayUntil) {
- return;
+ AuthorityInfo authority = getAuthorityLocked(info, "getDelayUntil");
+ if (authority == null) {
+ return 0;
}
- authority.delayUntil = delayUntil;
+ return authority.delayUntil;
}
-
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- public long getDelayUntilTime(Account account, int userId, String providerName) {
+ public void setDelayUntilTime(EndPoint info, long delayUntil) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "setDelayUntil: " + info
+ + " -> delayUntil " + delayUntil);
+ }
synchronized (mAuthorities) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
- "getDelayUntil");
- if (authority == null) {
- return 0;
+ AuthorityInfo authority = getOrCreateAuthorityLocked(info, -1, true);
+ if (authority.delayUntil == delayUntil) {
+ return;
}
- return authority.delayUntil;
+ authority.delayUntil = delayUntil;
}
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- private void updateOrRemovePeriodicSync(PeriodicSync toUpdate, int userId, boolean add) {
- if (DEBUG) {
- Log.v(TAG, "addOrRemovePeriodicSync: " + toUpdate.account + ", user " + userId
- + ", provider " + toUpdate.authority
- + " -> period " + toUpdate.period + ", extras " + toUpdate.extras);
+ public void updateOrAddPeriodicSync(EndPoint info, long period, long flextime, Bundle extras) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "addPeriodicSync: " + info
+ + " -> period " + period + ", flex " + flextime + ", extras "
+ + extras.toString());
}
synchronized (mAuthorities) {
- if (toUpdate.period <= 0 && add) {
- Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-"
- + add);
+ if (period <= 0) {
+ Log.e(TAG, "period < 0, should never happen in updateOrAddPeriodicSync");
}
- if (toUpdate.extras == null) {
- Log.e(TAG, "null extras, should never happen in updateOrRemovePeriodicSync: add-"
- + add);
+ if (extras == null) {
+ Log.e(TAG, "null extras, should never happen in updateOrAddPeriodicSync:");
}
try {
+ PeriodicSync toUpdate;
+ if (info.target_provider) {
+ toUpdate = new PeriodicSync(info.account,
+ info.provider,
+ extras,
+ period,
+ flextime);
+ } else {
+ toUpdate = new PeriodicSync(info.service,
+ extras,
+ period,
+ flextime);
+ }
AuthorityInfo authority =
- getOrCreateAuthorityLocked(toUpdate.account, userId, toUpdate.authority,
- -1, false);
- if (add) {
- // add this periodic sync if an equivalent periodic doesn't already exist.
- boolean alreadyPresent = false;
- for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
- PeriodicSync syncInfo = authority.periodicSyncs.get(i);
- if (PeriodicSync.syncExtrasEquals(
- toUpdate.extras,
- syncInfo.extras)) {
- if (toUpdate.period == syncInfo.period &&
- toUpdate.flexTime == syncInfo.flexTime) {
- // Absolutely the same.
- return;
- }
- authority.periodicSyncs.set(i, new PeriodicSync(toUpdate));
- alreadyPresent = true;
- break;
+ getOrCreateAuthorityLocked(info, -1, false);
+ // add this periodic sync if an equivalent periodic doesn't already exist.
+ boolean alreadyPresent = false;
+ for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
+ PeriodicSync syncInfo = authority.periodicSyncs.get(i);
+ if (SyncManager.syncExtrasEquals(syncInfo.extras,
+ extras,
+ true /* includeSyncSettings*/)) {
+ if (period == syncInfo.period &&
+ flextime == syncInfo.flexTime) {
+ // Absolutely the same.
+ Log.e(TAG, "update psync: exactly the same.");
+ return;
}
+ authority.periodicSyncs.set(i, toUpdate);
+ 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(new PeriodicSync(toUpdate));
- SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
- status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0L);
- }
- } else {
- // Remove any periodic syncs that match the authority and extras.
- SyncStatusInfo status = mSyncStatus.get(authority.ident);
- boolean changed = false;
- Iterator<PeriodicSync> iterator = authority.periodicSyncs.iterator();
- int i = 0;
- while (iterator.hasNext()) {
- PeriodicSync syncInfo = iterator.next();
- if (PeriodicSync.syncExtrasEquals(syncInfo.extras, toUpdate.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 {
- Log.e(TAG, "Tried removing sync status on remove periodic sync but"
- + "did not find it.");
- }
+ }
+ // 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(toUpdate);
+ SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
+ // A new periodic sync is initialised as already having been run.
+ status.setPeriodicSyncTime(
+ authority.periodicSyncs.size() - 1,
+ System.currentTimeMillis());
+ }
+ } finally {
+ writeAccountInfoLocked();
+ writeStatusLocked();
+ }
+ }
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
+ }
+
+ public void removePeriodicSync(EndPoint info, Bundle extras) {
+ synchronized(mAuthorities) {
+ try {
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(info, -1, false);
+ // Remove any periodic syncs that match the authority and extras.
+ SyncStatusInfo status = mSyncStatus.get(authority.ident);
+ boolean changed = false;
+ Iterator<PeriodicSync> iterator = authority.periodicSyncs.iterator();
+ int i = 0;
+ while (iterator.hasNext()) {
+ PeriodicSync syncInfo = iterator.next();
+ if (SyncManager.syncExtrasEquals(syncInfo.extras,
+ extras,
+ true /* includeSyncSettings */)) {
+ 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++;
+ Log.e(TAG, "Tried removing sync status on remove periodic sync but"
+ + " did not find it.");
}
+ } else {
+ i++;
}
- if (!changed) {
- return;
- }
+ }
+ if (!changed) {
+ return;
}
} finally {
writeAccountInfoLocked();
writeStatusLocked();
}
}
-
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- public void addPeriodicSync(PeriodicSync toAdd, int userId) {
- updateOrRemovePeriodicSync(toAdd, userId, true /* add */);
- }
-
- public void removePeriodicSync(PeriodicSync toRemove, int userId) {
- updateOrRemovePeriodicSync(toRemove, userId, false /* remove */);
- }
-
- public List<PeriodicSync> getPeriodicSyncs(Account account, int userId, String providerName) {
- ArrayList<PeriodicSync> syncs = new ArrayList<PeriodicSync>();
+ /**
+ * @return list of periodic syncs for an authority. Never returns null - if no such syncs
+ * exist, returns an empty list.
+ */
+ public List<PeriodicSync> getPeriodicSyncs(EndPoint info) {
synchronized (mAuthorities) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
- "getPeriodicSyncs");
- if (authority != null) {
- for (PeriodicSync item : authority.periodicSyncs) {
+ AuthorityInfo authorityInfo = getAuthorityLocked(info, "getPeriodicSyncs");
+ ArrayList<PeriodicSync> syncs = new ArrayList<PeriodicSync>();
+ if (authorityInfo != null) {
+ for (PeriodicSync item : authorityInfo.periodicSyncs) {
// Copy and send out. Necessary for thread-safety although it's parceled.
syncs.add(new PeriodicSync(item));
}
}
+ return syncs;
}
- return syncs;
}
public void setMasterSyncAutomatically(boolean flag, int userId) {
synchronized (mAuthorities) {
Boolean auto = mMasterSyncAutomatically.get(userId);
- if (auto != null && (boolean) auto == flag) {
+ if (auto != null && auto == flag) {
return;
}
mMasterSyncAutomatically.put(userId, flag);
@@ -898,12 +1057,6 @@ public class SyncStorageEngine extends Handler {
}
}
- public void removeAuthority(Account account, int userId, String authority) {
- synchronized (mAuthorities) {
- removeAuthorityLocked(account, userId, authority, true /* doWrite */);
- }
- }
-
public AuthorityInfo getAuthority(int authorityId) {
synchronized (mAuthorities) {
return mAuthorities.get(authorityId);
@@ -911,53 +1064,47 @@ public class SyncStorageEngine extends Handler {
}
/**
- * Returns true if there is currently a sync operation for the given
- * account or authority actively being processed.
+ * Returns true if there is currently a sync operation being actively processed for the given
+ * authority.
*/
- public boolean isSyncActive(Account account, int userId, String authority) {
+ public boolean isSyncActive(EndPoint info) {
synchronized (mAuthorities) {
- for (SyncInfo syncInfo : getCurrentSyncs(userId)) {
+ for (SyncInfo syncInfo : getCurrentSyncs(info.userId)) {
AuthorityInfo ainfo = getAuthority(syncInfo.authorityId);
- if (ainfo != null && ainfo.account.equals(account)
- && ainfo.authority.equals(authority)
- && ainfo.userId == userId) {
+ if (ainfo != null && ainfo.base.matches(info)) {
return true;
}
}
}
-
return false;
}
- public PendingOperation insertIntoPending(PendingOperation op) {
+ public PendingOperation insertIntoPending(SyncOperation op) {
+ PendingOperation pop;
synchronized (mAuthorities) {
- if (DEBUG) {
- Log.v(TAG, "insertIntoPending: account=" + op.account
- + " user=" + op.userId
- + " auth=" + op.authority
- + " src=" + op.syncSource
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "insertIntoPending: authority=" + op.target
+ " extras=" + op.extras);
}
-
- AuthorityInfo authority = getOrCreateAuthorityLocked(op.account, op.userId,
- op.authority,
- -1 /* desired identifier */,
- true /* write accounts to storage */);
+ final EndPoint info = op.target;
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(info,
+ -1 /* desired identifier */,
+ true /* write accounts to storage */);
if (authority == null) {
return null;
}
- op = new PendingOperation(op);
- op.authorityId = authority.ident;
- mPendingOperations.add(op);
- appendPendingOperationLocked(op);
+ pop = new PendingOperation(authority, op.reason, op.syncSource, op.extras,
+ op.expedited);
+ mPendingOperations.add(pop);
+ writePendingOperationsLocked();
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = true;
}
-
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
- return op;
+ return pop;
}
/**
@@ -965,18 +1112,13 @@ public class SyncStorageEngine extends Handler {
* authorities. If there are no more pending syncs for the same authority/account/userid,
* update the SyncStatusInfo for that authority(authority here is the internal representation
* of a 'sync operation'.
- * @param op
- * @return
+ * @param op Pending op to delete.
*/
public boolean deleteFromPending(PendingOperation op) {
boolean res = false;
synchronized (mAuthorities) {
- if (DEBUG) {
- Log.v(TAG, "deleteFromPending: account=" + op.account
- + " user=" + op.userId
- + " auth=" + op.authority
- + " src=" + op.syncSource
- + " extras=" + op.extras);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "deleteFromPending: account=" + op.toString());
}
if (mPendingOperations.remove(op)) {
if (mPendingOperations.size() == 0
@@ -986,30 +1128,27 @@ public class SyncStorageEngine extends Handler {
} else {
mNumPendingFinished++;
}
-
- AuthorityInfo authority = getAuthorityLocked(op.account, op.userId, op.authority,
- "deleteFromPending");
+ AuthorityInfo authority = getAuthorityLocked(op.authority, "deleteFromPending");
if (authority != null) {
- if (DEBUG) Log.v(TAG, "removing - " + authority.toString());
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "removing - " + authority.toString());
+ }
final int N = mPendingOperations.size();
boolean morePending = false;
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
PendingOperation cur = mPendingOperations.get(i);
- if (cur.account.equals(op.account)
- && cur.authority.equals(op.authority)
- && cur.userId == op.userId) {
+ if (cur.equals(op)) {
morePending = true;
break;
}
}
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;
}
}
-
res = true;
}
}
@@ -1044,7 +1183,7 @@ public class SyncStorageEngine extends Handler {
*/
public void doDatabaseCleanup(Account[] accounts, int userId) {
synchronized (mAuthorities) {
- if (DEBUG) Log.v(TAG, "Updating for new accounts...");
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Updating for new accounts...");
SparseArray<AuthorityInfo> removing = new SparseArray<AuthorityInfo>();
Iterator<AccountInfo> accIt = mAccounts.values().iterator();
while (accIt.hasNext()) {
@@ -1052,7 +1191,7 @@ public class SyncStorageEngine extends Handler {
if (!ArrayUtils.contains(accounts, acc.accountAndUser.account)
&& acc.accountAndUser.userId == userId) {
// This account no longer exists...
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Account removed: " + acc.accountAndUser);
}
for (AuthorityInfo auth : acc.authorities.values()) {
@@ -1099,25 +1238,25 @@ public class SyncStorageEngine extends Handler {
public SyncInfo addActiveSync(SyncManager.ActiveSyncContext activeSyncContext) {
final SyncInfo syncInfo;
synchronized (mAuthorities) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setActiveSync: account="
- + activeSyncContext.mSyncOperation.account
- + " auth=" + activeSyncContext.mSyncOperation.authority
+ + " auth=" + activeSyncContext.mSyncOperation.target
+ " src=" + activeSyncContext.mSyncOperation.syncSource
+ " extras=" + activeSyncContext.mSyncOperation.extras);
}
- AuthorityInfo authority = getOrCreateAuthorityLocked(
- activeSyncContext.mSyncOperation.account,
- activeSyncContext.mSyncOperation.userId,
- activeSyncContext.mSyncOperation.authority,
+ final EndPoint info = activeSyncContext.mSyncOperation.target;
+ AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(
+ info,
-1 /* assign a new identifier if creating a new authority */,
true /* write to storage if this results in a change */);
- syncInfo = new SyncInfo(authority.ident,
- authority.account, authority.authority,
+ syncInfo = new SyncInfo(
+ authorityInfo.ident,
+ authorityInfo.base.account,
+ authorityInfo.base.provider,
+ authorityInfo.base.service,
activeSyncContext.mStartTime);
- getCurrentSyncs(authority.userId).add(syncInfo);
+ getCurrentSyncs(authorityInfo.base.userId).add(syncInfo);
}
-
reportActiveChange();
return syncInfo;
}
@@ -1127,10 +1266,11 @@ public class SyncStorageEngine extends Handler {
*/
public void removeActiveSync(SyncInfo syncInfo, int userId) {
synchronized (mAuthorities) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "removeActiveSync: account=" + syncInfo.account
+ " user=" + userId
- + " auth=" + syncInfo.authority);
+ + " auth=" + syncInfo.authority
+ + " service=" + syncInfo.service);
}
getCurrentSyncs(userId).remove(syncInfo);
}
@@ -1147,36 +1287,37 @@ public class SyncStorageEngine extends Handler {
/**
* Note that sync has started for the given account and authority.
+ *
+ syncOperation.account, syncOperation.userId, syncOperation.reason,
+ syncOperation.authority,
+ now, source, syncOperation.isInitialization(), syncOperation.extras
*/
- public long insertStartSyncEvent(Account accountName, int userId, int reason,
- String authorityName, long now, int source, boolean initialization, Bundle extras) {
+ public long insertStartSyncEvent(SyncOperation op, long now) {
long id;
synchronized (mAuthorities) {
- if (DEBUG) {
- Log.v(TAG, "insertStartSyncEvent: account=" + accountName + "user=" + userId
- + " auth=" + authorityName + " source=" + source);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "insertStartSyncEvent: " + op);
}
- AuthorityInfo authority = getAuthorityLocked(accountName, userId, authorityName,
- "insertStartSyncEvent");
+ AuthorityInfo authority = getAuthorityLocked(op.target, "insertStartSyncEvent");
if (authority == null) {
return -1;
}
SyncHistoryItem item = new SyncHistoryItem();
- item.initialization = initialization;
+ item.initialization = op.isInitialization();
item.authorityId = authority.ident;
item.historyId = mNextHistoryId++;
if (mNextHistoryId < 0) mNextHistoryId = 0;
item.eventTime = now;
- item.source = source;
- item.reason = reason;
- item.extras = extras;
+ item.source = op.syncSource;
+ item.reason = op.reason;
+ item.extras = op.extras;
item.event = EVENT_START;
mSyncHistory.add(0, item);
while (mSyncHistory.size() > MAX_HISTORY) {
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);
@@ -1186,7 +1327,7 @@ public class SyncStorageEngine extends Handler {
public void stopSyncEvent(long historyId, long elapsedTime, String resultMessage,
long downstreamActivity, long upstreamActivity) {
synchronized (mAuthorities) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "stopSyncEvent: historyId=" + historyId);
}
SyncHistoryItem item = null;
@@ -1325,10 +1466,9 @@ public class SyncStorageEngine extends Handler {
/**
* Return a copy of the specified authority with the corresponding sync status
*/
- public Pair<AuthorityInfo, SyncStatusInfo> getCopyOfAuthorityWithSyncStatus(
- Account account, int userId, String authority) {
+ public Pair<AuthorityInfo, SyncStatusInfo> getCopyOfAuthorityWithSyncStatus(EndPoint info) {
synchronized (mAuthorities) {
- AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(account, userId, authority,
+ AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(info,
-1 /* assign a new identifier if creating a new authority */,
true /* write to storage if this results in a change */);
return createCopyPairOfAuthorityWithSyncStatusLocked(authorityInfo);
@@ -1352,24 +1492,22 @@ public class SyncStorageEngine extends Handler {
/**
* Returns the status that matches the authority and account.
*
- * @param account the account we want to check
- * @param authority the authority whose row should be selected
- * @return the SyncStatusInfo for the authority
+ * @param info the target we want to check
+ * @return the SyncStatusInfo for the target
*/
- public SyncStatusInfo getStatusByAccountAndAuthority(Account account, int userId,
- String authority) {
- if (account == null || authority == null) {
+ public SyncStatusInfo getStatusByAuthority(EndPoint info) {
+ if (info.target_provider && (info.account == null || info.provider == null)) {
throw new IllegalArgumentException();
+ } else if (info.target_service && info.service == null) {
+ throw new IllegalArgumentException();
}
synchronized (mAuthorities) {
final int N = mSyncStatus.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
SyncStatusInfo cur = mSyncStatus.valueAt(i);
AuthorityInfo ainfo = mAuthorities.get(cur.authorityId);
-
- if (ainfo != null && ainfo.authority.equals(authority)
- && ainfo.userId == userId
- && account.equals(ainfo.account)) {
+ if (ainfo != null
+ && ainfo.base.matches(info)) {
return cur;
}
}
@@ -1377,25 +1515,20 @@ public class SyncStorageEngine extends Handler {
}
}
- /**
- * Return true if the pending status is true of any matching authorities.
- */
- public boolean isSyncPending(Account account, int userId, String authority) {
+ /** Return true if the pending status is true of any matching authorities. */
+ public boolean isSyncPending(EndPoint info) {
synchronized (mAuthorities) {
final int N = mSyncStatus.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
SyncStatusInfo cur = mSyncStatus.valueAt(i);
AuthorityInfo ainfo = mAuthorities.get(cur.authorityId);
if (ainfo == null) {
continue;
}
- if (userId != ainfo.userId) {
+ if (!ainfo.base.matches(info)) {
continue;
}
- if (account != null && !ainfo.account.equals(account)) {
- continue;
- }
- if (ainfo.authority.equals(authority) && cur.pending) {
+ if (cur.pending) {
return true;
}
}
@@ -1453,126 +1586,131 @@ public class SyncStorageEngine extends Handler {
/**
* Retrieve an authority, returning null if one does not exist.
*
- * @param accountName The name of the account for the authority.
- * @param authorityName The name of the authority itself.
+ * @param info container for the info of the authority to look up.
* @param tag If non-null, this will be used in a log message if the
* requested authority does not exist.
*/
- private AuthorityInfo getAuthorityLocked(Account accountName, int userId, String authorityName,
- String tag) {
- AccountAndUser au = new AccountAndUser(accountName, userId);
- AccountInfo accountInfo = mAccounts.get(au);
- if (accountInfo == null) {
- if (tag != null) {
- if (DEBUG) {
- Log.v(TAG, tag + ": unknown account " + au);
+ private AuthorityInfo getAuthorityLocked(EndPoint info, String tag) {
+ if (info.target_service) {
+ SparseArray<AuthorityInfo> aInfo = mServices.get(info.service);
+ AuthorityInfo authority = null;
+ if (aInfo != null) {
+ authority = aInfo.get(info.userId);
+ }
+ if (authority == null) {
+ if (tag != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + " No authority info found for " + info.service + " for user "
+ + info.userId);
+ }
}
+ return null;
}
- return null;
- }
- AuthorityInfo authority = accountInfo.authorities.get(authorityName);
- if (authority == null) {
- if (tag != null) {
- if (DEBUG) {
- Log.v(TAG, tag + ": unknown authority " + authorityName);
+ return authority;
+ } else if (info.target_provider){
+ AccountAndUser au = new AccountAndUser(info.account, info.userId);
+ AccountInfo accountInfo = mAccounts.get(au);
+ if (accountInfo == null) {
+ if (tag != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + ": unknown account " + au);
+ }
}
+ return null;
}
- return null;
- }
-
- return authority;
- }
-
- /**
- * Retrieve an authority, returning null if one does not exist.
- *
- * @param service The service name used for this sync.
- * @param userId The user for whom this sync is scheduled.
- * @param tag If non-null, this will be used in a log message if the
- * requested authority does not exist.
- */
- private AuthorityInfo getAuthorityLocked(ComponentName service, int userId, String tag) {
- AuthorityInfo authority = mServices.get(service).get(userId);
- if (authority == null) {
- if (tag != null) {
- if (DEBUG) {
- Log.v(TAG, tag + " No authority info found for " + service + " for user "
- + userId);
+ AuthorityInfo authority = accountInfo.authorities.get(info.provider);
+ if (authority == null) {
+ if (tag != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + ": unknown provider " + info.provider);
+ }
}
+ return null;
}
+ return authority;
+ } else {
+ Log.e(TAG, tag + " Authority : " + info + ", invalid target");
return null;
}
- return authority;
}
/**
- * @param cname identifier for the service.
- * @param userId for the syncs corresponding to this authority.
+ * @param info info identifying authority.
* @param ident unique identifier for authority. -1 for none.
* @param doWrite if true, update the accounts.xml file on the disk.
- * @return the authority that corresponds to the provided sync service, creating it if none
+ * @return the authority that corresponds to the provided sync authority, creating it if none
* exists.
*/
- private AuthorityInfo getOrCreateAuthorityLocked(ComponentName cname, int userId, int ident,
- boolean doWrite) {
- SparseArray<AuthorityInfo> aInfo = mServices.get(cname);
- if (aInfo == null) {
- aInfo = new SparseArray<AuthorityInfo>();
- mServices.put(cname, aInfo);
- }
- AuthorityInfo authority = aInfo.get(userId);
- if (authority == null) {
- if (ident < 0) {
- ident = mNextAuthorityId;
- mNextAuthorityId++;
- doWrite = true;
- }
- if (DEBUG) {
- Log.v(TAG, "created a new AuthorityInfo for " + cname.getPackageName()
- + ", " + cname.getClassName()
- + ", user: " + userId);
- }
- authority = new AuthorityInfo(cname, userId, ident);
- aInfo.put(userId, authority);
- mAuthorities.put(ident, authority);
- if (doWrite) {
- writeAccountInfoLocked();
+ private AuthorityInfo getOrCreateAuthorityLocked(EndPoint info, int ident, boolean doWrite) {
+ AuthorityInfo authority = null;
+ if (info.target_service) {
+ SparseArray<AuthorityInfo> aInfo = mServices.get(info.service);
+ if (aInfo == null) {
+ aInfo = new SparseArray<AuthorityInfo>();
+ mServices.put(info.service, aInfo);
+ }
+ authority = aInfo.get(info.userId);
+ if (authority == null) {
+ authority = createAuthorityLocked(info, ident, doWrite);
+ aInfo.put(info.userId, authority);
+ }
+ } else if (info.target_provider) {
+ AccountAndUser au = new AccountAndUser(info.account, info.userId);
+ AccountInfo account = mAccounts.get(au);
+ if (account == null) {
+ account = new AccountInfo(au);
+ mAccounts.put(au, account);
+ }
+ authority = account.authorities.get(info.provider);
+ if (authority == null) {
+ authority = createAuthorityLocked(info, ident, doWrite);
+ account.authorities.put(info.provider, authority);
}
}
return authority;
}
- private AuthorityInfo getOrCreateAuthorityLocked(Account accountName, int userId,
- String authorityName, int ident, boolean doWrite) {
- AccountAndUser au = new AccountAndUser(accountName, userId);
- AccountInfo account = mAccounts.get(au);
- if (account == null) {
- account = new AccountInfo(au);
- mAccounts.put(au, account);
- }
- AuthorityInfo authority = account.authorities.get(authorityName);
- if (authority == null) {
- if (ident < 0) {
- ident = mNextAuthorityId;
- mNextAuthorityId++;
- doWrite = true;
- }
- if (DEBUG) {
- Log.v(TAG, "created a new AuthorityInfo for " + accountName
- + ", user " + userId
- + ", provider " + authorityName);
- }
- authority = new AuthorityInfo(accountName, userId, authorityName, ident);
- account.authorities.put(authorityName, authority);
- mAuthorities.put(ident, authority);
- if (doWrite) {
- writeAccountInfoLocked();
- }
+ private AuthorityInfo createAuthorityLocked(EndPoint info, int ident, boolean doWrite) {
+ AuthorityInfo authority;
+ if (ident < 0) {
+ ident = mNextAuthorityId;
+ mNextAuthorityId++;
+ doWrite = true;
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "created a new AuthorityInfo for " + info);
+ }
+ authority = new AuthorityInfo(info, ident);
+ mAuthorities.put(ident, authority);
+ if (doWrite) {
+ writeAccountInfoLocked();
}
-
return authority;
}
+ public void removeAuthority(EndPoint info) {
+ synchronized (mAuthorities) {
+ if (info.target_provider) {
+ removeAuthorityLocked(info.account, info.userId, info.provider, true /* doWrite */);
+ } else {
+ SparseArray<AuthorityInfo> aInfos = mServices.get(info.service);
+ if (aInfos != null) {
+ AuthorityInfo authorityInfo = aInfos.get(info.userId);
+ if (authorityInfo != null) {
+ mAuthorities.remove(authorityInfo.ident);
+ aInfos.delete(info.userId);
+ writeAccountInfoLocked();
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Remove an authority associated with a provider. Needs to be a standalone function for
+ * backward compatibility.
+ */
private void removeAuthorityLocked(Account account, int userId, String authorityName,
boolean doWrite) {
AccountInfo accountInfo = mAccounts.get(new AccountAndUser(account, userId));
@@ -1591,8 +1729,7 @@ public class SyncStorageEngine extends Handler {
* Updates (in a synchronized way) the periodic sync time of the specified
* authority id and target periodic sync
*/
- public void setPeriodicSyncTime(
- int authorityId, PeriodicSync targetPeriodicSync, long when) {
+ public void setPeriodicSyncTime(int authorityId, PeriodicSync targetPeriodicSync, long when) {
boolean found = false;
final AuthorityInfo authorityInfo;
synchronized (mAuthorities) {
@@ -1608,7 +1745,7 @@ public class SyncStorageEngine extends Handler {
}
if (!found) {
Log.w(TAG, "Ignoring setPeriodicSyncTime request for a sync that does not exist. " +
- "Authority: " + authorityInfo.authority);
+ "Authority: " + authorityInfo.base);
}
}
@@ -1777,10 +1914,10 @@ public class SyncStorageEngine extends Handler {
ArrayList<AuthorityInfo> authoritiesToRemove = new ArrayList<AuthorityInfo>();
final int N = mAuthorities.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
AuthorityInfo authority = mAuthorities.valueAt(i);
// skip this authority if it isn't one of the renamed ones
- final String newAuthorityName = sAuthorityRenames.get(authority.authority);
+ final String newAuthorityName = sAuthorityRenames.get(authority.base);
if (newAuthorityName == null) {
continue;
}
@@ -1796,20 +1933,26 @@ public class SyncStorageEngine extends Handler {
}
// if we already have a record of this new authority then don't copy over the settings
- if (getAuthorityLocked(authority.account, authority.userId, newAuthorityName, "cleanup")
- != null) {
+ EndPoint newInfo =
+ new EndPoint(authority.base.account,
+ newAuthorityName,
+ authority.base.userId);
+ if (getAuthorityLocked(newInfo, "cleanup") != null) {
continue;
}
- AuthorityInfo newAuthority = getOrCreateAuthorityLocked(authority.account,
- authority.userId, newAuthorityName, -1 /* ident */, false /* doWrite */);
+ AuthorityInfo newAuthority =
+ getOrCreateAuthorityLocked(newInfo, -1 /* ident */, false /* doWrite */);
newAuthority.enabled = true;
writeNeeded = true;
}
for (AuthorityInfo authorityInfo : authoritiesToRemove) {
- removeAuthorityLocked(authorityInfo.account, authorityInfo.userId,
- authorityInfo.authority, false /* doWrite */);
+ removeAuthorityLocked(
+ authorityInfo.base.account,
+ authorityInfo.base.userId,
+ authorityInfo.base.provider,
+ false /* doWrite */);
writeNeeded = true;
}
@@ -1865,15 +2008,18 @@ public class SyncStorageEngine extends Handler {
}
if (authority == null) {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Creating entry");
+ Log.v(TAG_FILE, "Creating authority entry");
}
if (accountName != null && accountType != null) {
- authority = getOrCreateAuthorityLocked(
- new Account(accountName, accountType), userId, authorityName, id,
- false);
+ EndPoint info =
+ new EndPoint(
+ new Account(accountName, accountType),
+ authorityName, userId);
+ authority = getOrCreateAuthorityLocked(info, id, false);
} else {
- authority = getOrCreateAuthorityLocked(
- new ComponentName(packageName, className), userId, id, false);
+ EndPoint info =
+ new EndPoint(new ComponentName(packageName, className), userId);
+ authority = getOrCreateAuthorityLocked(info, id, false);
}
// If the version is 0 then we are upgrading from a file format that did not
// know about periodic syncs. In that case don't clear the list since we
@@ -1905,7 +2051,7 @@ public class SyncStorageEngine extends Handler {
/**
* Parse a periodic sync from accounts.xml. Sets the bundle to be empty.
*/
- private PeriodicSync parsePeriodicSync(XmlPullParser parser, AuthorityInfo authority) {
+ private PeriodicSync parsePeriodicSync(XmlPullParser parser, AuthorityInfo authorityInfo) {
Bundle extras = new Bundle(); // Gets filled in later.
String periodValue = parser.getAttributeValue(null, "period");
String flexValue = parser.getAttributeValue(null, "flex");
@@ -1930,10 +2076,22 @@ public class SyncStorageEngine extends Handler {
Log.d(TAG, "No flex time specified for this sync, using a default. period: "
+ period + " flex: " + flextime);
}
- final PeriodicSync periodicSync =
- new PeriodicSync(authority.account, authority.authority, extras,
+ PeriodicSync periodicSync;
+ if (authorityInfo.base.target_provider) {
+ periodicSync =
+ new PeriodicSync(authorityInfo.base.account,
+ authorityInfo.base.provider,
+ extras,
period, flextime);
- authority.periodicSyncs.add(periodicSync);
+ } else {
+ periodicSync =
+ new PeriodicSync(
+ authorityInfo.base.service,
+ extras,
+ period,
+ flextime);
+ }
+ authorityInfo.periodicSyncs.add(periodicSync);
return periodicSync;
}
@@ -2001,17 +2159,18 @@ public class SyncStorageEngine extends Handler {
final int N = mAuthorities.size();
for (int i = 0; i < N; i++) {
AuthorityInfo authority = mAuthorities.valueAt(i);
+ EndPoint info = authority.base;
out.startTag(null, "authority");
out.attribute(null, "id", Integer.toString(authority.ident));
- out.attribute(null, XML_ATTR_USER, Integer.toString(authority.userId));
+ out.attribute(null, XML_ATTR_USER, Integer.toString(info.userId));
out.attribute(null, XML_ATTR_ENABLED, Boolean.toString(authority.enabled));
- if (authority.service == null) {
- out.attribute(null, "account", authority.account.name);
- out.attribute(null, "type", authority.account.type);
- out.attribute(null, "authority", authority.authority);
+ if (info.service == null) {
+ out.attribute(null, "account", info.account.name);
+ out.attribute(null, "type", info.account.type);
+ out.attribute(null, "authority", info.provider);
} else {
- out.attribute(null, "package", authority.service.getPackageName());
- out.attribute(null, "class", authority.service.getClassName());
+ out.attribute(null, "package", info.service.getPackageName());
+ out.attribute(null, "class", info.service.getClassName());
}
if (authority.syncable < 0) {
out.attribute(null, "syncable", "unknown");
@@ -2105,9 +2264,13 @@ public class SyncStorageEngine extends Handler {
accountType = "com.google";
}
String authorityName = c.getString(c.getColumnIndex("authority"));
- AuthorityInfo authority = this.getOrCreateAuthorityLocked(
- new Account(accountName, accountType), 0 /* legacy is single-user */,
- authorityName, -1, false);
+ AuthorityInfo authority =
+ this.getOrCreateAuthorityLocked(
+ new EndPoint(new Account(accountName, accountType),
+ authorityName,
+ 0 /* legacy is single-user */)
+ , -1,
+ false);
if (authority != null) {
int i = mSyncStatus.size();
boolean found = false;
@@ -2159,7 +2322,7 @@ public class SyncStorageEngine extends Handler {
while (i > 0) {
i--;
AuthorityInfo authority = mAuthorities.valueAt(i);
- if (authority.authority.equals(provider)) {
+ if (authority.base.equals(provider)) {
authority.enabled = value == null || Boolean.parseBoolean(value);
authority.syncable = 1;
}
@@ -2275,62 +2438,52 @@ public class SyncStorageEngine extends Handler {
String tagName = parser.getName();
do {
PendingOperation pop = null;
- if (eventType == XmlPullParser.START_TAG) {
- try {
- tagName = parser.getName();
- if (parser.getDepth() == 1 && "op".equals(tagName)) {
- // Verify version.
- String versionString =
- parser.getAttributeValue(null, XML_ATTR_VERSION);
- if (versionString == null ||
- Integer.parseInt(versionString) != PENDING_OPERATION_VERSION) {
- Log.w(TAG, "Unknown pending operation version " + versionString);
- throw new java.io.IOException("Unknown version.");
- }
- int authorityId = Integer.valueOf(parser.getAttributeValue(
- null, XML_ATTR_AUTHORITYID));
- boolean expedited = Boolean.valueOf(parser.getAttributeValue(
- null, XML_ATTR_EXPEDITED));
- int syncSource = Integer.valueOf(parser.getAttributeValue(
- null, XML_ATTR_SOURCE));
- int reason = Integer.valueOf(parser.getAttributeValue(
- null, XML_ATTR_REASON));
- AuthorityInfo authority = mAuthorities.get(authorityId);
- if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG_FILE, authorityId + " " + expedited + " " + syncSource + " "
- + reason);
- }
- if (authority != null) {
- pop = new PendingOperation(
- authority.account, authority.userId, reason,
- syncSource, authority.authority, new Bundle(),
- expedited);
- pop.flatExtras = null; // No longer used.
- mPendingOperations.add(pop);
+ if (eventType == XmlPullParser.START_TAG) {
+ try {
+ tagName = parser.getName();
+ if (parser.getDepth() == 2 && "op".equals(tagName)) {
+ int authorityId = Integer.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_AUTHORITYID));
+ boolean expedited = Boolean.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_EXPEDITED));
+ int syncSource = Integer.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_SOURCE));
+ int reason = Integer.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_REASON));
+ AuthorityInfo authority = mAuthorities.get(authorityId);
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG_FILE, "Adding pending op: "
+ Log.v(TAG_FILE, authorityId + " " + expedited + " " +
+ syncSource + " " + reason);
+ }
+ if (authority != null) {
+ pop = new PendingOperation(
+ authority, reason, syncSource, new Bundle(), expedited);
+ pop.flatExtras = null; // No longer used.
+ mPendingOperations.add(pop);
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, "Adding pending op: "
+ pop.authority
+ " src=" + pop.syncSource
+ " reason=" + pop.reason
+ " expedited=" + pop.expedited);
+ }
+ } else {
+ // Skip non-existent authority.
+ pop = null;
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, "No authority found for " + authorityId
+ + ", skipping");
+ }
}
- } else {
- // Skip non-existent authority.
- pop = null;
- if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG_FILE, "No authority found for " + authorityId
- + ", skipping");
- }
+ } else if (parser.getDepth() == 2 &&
+ pop != null &&
+ "extra".equals(tagName)) {
+ parseExtra(parser, pop.extras);
}
- } else if (parser.getDepth() == 2 &&
- pop != null &&
- "extra".equals(tagName)) {
- parseExtra(parser, pop.extras);
+ } catch (NumberFormatException e) {
+ Log.d(TAG, "Invalid data in xml file.", e);
}
- } catch (NumberFormatException e) {
- Log.d(TAG, "Invalid data in xml file.", e);
}
- }
eventType = parser.next();
} while(eventType != XmlPullParser.END_DOCUMENT);
} catch (java.io.IOException e) {
@@ -2348,39 +2501,80 @@ public class SyncStorageEngine extends Handler {
}
}
+ static private byte[] flattenBundle(Bundle bundle) {
+ byte[] flatData = null;
+ Parcel parcel = Parcel.obtain();
+ try {
+ bundle.writeToParcel(parcel, 0);
+ flatData = parcel.marshall();
+ } finally {
+ parcel.recycle();
+ }
+ return flatData;
+ }
+
+ static private Bundle unflattenBundle(byte[] flatData) {
+ Bundle bundle;
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.unmarshall(flatData, 0, flatData.length);
+ parcel.setDataPosition(0);
+ bundle = parcel.readBundle();
+ } catch (RuntimeException e) {
+ // A RuntimeException is thrown if we were unable to parse the parcel.
+ // Create an empty parcel in this case.
+ bundle = new Bundle();
+ } finally {
+ parcel.recycle();
+ }
+ return bundle;
+ }
+
private static final String XML_ATTR_AUTHORITYID = "authority_id";
private static final String XML_ATTR_SOURCE = "source";
private static final String XML_ATTR_EXPEDITED = "expedited";
private static final String XML_ATTR_REASON = "reason";
- private static final String XML_ATTR_VERSION = "version";
/**
* Write all currently pending ops to the pending ops file.
+ * TODO: Change this from xml so that we can append to this file as before.
*/
private void writePendingOperationsLocked() {
final int N = mPendingOperations.size();
FileOutputStream fos = null;
try {
if (N == 0) {
- if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG_FILE, "Truncating " + mPendingFile.getBaseFile());
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)){
+ Log.v(TAG, "Truncating " + mPendingFile.getBaseFile());
}
mPendingFile.truncate();
return;
}
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG_FILE, "Writing new " + mPendingFile.getBaseFile());
+ Log.v(TAG, "Writing new " + mPendingFile.getBaseFile());
}
fos = mPendingFile.startWrite();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(fos, "utf-8");
+ out.startDocument(null, true);
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ out.startTag(null, "pending");
+ out.attribute(null, "version", Integer.toString(PENDING_OPERATION_VERSION));
for (int i = 0; i < N; i++) {
PendingOperation pop = mPendingOperations.get(i);
- writePendingOperationLocked(pop, out);
- }
- out.endDocument();
- mPendingFile.finishWrite(fos);
+ out.startTag(null, "op");
+ out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId));
+ out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource));
+ out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited));
+ out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason));
+ extrasToXml(out, pop.extras);
+ out.endTag(null, "op");
+ }
+ out.endTag(null, "pending");
+ out.endDocument();
+ mPendingFile.finishWrite(fos);
} catch (java.io.IOException e1) {
Log.w(TAG, "Error writing pending operations", e1);
if (fos != null) {
@@ -2389,85 +2583,6 @@ public class SyncStorageEngine extends Handler {
}
}
- /** Write all currently pending ops to the pending ops file. */
- private void writePendingOperationLocked(PendingOperation pop, XmlSerializer out)
- throws IOException {
- // Pending operation.
- out.startTag(null, "op");
-
- out.attribute(null, XML_ATTR_VERSION, Integer.toString(PENDING_OPERATION_VERSION));
- out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId));
- out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource));
- out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited));
- out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason));
- extrasToXml(out, pop.extras);
-
- out.endTag(null, "op");
- }
-
- /**
- * Append the given operation to the pending ops file; if unable to,
- * write all pending ops.
- */
- private void appendPendingOperationLocked(PendingOperation op) {
- if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Appending to " + mPendingFile.getBaseFile());
- }
- FileOutputStream fos = null;
- try {
- fos = mPendingFile.openAppend();
- } catch (java.io.IOException e) {
- if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Failed append; writing full file");
- }
- writePendingOperationsLocked();
- return;
- }
-
- try {
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(fos, "utf-8");
- writePendingOperationLocked(op, out);
- out.endDocument();
- mPendingFile.finishWrite(fos);
- } catch (java.io.IOException e1) {
- Log.w(TAG, "Error writing appending operation", e1);
- mPendingFile.failWrite(fos);
- } finally {
- try {
- fos.close();
- } catch (IOException e) {}
- }
- }
-
- static private byte[] flattenBundle(Bundle bundle) {
- byte[] flatData = null;
- Parcel parcel = Parcel.obtain();
- try {
- bundle.writeToParcel(parcel, 0);
- flatData = parcel.marshall();
- } finally {
- parcel.recycle();
- }
- return flatData;
- }
-
- static private Bundle unflattenBundle(byte[] flatData) {
- Bundle bundle;
- Parcel parcel = Parcel.obtain();
- try {
- parcel.unmarshall(flatData, 0, flatData.length);
- parcel.setDataPosition(0);
- bundle = parcel.readBundle();
- } catch (RuntimeException e) {
- // A RuntimeException is thrown if we were unable to parse the parcel.
- // Create an empty parcel in this case.
- bundle = new Bundle();
- } finally {
- parcel.recycle();
- }
- return bundle;
- }
private void extrasToXml(XmlSerializer out, Bundle extras) throws java.io.IOException {
for (String key : extras.keySet()) {
@@ -2501,6 +2616,26 @@ public class SyncStorageEngine extends Handler {
}
}
+ private void requestSync(AuthorityInfo authorityInfo, int reason, Bundle extras) {
+ if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID
+ && mSyncRequestListener != null) {
+ mSyncRequestListener.onSyncRequest(authorityInfo.base, reason, extras);
+ } else {
+ SyncRequest.Builder req =
+ new SyncRequest.Builder()
+ .syncOnce(0, 0)
+ .setExtras(extras);
+ if (authorityInfo.base.target_provider) {
+ req.setSyncAdapter(
+ authorityInfo.base.account,
+ authorityInfo.base.provider);
+ } else {
+ req.setSyncAdapter(authorityInfo.base.service);
+ }
+ ContentResolver.requestSync(req.build());
+ }
+ }
+
private void requestSync(Account account, int userId, int reason, String authority,
Bundle extras) {
// If this is happening in the system process, then call the syncrequest listener
@@ -2509,7 +2644,10 @@ public class SyncStorageEngine extends Handler {
// which will know which userId to apply based on the Binder id.
if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID
&& mSyncRequestListener != null) {
- mSyncRequestListener.onSyncRequest(account, userId, reason, authority, extras);
+ mSyncRequestListener.onSyncRequest(
+ new EndPoint(account, authority, userId),
+ reason,
+ extras);
} else {
ContentResolver.requestSync(account, authority, extras);
}
@@ -2605,10 +2743,8 @@ public class SyncStorageEngine extends Handler {
public void dumpPendingOperations(StringBuilder sb) {
sb.append("Pending Ops: ").append(mPendingOperations.size()).append(" operation(s)\n");
for (PendingOperation pop : mPendingOperations) {
- sb.append("(" + pop.account)
- .append(", u" + pop.userId)
- .append(", " + pop.authority)
- .append(", " + pop.extras)
+ sb.append("(info: " + pop.authority.toString())
+ .append(", extras: " + pop.extras)
.append(")\n");
}
}
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
index e44652f..853d2a2 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -17,6 +17,7 @@
package com.android.server.content;
import android.accounts.Account;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
@@ -32,22 +33,33 @@ import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.content.SyncStorageEngine.EndPoint;
+
import com.android.internal.os.AtomicFile;
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
+import com.android.server.content.SyncStorageEngine.EndPoint;
+
public class SyncStorageEngineTest extends AndroidTestCase {
protected Account account1;
+ protected ComponentName syncService1;
protected String authority1 = "testprovider";
protected Bundle defaultBundle;
protected final int DEFAULT_USER = 0;
-
+
+ /* Some default poll frequencies. */
+ final long dayPoll = (60 * 60 * 24);
+ final long dayFuzz = 60;
+ final long thousandSecs = 1000;
+ final long thousandSecsFuzz = 100;
+
MockContentResolver mockResolver;
SyncStorageEngine engine;
-
+
private File getSyncDir() {
return new File(new File(getContext().getFilesDir(), "system"), "sync");
}
@@ -55,6 +67,7 @@ public class SyncStorageEngineTest extends AndroidTestCase {
@Override
public void setUp() {
account1 = new Account("a@example.com", "example.type");
+ syncService1 = new ComponentName("com.example", "SyncService");
// Default bundle.
defaultBundle = new Bundle();
defaultBundle.putInt("int_key", 0);
@@ -80,11 +93,13 @@ public class SyncStorageEngineTest extends AndroidTestCase {
SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
new TestContext(mockResolver, getContext()));
-
long time0 = 1000;
- long historyId = engine.insertStartSyncEvent(
- account, 0, SyncOperation.REASON_PERIODIC, authority, time0,
- SyncStorageEngine.SOURCE_LOCAL, false /* initialization */, null /* extras */);
+ SyncOperation op = new SyncOperation(account, 0,
+ SyncOperation.REASON_PERIODIC,
+ SyncStorageEngine.SOURCE_LOCAL,
+ authority,
+ null, time0, 0 /* flex*/, 0, 0, true);
+ long historyId = engine.insertStartSyncEvent(op, time0);
long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
}
@@ -94,27 +109,28 @@ public class SyncStorageEngineTest extends AndroidTestCase {
*/
@MediumTest
public void testPending() throws Exception {
- SyncStorageEngine.PendingOperation pop =
- new SyncStorageEngine.PendingOperation(account1, DEFAULT_USER,
- SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_LOCAL,
- authority1, defaultBundle, false);
-
- engine.insertIntoPending(pop);
+ SyncOperation sop = new SyncOperation(account1,
+ DEFAULT_USER,
+ SyncOperation.REASON_PERIODIC,
+ SyncStorageEngine.SOURCE_LOCAL, authority1, null,
+ 0 /* runtime */, 0 /* flex */, 0 /* backoff */, 0 /* delayuntil */,
+ true /* expedited */);
+ engine.insertIntoPending(sop);
+
// Force engine to read from disk.
engine.clearAndReadState();
assert(engine.getPendingOperationCount() == 1);
List<SyncStorageEngine.PendingOperation> pops = engine.getPendingOperations();
SyncStorageEngine.PendingOperation popRetrieved = pops.get(0);
- assertEquals(pop.account, popRetrieved.account);
- assertEquals(pop.reason, popRetrieved.reason);
- assertEquals(pop.userId, popRetrieved.userId);
- assertEquals(pop.syncSource, popRetrieved.syncSource);
- assertEquals(pop.authority, popRetrieved.authority);
- assertEquals(pop.expedited, popRetrieved.expedited);
- assertEquals(pop.serviceName, popRetrieved.serviceName);
- assert(android.content.PeriodicSync.syncExtrasEquals(pop.extras, popRetrieved.extras));
-
+ assertEquals(sop.target.account, popRetrieved.authority.account);
+ assertEquals(sop.target.provider, popRetrieved.authority.provider);
+ assertEquals(sop.target.service, popRetrieved.authority.service);
+ assertEquals(sop.target.userId, popRetrieved.authority.userId);
+ assertEquals(sop.reason, popRetrieved.reason);
+ assertEquals(sop.syncSource, popRetrieved.syncSource);
+ assertEquals(sop.expedited, popRetrieved.expedited);
+ assert(android.content.PeriodicSync.syncExtrasEquals(sop.extras, popRetrieved.extras));
}
/**
@@ -134,42 +150,44 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final int period2 = 1000;
PeriodicSync sync1 = new PeriodicSync(account1, authority, extras1, period1);
+ EndPoint end1 = new EndPoint(account1, authority, 0);
+
PeriodicSync sync2 = new PeriodicSync(account1, authority, extras2, period1);
PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2);
PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2);
-
+
removePeriodicSyncs(engine, account1, 0, authority);
removePeriodicSyncs(engine, account2, 0, authority);
removePeriodicSyncs(engine, account1, 1, authority);
// this should add two distinct periodic syncs for account1 and one for account2
- engine.addPeriodicSync(sync1, 0);
- engine.addPeriodicSync(sync2, 0);
- engine.addPeriodicSync(sync3, 0);
- engine.addPeriodicSync(sync4, 0);
+ engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 0), period1, 0, extras1);
+ engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 0), period1, 0, extras2);
+ engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 0), period2, 0, extras2);
+ engine.updateOrAddPeriodicSync(new EndPoint(account2, authority, 0), period2, 0, extras2);
// add a second user
- engine.addPeriodicSync(sync2, 1);
+ engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 1), period1, 0, extras2);
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(new EndPoint(account1, authority, 0));
assertEquals(2, syncs.size());
assertEquals(sync1, syncs.get(0));
assertEquals(sync3, syncs.get(1));
- engine.removePeriodicSync(sync1, 0);
+ engine.removePeriodicSync(new EndPoint(account1, authority, 0), extras1);
- syncs = engine.getPeriodicSyncs(account1, 0, authority);
+ syncs = engine.getPeriodicSyncs(new EndPoint(account1, authority, 0));
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account2, 0, authority);
+ syncs = engine.getPeriodicSyncs(new EndPoint(account2, authority, 0));
assertEquals(1, syncs.size());
assertEquals(sync4, syncs.get(0));
- syncs = engine.getPeriodicSyncs(sync2.account, 1, sync2.authority);
+ syncs = engine.getPeriodicSyncs(new EndPoint(sync2.account, sync2.authority, 1));
assertEquals(1, syncs.size());
assertEquals(sync2, syncs.get(0));
}
@@ -190,12 +208,19 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final int period2 = 1000;
final int flex1 = 10;
final int flex2 = 100;
+ EndPoint point1 = new EndPoint(account1, authority, 0);
+ EndPoint point2 = new EndPoint(account2, authority, 0);
+ EndPoint point1User2 = new EndPoint(account1, authority, 1);
PeriodicSync sync1 = new PeriodicSync(account1, authority, extras1, period1, flex1);
PeriodicSync sync2 = new PeriodicSync(account1, authority, extras2, period1, flex1);
PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2, flex2);
PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2, flex2);
+ EndPoint target1 = new EndPoint(account1, authority, 0);
+ EndPoint target2 = new EndPoint(account2, authority, 0);
+ EndPoint target1UserB = new EndPoint(account1, authority, 1);
+
MockContentResolver mockResolver = new MockContentResolver();
SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
@@ -206,40 +231,42 @@ public class SyncStorageEngineTest extends AndroidTestCase {
removePeriodicSyncs(engine, account1, 1, authority);
// This should add two distinct periodic syncs for account1 and one for account2
- engine.addPeriodicSync(sync1, 0);
- engine.addPeriodicSync(sync2, 0);
- engine.addPeriodicSync(sync3, 0); // Should edit sync2 and update the period.
- engine.addPeriodicSync(sync4, 0);
- // add a second user
- engine.addPeriodicSync(sync2, 1);
+ engine.updateOrAddPeriodicSync(target1, period1, flex1, extras1);
+ engine.updateOrAddPeriodicSync(target1, period1, flex1, extras2);
+ // Edit existing sync and update the period and flex.
+ engine.updateOrAddPeriodicSync(target1, period2, flex2, extras2);
+ engine.updateOrAddPeriodicSync(target2, period2, flex2, extras2);
+ // add a target for a second user.
+ engine.updateOrAddPeriodicSync(target1UserB, period1, flex1, extras2);
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
assertEquals(2, syncs.size());
assertEquals(sync1, syncs.get(0));
assertEquals(sync3, syncs.get(1));
- engine.removePeriodicSync(sync1, 0);
+ engine.removePeriodicSync(target1, extras1);
- syncs = engine.getPeriodicSyncs(account1, 0, authority);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account2, 0, authority);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync4, syncs.get(0));
- syncs = engine.getPeriodicSyncs(sync2.account, 1, sync2.authority);
+ syncs = engine.getPeriodicSyncs(target1UserB);
assertEquals(1, syncs.size());
assertEquals(sync2, syncs.get(0));
}
private void removePeriodicSyncs(SyncStorageEngine engine, Account account, int userId, String authority) {
- engine.setIsSyncable(account, userId, authority, engine.getIsSyncable(account, 0, authority));
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, userId, authority);
+ EndPoint target = new EndPoint(account, authority, userId);
+ engine.setIsSyncable(account, userId, authority, engine.getIsSyncable(account, userId, authority));
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target);
for (PeriodicSync sync : syncs) {
- engine.removePeriodicSync(sync, userId);
+ engine.removePeriodicSync(target, sync.extras);
}
}
@@ -264,16 +291,19 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final int flex1 = 10;
final int flex2 = 100;
+ EndPoint point1 = new EndPoint(account1, authority1, 0);
+ EndPoint point2 = new EndPoint(account1, authority2, 0);
+ EndPoint point3 = new EndPoint(account2, authority1, 0);
+
PeriodicSync sync1 = new PeriodicSync(account1, authority1, extras1, period1, flex1);
PeriodicSync sync2 = new PeriodicSync(account1, authority1, extras2, period1, flex1);
PeriodicSync sync3 = new PeriodicSync(account1, authority2, extras1, period1, flex1);
PeriodicSync sync4 = new PeriodicSync(account1, authority2, extras2, period2, flex2);
PeriodicSync sync5 = new PeriodicSync(account2, authority1, extras1, period1, flex1);
- MockContentResolver mockResolver = new MockContentResolver();
-
- SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
- new TestContext(mockResolver, getContext()));
+ EndPoint target1 = new EndPoint(account1, authority1, 0);
+ EndPoint target2 = new EndPoint(account1, authority2, 0);
+ EndPoint target3 = new EndPoint(account2, authority1, 0);
removePeriodicSyncs(engine, account1, 0, authority1);
removePeriodicSyncs(engine, account2, 0, authority1);
@@ -294,26 +324,26 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.setIsSyncable(account2, 0, authority2, 0);
engine.setSyncAutomatically(account2, 0, authority2, true);
- engine.addPeriodicSync(sync1, 0);
- engine.addPeriodicSync(sync2, 0);
- engine.addPeriodicSync(sync3, 0);
- engine.addPeriodicSync(sync4, 0);
- engine.addPeriodicSync(sync5, 0);
+ engine.updateOrAddPeriodicSync(target1, period1, flex1, extras1);
+ engine.updateOrAddPeriodicSync(target1, period1, flex1, extras2);
+ engine.updateOrAddPeriodicSync(target2, period1, flex1, extras1);
+ engine.updateOrAddPeriodicSync(target2, period2, flex2, extras2);
+ engine.updateOrAddPeriodicSync(target3, period1, flex1, extras1);
engine.writeAllState();
engine.clearAndReadState();
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority1);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
assertEquals(2, syncs.size());
assertEquals(sync1, syncs.get(0));
assertEquals(sync2, syncs.get(1));
- syncs = engine.getPeriodicSyncs(account1, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(2, syncs.size());
assertEquals(sync3, syncs.get(0));
assertEquals(sync4, syncs.get(1));
- syncs = engine.getPeriodicSyncs(account2, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync5, syncs.get(0));
@@ -328,6 +358,35 @@ public class SyncStorageEngineTest extends AndroidTestCase {
assertEquals(0, engine.getIsSyncable(account2, 0, authority2));
}
+ @SmallTest
+ public void testComponentParsing() throws Exception {
+ // Sync Service component.
+ PeriodicSync sync1 = new PeriodicSync(syncService1, Bundle.EMPTY, dayPoll, dayFuzz);
+
+ byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<accounts version=\"2\" >\n"
+ + "<authority id=\"0\" user=\"0\" package=\"" + syncService1.getPackageName() + "\""
+ + " class=\"" + syncService1.getClassName() + "\" syncable=\"true\">"
+ + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+ + "\n</authority>"
+ + "</accounts>").getBytes();
+
+ File syncDir = getSyncDir();
+ syncDir.mkdirs();
+ AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
+ FileOutputStream fos = accountInfoFile.startWrite();
+ fos.write(accountsFileData);
+ accountInfoFile.finishWrite(fos);
+
+ engine.clearAndReadState();
+
+ // Test service component read
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(
+ new SyncStorageEngine.EndPoint(syncService1, 0));
+ assertEquals(1, syncs.size());
+ assertEquals(1, engine.getIsTargetServiceActive(syncService1, 0));
+ }
+
@MediumTest
/**
* V2 introduces flex time as well as service components.
@@ -339,20 +398,20 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final String authority2 = "auth2";
final String authority3 = "auth3";
- final long dayPoll = (60 * 60 * 24);
- final long dayFuzz = 60;
- final long thousandSecs = 1000;
- final long thousandSecsFuzz = 100;
- final Bundle extras = new Bundle();
- PeriodicSync sync1 = new PeriodicSync(account, authority1, extras, dayPoll, dayFuzz);
- PeriodicSync sync2 = new PeriodicSync(account, authority2, extras, dayPoll, dayFuzz);
- PeriodicSync sync3 = new PeriodicSync(account, authority3, extras, dayPoll, dayFuzz);
- PeriodicSync sync1s = new PeriodicSync(account, authority1, extras, thousandSecs, thousandSecsFuzz);
- PeriodicSync sync2s = new PeriodicSync(account, authority2, extras, thousandSecs, thousandSecsFuzz);
- PeriodicSync sync3s = new PeriodicSync(account, authority3, extras, thousandSecs, thousandSecsFuzz);
- MockContentResolver mockResolver = new MockContentResolver();
-
- final TestContext testContext = new TestContext(mockResolver, getContext());
+ EndPoint target1 = new EndPoint(account, authority1, 0);
+ EndPoint target2 = new EndPoint(account, authority2, 0);
+ EndPoint target3 = new EndPoint(account, authority3, 0);
+ EndPoint target4 = new EndPoint(account, authority3, 1);
+
+ PeriodicSync sync1 = new PeriodicSync(account, authority1, Bundle.EMPTY, dayPoll, dayFuzz);
+ PeriodicSync sync2 = new PeriodicSync(account, authority2, Bundle.EMPTY, dayPoll, dayFuzz);
+ PeriodicSync sync3 = new PeriodicSync(account, authority3, Bundle.EMPTY, dayPoll, dayFuzz);
+ PeriodicSync sync1s = new PeriodicSync(account, authority1, Bundle.EMPTY, thousandSecs,
+ thousandSecsFuzz);
+ PeriodicSync sync2s = new PeriodicSync(account, authority2, Bundle.EMPTY, thousandSecs,
+ thousandSecsFuzz);
+ PeriodicSync sync3s = new PeriodicSync(account, authority3, Bundle.EMPTY, thousandSecs,
+ thousandSecsFuzz);
byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<accounts version=\"2\" >\n"
@@ -378,21 +437,22 @@ public class SyncStorageEngineTest extends AndroidTestCase {
fos.write(accountsFileData);
accountInfoFile.finishWrite(fos);
- SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
+ engine.clearAndReadState();
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
assertEquals("Got incorrect # of syncs", 1, syncs.size());
assertEquals(sync1, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync2, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 1, authority3);
+ syncs = engine.getPeriodicSyncs(target4);
+
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
@@ -411,13 +471,13 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.clearAndReadState();
- syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(0, syncs.size());
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(0, syncs.size());
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(0, syncs.size());
accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
@@ -440,15 +500,15 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.clearAndReadState();
- syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(1, syncs.size());
assertEquals(sync1s, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync2s, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync3s, syncs.get(0));
}
@@ -460,6 +520,12 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final String authority2 = "auth2";
final String authority3 = "auth3";
final Bundle extras = new Bundle();
+
+ EndPoint target1 = new EndPoint(account, authority1, 0);
+ EndPoint target2 = new EndPoint(account, authority2, 0);
+ EndPoint target3 = new EndPoint(account, authority3, 0);
+ EndPoint target4 = new EndPoint(account, authority3, 1);
+
PeriodicSync sync1 = new PeriodicSync(account, authority1, extras, (long) (60 * 60 * 24));
PeriodicSync sync2 = new PeriodicSync(account, authority2, extras, (long) (60 * 60 * 24));
PeriodicSync sync3 = new PeriodicSync(account, authority3, extras, (long) (60 * 60 * 24));
@@ -488,19 +554,20 @@ public class SyncStorageEngineTest extends AndroidTestCase {
SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
assertEquals(1, syncs.size());
assertEquals("expected sync1: " + sync1.toString() + " == sync 2" + syncs.get(0).toString(), sync1, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync2, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
+ syncs = engine.getPeriodicSyncs(target4);
+
- syncs = engine.getPeriodicSyncs(account, 1, authority3);
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
@@ -518,13 +585,13 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.clearAndReadState();
- syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(0, syncs.size());
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(0, syncs.size());
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(0, syncs.size());
accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
@@ -547,15 +614,15 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.clearAndReadState();
- syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(1, syncs.size());
assertEquals(sync1s, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync2s, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync3s, syncs.get(0));
}