summaryrefslogtreecommitdiffstats
path: root/core/java/android/content/SyncManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/content/SyncManager.java')
-rw-r--r--core/java/android/content/SyncManager.java243
1 files changed, 120 insertions, 123 deletions
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 564a804..053cc6f 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -20,8 +20,8 @@ import android.accounts.Account;
import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
import android.accounts.AccountManagerService;
-import android.accounts.OnAccountsUpdateListener;
import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -58,6 +58,7 @@ import android.util.Log;
import android.util.Pair;
import com.android.internal.R;
+import com.android.internal.util.IndentingPrintWriter;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -81,7 +82,7 @@ import java.util.concurrent.CountDownLatch;
/**
* @hide
*/
-public class SyncManager implements OnAccountsUpdateListener {
+public class SyncManager {
private static final String TAG = "SyncManager";
/** Delay a sync due to local changes this long. In milliseconds */
@@ -141,7 +142,8 @@ public class SyncManager implements OnAccountsUpdateListener {
private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
- private volatile AccountAndUser[] mAccounts = INITIAL_ACCOUNTS_ARRAY;
+ // TODO: add better locking around mRunningAccounts
+ private volatile AccountAndUser[] mRunningAccounts = INITIAL_ACCOUNTS_ARRAY;
volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
volatile private PowerManager.WakeLock mSyncManagerWakeLock;
@@ -205,7 +207,10 @@ public class SyncManager implements OnAccountsUpdateListener {
private BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
- onAccountsUpdated(null);
+ updateRunningAccounts();
+
+ // Kick off sync for everyone, since this was a radical account change
+ scheduleSync(null, UserHandle.USER_ALL, null, null, 0 /* no delay */, false);
}
};
@@ -242,33 +247,14 @@ public class SyncManager implements OnAccountsUpdateListener {
return found;
}
- public void onAccountsUpdated(Account[] accounts) {
- // remember if this was the first time this was called after an update
- final boolean justBootedUp = mAccounts == INITIAL_ACCOUNTS_ARRAY;
-
- List<UserInfo> users = getAllUsers();
- if (users == null) return;
-
- int count = 0;
-
- // Get accounts from AccountManager for all the users on the system
- // TODO: Limit this to active users, when such a concept exists.
- AccountAndUser[] allAccounts = AccountManagerService.getSingleton().getAllAccounts();
- for (UserInfo user : users) {
- if (mBootCompleted) {
- Account[] accountsForUser =
- AccountManagerService.getSingleton().getAccounts(user.id);
- mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
- }
- }
-
- mAccounts = allAccounts;
+ public void updateRunningAccounts() {
+ mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
- if (!containsAccountAndUser(allAccounts,
+ if (!containsAccountAndUser(mRunningAccounts,
currentSyncContext.mSyncOperation.account,
currentSyncContext.mSyncOperation.userId)) {
- Log.d(TAG, "canceling sync since the account has been removed");
+ Log.d(TAG, "canceling sync since the account is no longer running");
sendSyncFinishedOrCanceledMessage(currentSyncContext,
null /* no result since this is a cancel */);
}
@@ -277,26 +263,6 @@ public class SyncManager implements OnAccountsUpdateListener {
// we must do this since we don't bother scheduling alarms when
// the accounts are not set yet
sendCheckAlarmsMessage();
-
- if (allAccounts.length > 0) {
- // If this is the first time this was called after a bootup then
- // the accounts haven't really changed, instead they were just loaded
- // from the AccountManager. Otherwise at least one of the accounts
- // has a change.
- //
- // If there was a real account change then force a sync of all accounts.
- // This is a bit of overkill, but at least it will end up retrying syncs
- // that failed due to an authentication failure and thus will recover if the
- // account change was a password update.
- //
- // If this was the bootup case then don't sync everything, instead only
- // sync those that have an unknown syncable state, which will give them
- // a chance to set their syncable state.
-
- boolean onlyThoseWithUnkownSyncableState = justBootedUp;
- scheduleSync(null, UserHandle.USER_ALL, null, null, 0 /* no delay */,
- onlyThoseWithUnkownSyncableState);
- }
}
private BroadcastReceiver mConnectivityIntentReceiver =
@@ -336,19 +302,18 @@ public class SyncManager implements OnAccountsUpdateListener {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) return;
+
if (Intent.ACTION_USER_REMOVED.equals(action)) {
- Log.i(TAG, "User removed - cleanup: u" + userId);
- onUserRemoved(intent);
- } else if (Intent.ACTION_USER_STARTED.equals(action)) {
- Log.i(TAG, "User started - check alarms: u" + userId);
- sendCheckAlarmsMessage();
- } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
- Log.i(TAG, "User stopped - stop syncs: u" + userId);
- cancelActiveSync(
- null /* any account */,
- userId,
- null /* any authority */);
+ Log.i(TAG, "User removed: u" + userId);
+ onUserRemoved(userId);
+ } else if (Intent.ACTION_USER_STARTING.equals(action)) {
+ Log.i(TAG, "User starting: u" + userId);
+ onUserStarting(userId);
+ } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
+ Log.i(TAG, "User stopping: u" + userId);
+ onUserStopping(userId);
}
}
};
@@ -390,7 +355,8 @@ public class SyncManager implements OnAccountsUpdateListener {
mSyncHandler = new SyncHandler(syncThread.getLooper());
mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
- public void onServiceChanged(SyncAdapterType type, boolean removed) {
+ @Override
+ public void onServiceChanged(SyncAdapterType type, int userId, boolean removed) {
if (!removed) {
scheduleSync(null, UserHandle.USER_ALL, type.authority, null, 0 /* no delay */,
false /* onlyThoseWithUnkownSyncableState */);
@@ -422,7 +388,8 @@ public class SyncManager implements OnAccountsUpdateListener {
intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
- intentFilter.addAction(Intent.ACTION_USER_STARTED);
+ intentFilter.addAction(Intent.ACTION_USER_STARTING);
+ intentFilter.addAction(Intent.ACTION_USER_STOPPING);
mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
@@ -467,8 +434,9 @@ public class SyncManager implements OnAccountsUpdateListener {
UserHandle.ALL,
new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
null, null);
+
// do this synchronously to ensure we have the accounts before this call returns
- onAccountsUpdated(null);
+ onUserStarting(UserHandle.USER_OWNER);
}
// Pick a random second in a day to seed all periodic syncs
@@ -548,7 +516,7 @@ public class SyncManager implements OnAccountsUpdateListener {
} else {
// if the accounts aren't configured yet then we can't support an account-less
// sync request
- accounts = mAccounts;
+ accounts = mRunningAccounts;
if (accounts.length == 0) {
if (isLoggable) {
Log.v(TAG, "scheduleSync: no accounts configured, dropping");
@@ -579,32 +547,33 @@ public class SyncManager implements OnAccountsUpdateListener {
source = SyncStorageEngine.SOURCE_SERVER;
}
- // 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()) {
- syncableAuthorities.add(syncAdapter.type.authority);
- }
+ 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 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);
- }
+ // 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);
+ }
- for (String authority : syncableAuthorities) {
- for (AccountAndUser account : accounts) {
+ for (String authority : syncableAuthorities) {
int isSyncable = mSyncStorageEngine.getIsSyncable(account.account, account.userId,
authority);
if (isSyncable == 0) {
continue;
}
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
- mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(authority, account.account.type));
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(authority, account.account.type), account.userId);
if (syncAdapterInfo == null) {
continue;
}
@@ -681,10 +650,9 @@ public class SyncManager implements OnAccountsUpdateListener {
false /* onlyThoseWithUnkownSyncableState */);
}
- public SyncAdapterType[] getSyncAdapterTypes() {
- final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>
- serviceInfos =
- mSyncAdapters.getAllServices();
+ public SyncAdapterType[] getSyncAdapterTypes(int userId) {
+ final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
+ serviceInfos = mSyncAdapters.getAllServices(userId);
SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
int i = 0;
for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
@@ -920,16 +888,39 @@ public class SyncManager implements OnAccountsUpdateListener {
}
}
- private void onUserRemoved(Intent intent) {
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId == -1) return;
- removeUser(userId);
+ private void onUserStarting(int userId) {
+ mSyncAdapters.invalidateCache(userId);
+
+ updateRunningAccounts();
+
+ final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId);
+ mSyncStorageEngine.doDatabaseCleanup(accounts, userId);
+
+ mSyncQueue.addPendingOperations(userId);
+
+ // Schedule sync for any accounts under started user
+ for (Account account : accounts) {
+ scheduleSync(account, userId, null, null, 0 /* no delay */,
+ true /* onlyThoseWithUnknownSyncableState */);
+ }
+
+ sendCheckAlarmsMessage();
+ }
+
+ private void onUserStopping(int userId) {
+ updateRunningAccounts();
+
+ cancelActiveSync(
+ null /* any account */,
+ userId,
+ null /* any authority */);
}
- private void removeUser(int userId) {
+ private void onUserRemoved(int userId) {
+ updateRunningAccounts();
+
// Clean up the storage engine database
mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId);
- onAccountsUpdated(null);
synchronized (mSyncQueue) {
mSyncQueue.removeUser(userId);
}
@@ -1062,14 +1053,10 @@ public class SyncManager implements OnAccountsUpdateListener {
}
protected void dump(FileDescriptor fd, PrintWriter pw) {
- dumpSyncState(pw);
- dumpSyncHistory(pw);
-
- pw.println();
- pw.println("SyncAdapters:");
- for (RegisteredServicesCache.ServiceInfo info : mSyncAdapters.getAllServices()) {
- pw.println(" " + info);
- }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ dumpSyncState(ipw);
+ dumpSyncHistory(ipw);
+ dumpSyncAdapters(ipw);
}
static String formatTime(long time) {
@@ -1085,15 +1072,15 @@ public class SyncManager implements OnAccountsUpdateListener {
if (users != null) {
for (UserInfo user : users) {
pw.print("u" + user.id + "="
- + mSyncStorageEngine.getMasterSyncAutomatically(user.id));
+ + mSyncStorageEngine.getMasterSyncAutomatically(user.id) + " ");
}
pw.println();
}
pw.print("memory low: "); pw.println(mStorageIsLow);
- final AccountAndUser[] accounts = mAccounts;
+ final AccountAndUser[] accounts = mRunningAccounts;
- pw.print("accounts: ");
+ pw.print("running accounts: ");
if (accounts != INITIAL_ACCOUNTS_ARRAY) {
pw.println(accounts.length);
} else {
@@ -1153,7 +1140,7 @@ public class SyncManager implements OnAccountsUpdateListener {
pw.print(" "); pw.print(account.account.type);
pw.println(":");
for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterType :
- mSyncAdapters.getAllServices()) {
+ mSyncAdapters.getAllServices(account.userId)) {
if (!syncAdapterType.type.accountType.equals(account.account.type)) {
continue;
}
@@ -1530,6 +1517,23 @@ public class SyncManager implements OnAccountsUpdateListener {
}
}
+ private void dumpSyncAdapters(IndentingPrintWriter pw) {
+ pw.println();
+ final List<UserInfo> users = getAllUsers();
+ if (users != null) {
+ for (UserInfo user : users) {
+ pw.println("Sync adapters for " + user + ":");
+ pw.increaseIndent();
+ for (RegisteredServicesCache.ServiceInfo<?> info :
+ mSyncAdapters.getAllServices(user.id)) {
+ pw.println(info);
+ }
+ pw.decreaseIndent();
+ pw.println();
+ }
+ }
+ }
+
private static class AuthoritySyncStats {
String name;
long elapsedTime;
@@ -1613,18 +1617,10 @@ public class SyncManager implements OnAccountsUpdateListener {
Maps.newHashMap();
private volatile CountDownLatch mReadyToRunLatch = new CountDownLatch(1);
+
public void onBootCompleted() {
mBootCompleted = true;
- // TODO: Handle bootcompleted event for specific user. Now let's just iterate through
- // all the users.
- List<UserInfo> users = getAllUsers();
- if (users != null) {
- for (UserInfo user : users) {
- mSyncStorageEngine.doDatabaseCleanup(
- AccountManagerService.getSingleton().getAccounts(user.id),
- user.id);
- }
- }
+
if (mReadyToRunLatch != null) {
mReadyToRunLatch.countDown();
}
@@ -1814,7 +1810,7 @@ public class SyncManager implements OnAccountsUpdateListener {
return earliestFuturePollTime;
}
- AccountAndUser[] accounts = mAccounts;
+ AccountAndUser[] accounts = mRunningAccounts;
final long nowAbsolute = System.currentTimeMillis();
final long shiftedNowAbsolute = (0 < nowAbsolute - mSyncRandomOffsetMillis)
@@ -1869,9 +1865,10 @@ public class SyncManager implements OnAccountsUpdateListener {
// Sync now
final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
info.account, info.userId, info.authority);
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
- mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(info.authority, info.account.type));
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(info.authority, info.account.type),
+ info.userId);
if (syncAdapterInfo == null) {
continue;
}
@@ -1927,7 +1924,7 @@ public class SyncManager implements OnAccountsUpdateListener {
// 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 = mAccounts;
+ AccountAndUser[] accounts = mRunningAccounts;
if (accounts == INITIAL_ACCOUNTS_ARRAY) {
if (isLoggable) {
Log.v(TAG, "maybeStartNextSync: accounts not known, skipping");
@@ -1998,7 +1995,7 @@ public class SyncManager implements OnAccountsUpdateListener {
final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
syncAdapterInfo = mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(op.authority, op.account.type));
+ SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
// only proceed if network is connected for requesting UID
final boolean uidNetworkConnected;
@@ -2030,7 +2027,7 @@ public class SyncManager implements OnAccountsUpdateListener {
for (Integer user : removedUsers) {
// if it's still removed
if (mUserManager.getUserInfo(user) == null) {
- removeUser(user);
+ onUserRemoved(user);
}
}
}
@@ -2167,8 +2164,8 @@ public class SyncManager implements OnAccountsUpdateListener {
// connect to the sync adapter
SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type);
- RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
- mSyncAdapters.getServiceInfo(syncAdapterType);
+ 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");