summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java78
1 files changed, 66 insertions, 12 deletions
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 810270dc71ea..9bc6bffddaf3 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -87,6 +87,7 @@ import android.util.SparseBooleanArray;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.google.android.collect.Lists;
@@ -553,7 +554,7 @@ public class AccountManagerService
CeDatabaseHelper.create(mContext, userId);
accounts.openHelper.attachCeDatabase();
}
- // TODO Synchronize accounts by removing CE account not available in DE
+ syncDeCeAccountsLocked(accounts);
}
if (validateAccounts) {
validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
@@ -562,6 +563,21 @@ public class AccountManagerService
}
}
+ private void syncDeCeAccountsLocked(UserAccounts accounts) {
+ Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
+ final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
+ List<Account> accountsToRemove = CeDatabaseHelper.findCeAccountsNotInDe(db);
+ if (!accountsToRemove.isEmpty()) {
+ Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
+ + accounts.userId + " was locked. Removing accounts from CE tables");
+ logRecord(accounts, DebugDbHelper.ACTION_SYNC_DE_CE_ACCOUNTS, TABLE_ACCOUNTS);
+
+ for (Account account : accountsToRemove) {
+ removeAccountInternal(accounts, account, Process.myUid());
+ }
+ }
+ }
+
private void purgeOldGrantsAll() {
synchronized (mUsers) {
for (int i = 0; i < mUsers.size(); i++) {
@@ -799,7 +815,7 @@ public class AccountManagerService
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAuthenticatorTypes: "
+ "for user id " + userId
- + "caller's uid " + callingUid
+ + " caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
// Only allow the system process to read accounts of other users
@@ -1543,21 +1559,35 @@ public class AccountManagerService
}
private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
- // For now user is required to be unlocked. TODO: Handle both cases in the future
int deleted;
+ boolean userUnlocked = isUserUnlocked(accounts.userId);
+ if (!userUnlocked) {
+ Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
+ + " is still locked. CE data will be removed later");
+ }
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
+ final SQLiteDatabase db = userUnlocked
+ ? accounts.openHelper.getWritableDatabaseUserIsUnlocked()
+ : accounts.openHelper.getWritableDatabase();
final long accountId = getAccountIdLocked(db, account);
- deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
- + "=?",
- new String[]{account.name, account.type});
- // Delete from CE table
- db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
- new String[]{account.name, account.type});
+ db.beginTransaction();
+ try {
+ deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
+ + "=?", new String[]{account.name, account.type});
+ if (userUnlocked) {
+ // Delete from CE table
+ deleted = db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
+ + "=?", new String[]{account.name, account.type});
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
removeAccountFromCacheLocked(accounts, account);
sendAccountsChangedBroadcast(accounts.userId);
-
- logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_ACCOUNTS, accountId, accounts);
+ String action = userUnlocked ? DebugDbHelper.ACTION_ACCOUNT_REMOVE
+ : DebugDbHelper.ACTION_ACCOUNT_REMOVE_DE;
+ logRecord(db, action, TABLE_ACCOUNTS, accountId, accounts);
}
long id = Binder.clearCallingIdentity();
try {
@@ -4072,6 +4102,7 @@ public class AccountManagerService
private static String ACTION_CLEAR_PASSWORD = "action_clear_password";
private static String ACTION_ACCOUNT_ADD = "action_account_add";
private static String ACTION_ACCOUNT_REMOVE = "action_account_remove";
+ private static String ACTION_ACCOUNT_REMOVE_DE = "action_account_remove_de";
private static String ACTION_AUTHENTICATOR_REMOVE = "action_authenticator_remove";
private static String ACTION_ACCOUNT_RENAME = "action_account_rename";
@@ -4082,6 +4113,7 @@ public class AccountManagerService
// who called.
private static String ACTION_CALLED_ACCOUNT_ADD = "action_called_account_add";
private static String ACTION_CALLED_ACCOUNT_REMOVE = "action_called_account_remove";
+ private static String ACTION_SYNC_DE_CE_ACCOUNTS = "action_sync_de_ce_accounts";
//This action doesn't add account to accountdb. Account is only
// added in finishSession which may be in a different user profile.
@@ -4580,6 +4612,28 @@ public class AccountManagerService
}
}
+ static List<Account> findCeAccountsNotInDe(SQLiteDatabase db) {
+ // Select accounts from CE that do not exist in DE
+ Cursor cursor = db.rawQuery(
+ "SELECT " + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
+ + " FROM " + CE_TABLE_ACCOUNTS
+ + " WHERE NOT EXISTS "
+ + " (SELECT " + ACCOUNTS_ID + " FROM " + TABLE_ACCOUNTS
+ + " WHERE " + ACCOUNTS_ID + "=" + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+ + " )", null);
+ try {
+ List<Account> accounts = new ArrayList<>(cursor.getCount());
+ while (cursor.moveToNext()) {
+ String accountName = cursor.getString(0);
+ String accountType = cursor.getString(1);
+ accounts.add(new Account(accountName, accountType));
+ }
+ return accounts;
+ } finally {
+ cursor.close();
+ }
+ }
+
/**
* Creates a new {@code CeDatabaseHelper}. If pre-N db file is present at the old location,
* it also performs migration to the new CE database.