Fix a race condition in SyncManager.onAccountsUpdated()

Get the full list of accounts from AccountManagerService in one shot
instead of getting them per user.

Bug: 6263091

Change-Id: I488f24749a96281ef1e2a620820399c97f471024
This commit is contained in:
Amith Yamasani
2012-04-05 18:29:52 -07:00
parent d3ce6f50c1
commit f29f2369cf
4 changed files with 81 additions and 41 deletions

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.accounts;
/**
* Used to store the Account and the UserId this account is associated with.
*
* @hide
*/
public class AccountAndUser {
public Account account;
public int userId;
public AccountAndUser(Account account, int userId) {
this.account = account;
this.userId = userId;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof AccountAndUser)) return false;
final AccountAndUser other = (AccountAndUser) o;
return this.account.equals(other.account)
&& this.userId == other.userId;
}
@Override
public int hashCode() {
return account.hashCode() + userId;
}
public String toString() {
return account.toString() + " u" + userId;
}
}

View File

@@ -1488,6 +1488,31 @@ public class AccountManagerService
}
}
/**
* Returns all the accounts qualified by user.
* @hide
*/
public AccountAndUser[] getAllAccounts() {
ArrayList<AccountAndUser> allAccounts = new ArrayList<AccountAndUser>();
List<UserInfo> users = getAllUsers();
if (users == null) return new AccountAndUser[0];
synchronized(mUsers) {
for (UserInfo user : users) {
UserAccounts userAccounts = getUserAccounts(user.id);
if (userAccounts == null) continue;
synchronized (userAccounts.cacheLock) {
Account[] accounts = getAccountsFromCacheLocked(userAccounts, null);
for (int a = 0; a < accounts.length; a++) {
allAccounts.add(new AccountAndUser(accounts[a], user.id));
}
}
}
}
AccountAndUser[] accountsArray = new AccountAndUser[allAccounts.size()];
return allAccounts.toArray(accountsArray);
}
public Account[] getAccounts(String type) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAccounts: accountType " + type

View File

@@ -22,6 +22,7 @@ import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import android.accounts.Account;
import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
import android.accounts.AccountManagerService;
import android.accounts.OnAccountsUpdateListener;
@@ -237,22 +238,14 @@ public class SyncManager implements OnAccountsUpdateListener {
int count = 0;
// For all known users on the system, get their accounts and add them to the list
// 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) {
accounts = AccountManagerService.getSingleton().getAccounts(user.id);
count += accounts.length;
}
AccountAndUser[] allAccounts = new AccountAndUser[count];
int index = 0;
for (UserInfo user : users) {
accounts = AccountManagerService.getSingleton().getAccounts(user.id);
for (Account account : accounts) {
allAccounts[index++] = new AccountAndUser(account, user.id);
}
if (mBootCompleted) {
mSyncStorageEngine.doDatabaseCleanup(accounts, user.id);
Account[] accountsForUser =
AccountManagerService.getSingleton().getAccounts(user.id);
mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
}
}
@@ -338,33 +331,6 @@ public class SyncManager implements OnAccountsUpdateListener {
private volatile boolean mBootCompleted = false;
static class AccountAndUser {
Account account;
int userId;
AccountAndUser(Account account, int userId) {
this.account = account;
this.userId = userId;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof AccountAndUser)) return false;
final AccountAndUser other = (AccountAndUser) o;
return this.account.equals(other.account)
&& this.userId == other.userId;
}
@Override
public int hashCode() {
return account.hashCode() + userId;
}
public String toString() {
return account.toString() + " u" + userId;
}
}
private ConnectivityManager getConnectivityManager() {
synchronized (this) {
if (mConnManagerDoNotUseDirectly == null) {

View File

@@ -25,7 +25,7 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.accounts.Account;
import android.content.SyncManager.AccountAndUser;
import android.accounts.AccountAndUser;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;