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;
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;
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";
/** 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. */
/** 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;
"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";
}
public static class PendingOperation {
- final Account account;
- final int userId;
+ final EndPoint target;
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.target = authority.target;
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.target = other.target;
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 target.matchesSpec(other.target);
+ }
+
+ public String toString() {
+ return "service=" + target.service
+ + " user=" + target.userId
+ + " auth=" + target
+ + " account=" + target.account
+ + " src=" + syncSource
+ + " extras=" + extras;
}
}
}
}
- 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 Endpoint for a sync matches if it targets the same sync adapter for the same user.
+ *
+ * @param spec the Endpoint to match. If the spec has null fields, they indicate a wildcard
+ * and match any.
+ */
+ public boolean matchesSpec(EndPoint spec) {
+ if (userId != spec.userId
+ && userId != UserHandle.USER_ALL
+ && spec.userId != UserHandle.USER_ALL) {
+ return false;
+ }
+ if (target_service && spec.target_service) {
+ return service.equals(spec.service);
+ } else if (target_provider && spec.target_provider) {
+ boolean accountsMatch;
+ if (spec.account == null) {
+ accountsMatch = true;
+ } else {
+ accountsMatch = account.equals(spec.account);
+ }
+ boolean providersMatch;
+ if (spec.provider == null) {
+ providersMatch = true;
+ } else {
+ providersMatch = provider.equals(spec.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() + "/")
+ .append(service.getClassName());
+ } else {
+ sb.append("invalid target");
+ }
+ sb.append(":u" + userId);
+ return sb.toString();
+ }
+ }
+
+ public static class AuthorityInfo {
+ final EndPoint target;
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;
+ /** Time offset to add to any requests coming to this target. */
long delayUntil;
+
final ArrayList<PeriodicSync> periodicSyncs;
/**
* @param toCopy AuthorityInfo to be copied.
*/
AuthorityInfo(AuthorityInfo toCopy) {
- account = toCopy.account;
- userId = toCopy.userId;
- authority = toCopy.authority;
- service = toCopy.service;
+ target = toCopy.target;
ident = toCopy.ident;
enabled = toCopy.enabled;
syncable = toCopy.syncable;
}
}
- /**
- * 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;
- 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
+ AuthorityInfo(EndPoint info, int id) {
+ target = 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>();
- // 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)));
+ defaultInitialisation();
}
- /**
- * 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.
- */
- 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;
+ 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>();
- 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 (target.target_provider) {
+ defaultSync =
+ new PeriodicSync(target.account, target.provider,
+ new Bundle(),
+ DEFAULT_POLL_FREQUENCY_SECONDS,
+ calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS));
+ periodicSyncs.add(defaultSync);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return target + ", enabled=" + enabled + ", syncable=" + syncable + ", backoff="
+ + backoffTime + ", delay=" + delayUntil;
}
}
}
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.
private final RemoteCallbackList<ISyncStatusObserver> mChangeListeners
= new RemoteCallbackList<ISyncStatusObserver>();
- /** Reverse mapping for component name -> <userid -> authority id>. */
- private final HashMap<ComponentName, SparseArray<AuthorityInfo>> mServices =
- new HashMap<ComponentName, SparseArray<AuthorityInfo>>();
+ /** Reverse mapping for component name -> <userid -> target id>. */
+ private final ArrayMap<ComponentName, SparseArray<AuthorityInfo>> mServices =
+ new ArrayMap<ComponentName, SparseArray<AuthorityInfo>>();
private int mNextAuthorityId = 0;
mChangeListeners.finishBroadcast();
}
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "reportChange " + which + " to: " + reports);
}
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;
}
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.target.matchesSpec(new EndPoint(account, providerName, userId))
+ && authorityInfo.enabled) {
return true;
}
}
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;
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;
}
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.target != null
+ && authorityInfo.target.provider.equals(providerName)) {
+ return authorityInfo.syncable;
}
}
return -1;
}
public void setIsSyncable(Account account, int userId, String providerName, 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);
+ setSyncableStateForEndPoint(new EndPoint(account, providerName, userId), syncable);
+ }
+
+ public boolean getIsTargetServiceActive(ComponentName cname, int userId) {
+ synchronized (mAuthorities) {
+ if (cname != null) {
+ AuthorityInfo authority = getAuthorityLocked(
+ new EndPoint(cname, userId),
+ "get service active");
+ if (authority == null) {
+ return false;
+ }
+ return (authority.syncable == 1);
+ }
+ return false;
}
+ }
+
+ public void setIsTargetServiceActive(ComponentName cname, int userId, boolean active) {
+ setSyncableStateForEndPoint(new EndPoint(cname, userId), active ? 1 : 0);
+ }
+
+ /**
+ * 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 target target to set value for.
+ * @param syncable 0 indicates unsyncable, <0 unknown, >0 is active/syncable.
+ */
+ private void setSyncableStateForEndPoint(EndPoint target, int syncable) {
+ AuthorityInfo aInfo;
synchronized (mAuthorities) {
- AuthorityInfo authority =
- getOrCreateAuthorityLocked(account, userId, providerName, -1, false);
- if (authority.syncable == syncable) {
- if (DEBUG) {
+ aInfo = getOrCreateAuthorityLocked(target, -1, false);
+ if (syncable > 1) {
+ syncable = 1;
+ } else if (syncable < -1) {
+ syncable = -1;
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "setIsSyncable: " + aInfo.toString() + " -> " + syncable);
+ }
+ if (aInfo.syncable == syncable) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
}
return;
}
- authority.syncable = syncable;
+ 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);
}
}
/**
- * Callers of this function need to hold a lock for syncQueue object passed in. Bear in mind
- * this function grabs the lock for {@link #mAuthorities}
- * @param syncQueue queue containing pending sync operations.
+ * 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.
+ * @return true if a change occured.
*/
+ 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.target.provider)) {
+ continue;
+ }
+ if (authorityInfo.backoffTime != nextSyncTime
+ || authorityInfo.backoffDelay != nextDelay) {
+ authorityInfo.backoffTime = nextSyncTime;
+ authorityInfo.backoffDelay = nextDelay;
+ changed = true;
+ }
+ }
+ }
+ return changed;
+ }
+
public void clearAllBackoffsLocked(SyncQueue syncQueue) {
boolean changed = false;
synchronized (mAuthorities) {
- 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) {
- Log.v(TAG, "clearAllBackoffs:"
- + " authority:" + authorityInfo.authority
- + " account:" + accountInfo.accountAndUser.account.name
- + " user:" + accountInfo.accountAndUser.userId
- + " backoffTime was: " + authorityInfo.backoffTime
- + " backoffDelay was: " + authorityInfo.backoffDelay);
+ // 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 (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "clearAllBackoffsLocked:"
+ + " authority:" + authorityInfo.target
+ + " account:" + accountInfo.accountAndUser.account.name
+ + " user:" + accountInfo.accountAndUser.userId
+ + " backoffTime was: " + authorityInfo.backoffTime
+ + " backoffDelay was: " + authorityInfo.backoffDelay);
+ }
+ authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
+ authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
+ changed = true;
}
- 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();
}
}
}
}
- 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 {
+ return;
+ }
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.
+ 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 target 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 a target. Never 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.equals(flag)) {
return;
}
mMasterSyncAutomatically.put(userId, flag);
}
}
- 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);
}
/**
- * 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
+ * target.
*/
- 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.target.matchesSpec(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.isExpedited());
+ mPendingOperations.add(pop);
+ appendPendingOperationLocked(pop);
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = true;
}
-
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
- return op;
+ return pop;
}
/**
* Remove from list of pending operations. If successful, search through list for matching
- * 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
+ * authorities. If there are no more pending syncs for the same target,
+ * update the SyncStatusInfo for that target.
+ * @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
} else {
mNumPendingFinished++;
}
-
- AuthorityInfo authority = getAuthorityLocked(op.account, op.userId, op.authority,
- "deleteFromPending");
+ AuthorityInfo authority = getAuthorityLocked(op.target, "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;
}
}
*/
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()) {
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()) {
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,
- -1 /* assign a new identifier if creating a new authority */,
+ final EndPoint info = activeSyncContext.mSyncOperation.target;
+ AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(
+ info,
+ -1 /* assign a new identifier if creating a new target */,
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.target.account,
+ authorityInfo.target.provider,
activeSyncContext.mStartTime);
- getCurrentSyncs(authority.userId).add(syncInfo);
+ getCurrentSyncs(authorityInfo.target.userId).add(syncInfo);
}
-
reportActiveChange();
return syncInfo;
}
*/
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);
}
/**
- * Note that sync has started for the given account and authority.
+ * Note that sync has started for the given operation.
*/
- 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);
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;
}
/**
- * @return a copy of the current syncs data structure. Will not return
- * null.
+ * @param userId Id of user to return current sync info.
+ * @param canAccessAccounts Determines whether to redact Account information from the result.
+ * @return a copy of the current syncs data structure. Will not return null.
*/
- public List<SyncInfo> getCurrentSyncsCopy(int userId) {
+ public List<SyncInfo> getCurrentSyncsCopy(int userId, boolean canAccessAccounts) {
synchronized (mAuthorities) {
final List<SyncInfo> syncs = getCurrentSyncsLocked(userId);
final List<SyncInfo> syncsCopy = new ArrayList<SyncInfo>();
for (SyncInfo sync : syncs) {
- syncsCopy.add(new SyncInfo(sync));
+ SyncInfo copy;
+ if (!canAccessAccounts) {
+ copy = SyncInfo.createAccountRedacted(
+ sync.authorityId, sync.authority, sync.startTime);
+ } else {
+ copy = new SyncInfo(sync);
+ }
+ syncsCopy.add(copy);
}
return syncsCopy;
}
}
/**
- * Return a copy of the specified authority with the corresponding sync status
+ * Return a copy of the specified target 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,
- -1 /* assign a new identifier if creating a new authority */,
+ AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(info,
+ -1 /* assign a new identifier if creating a new target */,
true /* write to storage if this results in a change */);
return createCopyPairOfAuthorityWithSyncStatusLocked(authorityInfo);
}
}
/**
- * Returns the status that matches the authority and account.
+ * Returns the status that matches the target.
*
- * @param account the account we want to check
- * @param authority the authority whose row should be selected
- * @return the SyncStatusInfo for the authority or null if none found.
+ * @param info the endpoint target we are querying status info for.
+ * @return the SyncStatusInfo for the endpoint.
*/
- public SyncStatusInfo getStatusByAccountAndAuthority(Account account, int userId,
- String authority) {
- if (account == null || authority == null) {
- return null;
+ public SyncStatusInfo getStatusByAuthority(EndPoint info) {
+ if (info.target_provider && (info.account == null || info.provider == null)) {
+ return null;
+ } else if (info.target_service && info.service == null) {
+ return null;
}
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.target.matchesSpec(info)) {
return cur;
}
}
}
}
- /**
- * 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.target.matchesSpec(info)) {
continue;
}
- if (account != null && !ainfo.account.equals(account)) {
- continue;
- }
- if (ainfo.authority.equals(authority) && cur.pending) {
+ if (cur.pending) {
return true;
}
}
}
/**
- * Retrieve an authority, returning null if one does not exist.
+ * Retrieve a target's full info, 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 info of the target to look up.
* @param tag If non-null, this will be used in a log message if the
- * requested authority does not exist.
+ * requested target 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 ident unique identifier for authority. -1 for none.
+ * @param info info identifying target.
+ * @param ident unique identifier for target. -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 target, 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));
/**
* Updates (in a synchronized way) the periodic sync time of the specified
- * authority id and target periodic sync
+ * target 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) {
}
if (!found) {
Log.w(TAG, "Ignoring setPeriodicSyncTime request for a sync that does not exist. " +
- "Authority: " + authorityInfo.authority);
+ "Authority: " + authorityInfo.target);
}
}
try {
fis = mAccountInfoFile.openRead();
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile());
+ Log.v(TAG_FILE, "Reading " + mAccountInfoFile.getBaseFile());
}
XmlPullParser parser = Xml.newPullParser();
parser.setInput(fis, null);
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 doesn't target a provider
+ if (authority.target.target_service) {
+ continue;
+ }
// 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.target.provider);
if (newAuthorityName == null) {
continue;
}
}
// 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.target.account,
+ newAuthorityName,
+ authority.target.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.target.account,
+ authorityInfo.target.userId,
+ authorityInfo.target.provider,
+ false /* doWrite */);
writeNeeded = true;
}
String packageName = parser.getAttributeValue(null, "package");
String className = parser.getAttributeValue(null, "class");
int userId = user == null ? 0 : Integer.parseInt(user);
- if (accountType == null) {
+ if (accountType == null && packageName == null) {
accountType = "com.google";
syncable = "unknown";
}
authority = mAuthorities.get(id);
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Adding authority: account="
- + accountName + " auth=" + authorityName
+ Log.v(TAG_FILE, "Adding authority:"
+ + " account=" + accountName
+ + " accountType=" + accountType
+ + " auth=" + authorityName
+ + " package=" + packageName
+ + " class=" + className
+ " user=" + userId
+ " enabled=" + enabled
+ " syncable=" + syncable);
}
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;
+ if (accountName != null && authorityName != null) {
+ info = new EndPoint(
+ new Account(accountName, accountType),
+ authorityName, userId);
} else {
- authority = getOrCreateAuthorityLocked(
- new ComponentName(packageName, className), userId, id, false);
+ 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
// want the default, which is a daily periodic sync.
/**
* 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");
try {
flextime = Long.parseLong(flexValue);
} catch (NumberFormatException e) {
- Log.e(TAG, "Error formatting value parsed for periodic sync flex: " + flexValue);
flextime = calculateDefaultFlexTime(period);
+ Log.e(TAG, "Error formatting value parsed for periodic sync flex: " + flexValue
+ + ", using default: "
+ + flextime);
} catch (NullPointerException expected) {
flextime = calculateDefaultFlexTime(period);
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.target.target_provider) {
+ periodicSync =
+ new PeriodicSync(authorityInfo.target.account,
+ authorityInfo.target.provider,
+ extras,
period, flextime);
- authority.periodicSyncs.add(periodicSync);
+ } else {
+ Log.e(TAG, "Unknown target.");
+ return null;
+ }
+ authorityInfo.periodicSyncs.add(periodicSync);
return periodicSync;
}
*/
private void writeAccountInfoLocked() {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile());
+ Log.v(TAG_FILE, "Writing new " + mAccountInfoFile.getBaseFile());
}
FileOutputStream fos = null;
final int N = mAuthorities.size();
for (int i = 0; i < N; i++) {
AuthorityInfo authority = mAuthorities.valueAt(i);
+ EndPoint info = authority.target;
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");
// Copy in all of the status information, as well as accounts.
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Reading legacy sync accounts db");
+ Log.v(TAG_FILE, "Reading legacy sync accounts db");
}
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables("stats, status");
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;
while (i > 0) {
i--;
AuthorityInfo authority = mAuthorities.valueAt(i);
- if (authority.authority.equals(provider)) {
+ if (authority.target.provider.equals(provider)) {
authority.enabled = value == null || Boolean.parseBoolean(value);
authority.syncable = 1;
}
*/
private void readStatusLocked() {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Reading " + mStatusFile.getBaseFile());
+ Log.v(TAG_FILE, "Reading " + mStatusFile.getBaseFile());
}
try {
byte[] data = mStatusFile.readFully();
if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
status.pending = false;
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Adding status for id "
- + status.authorityId);
+ Log.v(TAG_FILE, "Adding status for id " + status.authorityId);
}
mSyncStatus.put(status.authorityId, status);
}
*/
private void writeStatusLocked() {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Writing new " + mStatusFile.getBaseFile());
+ Log.v(TAG_FILE, "Writing new " + mStatusFile.getBaseFile());
}
// The file is being written, so we don't need to have a scheduled
if (!mPendingFile.getBaseFile().exists()) {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
Log.v(TAG_FILE, "No pending operation file.");
- return;
}
+ return;
}
try {
fis = mPendingFile.openRead();
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, "Reading " + mPendingFile.getBaseFile());
+ }
XmlPullParser parser;
parser = Xml.newPullParser();
parser.setInput(fis, null);
}
if (eventType == XmlPullParser.END_DOCUMENT) return; // Nothing to read.
- String tagName = parser.getName();
do {
PendingOperation pop = null;
if (eventType == XmlPullParser.START_TAG) {
try {
- tagName = parser.getName();
+ String tagName = parser.getName();
if (parser.getDepth() == 1 && "op".equals(tagName)) {
// Verify version.
String versionString =
}
if (authority != null) {
pop = new PendingOperation(
- authority.account, authority.userId, reason,
- syncSource, authority.authority, new Bundle(),
- expedited);
+ 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
+ + pop.target
+ " src=" + pop.syncSource
+ " reason=" + pop.reason
+ " expedited=" + pop.expedited);
- }
+ }
} else {
// Skip non-existent authority.
pop = null;
}
}
+ 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_VERSION = "version";
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.
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();
for (int i = 0; i < N; i++) {
PendingOperation pop = mPendingOperations.get(i);
writePendingOperationLocked(pop, out);
- }
- out.endDocument();
- mPendingFile.finishWrite(fos);
+ }
+ out.endDocument();
+ mPendingFile.finishWrite(fos);
} catch (java.io.IOException e1) {
Log.w(TAG, "Error writing pending operations", e1);
if (fos != null) {
}
}
- 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()) {
out.startTag(null, "extra");
}
}
+ private void requestSync(AuthorityInfo authorityInfo, int reason, Bundle extras) {
+ if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID
+ && mSyncRequestListener != null) {
+ mSyncRequestListener.onSyncRequest(authorityInfo.target, reason, extras);
+ } else {
+ SyncRequest.Builder req =
+ new SyncRequest.Builder()
+ .syncOnce()
+ .setExtras(extras);
+ if (authorityInfo.target.target_provider) {
+ req.setSyncAdapter(authorityInfo.target.account, authorityInfo.target.provider);
+ } else {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Unknown target, skipping sync request.");
+ }
+ return;
+ }
+ 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
// 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);
}
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.target.toString())
+ .append(", extras: " + pop.extras)
.append(")\n");
}
}