diff options
Diffstat (limited to 'core/java/android/content/SyncManager.java')
-rw-r--r-- | core/java/android/content/SyncManager.java | 243 |
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"); |