summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java97
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java1289
-rw-r--r--services/core/java/com/android/server/accounts/AccountsDb.java1174
3 files changed, 1332 insertions, 1228 deletions
diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
index f4511d28ba46..63afcccc5961 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
@@ -29,11 +29,14 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.PackageUtils;
+import android.util.Pair;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.server.accounts.AccountsDb.DeDatabaseHelper;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -59,14 +62,6 @@ public final class AccountManagerBackupHelper {
private static final String ATTR_PACKAGE = "package";
private static final String ATTR_DIGEST = "digest";
- private static final String ACCOUNT_ACCESS_GRANTS = ""
- + "SELECT " + AccountManagerService.ACCOUNTS_NAME + ", "
- + AccountManagerService.GRANTS_GRANTEE_UID
- + " FROM " + AccountManagerService.TABLE_ACCOUNTS
- + ", " + AccountManagerService.TABLE_GRANTS
- + " WHERE " + AccountManagerService.GRANTS_ACCOUNTS_ID
- + "=" + AccountManagerService.ACCOUNTS_ID;
-
private final Object mLock = new Object();
private final AccountManagerService mAccountManagerService;
@@ -148,60 +143,48 @@ public final class AccountManagerBackupHelper {
.getUserAccounts(userId);
synchronized (accounts.cacheLock) {
SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- try (
- Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null);
- ) {
- if (cursor == null || !cursor.moveToFirst()) {
- return null;
- }
-
- final int nameColumnIdx = cursor.getColumnIndex(
- AccountManagerService.ACCOUNTS_NAME);
- final int uidColumnIdx = cursor.getColumnIndex(
- AccountManagerService.GRANTS_GRANTEE_UID);
-
+ List<Pair<String, Integer>> allAccountGrants = DeDatabaseHelper.findAllAccountGrants(
+ db);
+ if (allAccountGrants.isEmpty()) {
+ return null;
+ }
+ try {
ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
- try {
- final XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
- serializer.startDocument(null, true);
- serializer.startTag(null, TAG_PERMISSIONS);
-
- PackageManager packageManager = mAccountManagerService.mContext
- .getPackageManager();
-
- do {
- final String accountName = cursor.getString(nameColumnIdx);
- final int uid = cursor.getInt(uidColumnIdx);
-
- final String[] packageNames = packageManager.getPackagesForUid(uid);
- if (packageNames == null) {
- continue;
- }
+ final XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TAG_PERMISSIONS);
+
+ PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
+ for (Pair<String, Integer> grant : allAccountGrants) {
+ final String accountName = grant.first;
+ final int uid = grant.second;
+
+ final String[] packageNames = packageManager.getPackagesForUid(uid);
+ if (packageNames == null) {
+ continue;
+ }
- for (String packageName : packageNames) {
- String digest = PackageUtils.computePackageCertSha256Digest(
- packageManager, packageName, userId);
- if (digest != null) {
- serializer.startTag(null, TAG_PERMISSION);
- serializer.attribute(null, ATTR_ACCOUNT_SHA_256,
- PackageUtils.computeSha256Digest(accountName.getBytes()));
- serializer.attribute(null, ATTR_PACKAGE, packageName);
- serializer.attribute(null, ATTR_DIGEST, digest);
- serializer.endTag(null, TAG_PERMISSION);
- }
+ for (String packageName : packageNames) {
+ String digest = PackageUtils.computePackageCertSha256Digest(
+ packageManager, packageName, userId);
+ if (digest != null) {
+ serializer.startTag(null, TAG_PERMISSION);
+ serializer.attribute(null, ATTR_ACCOUNT_SHA_256,
+ PackageUtils.computeSha256Digest(accountName.getBytes()));
+ serializer.attribute(null, ATTR_PACKAGE, packageName);
+ serializer.attribute(null, ATTR_DIGEST, digest);
+ serializer.endTag(null, TAG_PERMISSION);
}
- } while (cursor.moveToNext());
-
- serializer.endTag(null, TAG_PERMISSIONS);
- serializer.endDocument();
- serializer.flush();
- } catch (IOException e) {
- Log.e(TAG, "Error backing up account access grants", e);
- return null;
+ }
}
-
+ serializer.endTag(null, TAG_PERMISSIONS);
+ serializer.endDocument();
+ serializer.flush();
return dataStream.toByteArray();
+ } catch (IOException e) {
+ Log.e(TAG, "Error backing up account access grants", e);
+ return null;
}
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 04c15c8983cc..35ddc9b77bda 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -48,7 +48,6 @@ import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -66,14 +65,11 @@ import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
-import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -105,13 +101,15 @@ import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.accounts.AccountsDb.CeDatabaseHelper;
+import com.android.server.accounts.AccountsDb.DeDatabaseHelper;
+import com.android.server.accounts.AccountsDb.DebugDbHelper;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
@@ -164,11 +162,6 @@ public class AccountManagerService
}
}
- private static final String DATABASE_NAME = "accounts.db";
- private static final int PRE_N_DATABASE_VERSION = 9;
- private static final int CE_DATABASE_VERSION = 10;
- private static final int DE_DATABASE_VERSION = 1;
-
private static final int MAX_DEBUG_DB_SIZE = 64;
final Context mContext;
@@ -184,51 +177,7 @@ public class AccountManagerService
private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
private final IAccountAuthenticatorCache mAuthenticatorCache;
-
- static final String TABLE_ACCOUNTS = "accounts";
- static final String ACCOUNTS_ID = "_id";
- static final String ACCOUNTS_NAME = "name";
- private static final String ACCOUNTS_TYPE = "type";
- private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
- private static final String ACCOUNTS_PASSWORD = "password";
- private static final String ACCOUNTS_PREVIOUS_NAME = "previous_name";
- private static final String ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS =
- "last_password_entry_time_millis_epoch";
-
- private static final String TABLE_AUTHTOKENS = "authtokens";
- private static final String AUTHTOKENS_ID = "_id";
- private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
- private static final String AUTHTOKENS_TYPE = "type";
- private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
-
- static final String TABLE_GRANTS = "grants";
- static final String GRANTS_ACCOUNTS_ID = "accounts_id";
- private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
- static final String GRANTS_GRANTEE_UID = "uid";
-
- private static final String TABLE_EXTRAS = "extras";
- private static final String EXTRAS_ID = "_id";
- private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
- private static final String EXTRAS_KEY = "key";
- private static final String EXTRAS_VALUE = "value";
-
- private static final String TABLE_META = "meta";
- private static final String META_KEY = "key";
- private static final String META_VALUE = "value";
-
- private static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
- private static final String SHARED_ACCOUNTS_ID = "_id";
-
private static final String PRE_N_DATABASE_NAME = "accounts.db";
- private static final String CE_DATABASE_NAME = "accounts_ce.db";
- private static final String DE_DATABASE_NAME = "accounts_de.db";
- private static final String CE_DB_PREFIX = "ceDb.";
- private static final String CE_TABLE_ACCOUNTS = CE_DB_PREFIX + TABLE_ACCOUNTS;
- private static final String CE_TABLE_AUTHTOKENS = CE_DB_PREFIX + TABLE_AUTHTOKENS;
- private static final String CE_TABLE_EXTRAS = CE_DB_PREFIX + TABLE_EXTRAS;
-
- private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
- new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
private static final Intent ACCOUNTS_CHANGED_INTENT;
static {
@@ -236,35 +185,6 @@ public class AccountManagerService
ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
}
- private static final String COUNT_OF_MATCHING_GRANTS = ""
- + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
- + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
- + " AND " + GRANTS_GRANTEE_UID + "=?"
- + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
- + " AND " + ACCOUNTS_NAME + "=?"
- + " AND " + ACCOUNTS_TYPE + "=?";
-
- private static final String COUNT_OF_MATCHING_GRANTS_ANY_TOKEN = ""
- + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
- + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
- + " AND " + GRANTS_GRANTEE_UID + "=?"
- + " AND " + ACCOUNTS_NAME + "=?"
- + " AND " + ACCOUNTS_TYPE + "=?";
-
- private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
- AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
-
- private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
- AUTHTOKENS_AUTHTOKEN};
-
- private static final String SELECTION_USERDATA_BY_ACCOUNT =
- EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
- private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
-
- private static final String META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX =
- "auth_uid_for_type:";
- private static final String META_KEY_DELIMITER = ":";
- private static final String SELECTION_META_BY_AUTHENTICATOR_TYPE = META_KEY + " LIKE ?";
private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
private final AtomicInteger mNotificationIds = new AtomicInteger(1);
@@ -334,6 +254,8 @@ public class AccountManagerService
private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
+ // Not thread-safe. Only use in synchronized context
+ private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
@@ -1098,7 +1020,7 @@ public class AccountManagerService
boolean accountDeleted = false;
// Get a map of stored authenticator types to UID
- Map<String, Integer> metaAuthUid = AccountsDbUtils.findMetaAuthUid(db);
+ Map<String, Integer> metaAuthUid = DeDatabaseHelper.findMetaAuthUid(db);
// Create a list of authenticator type whose previous uid no longer exists
HashSet<String> obsoleteAuthType = Sets.newHashSet();
SparseBooleanArray knownUids = null;
@@ -1135,7 +1057,7 @@ public class AccountManagerService
// So purge its data from the account databases.
obsoleteAuthType.add(type);
// And delete it from the TABLE_META
- AccountsDbUtils.deleteMetaByAuthTypeAndUid(db, type, uid);
+ DeDatabaseHelper.deleteMetaByAuthTypeAndUid(db, type, uid);
}
}
}
@@ -1144,11 +1066,11 @@ public class AccountManagerService
// been re-enabled (after being updated for example), then we just overwrite the old
// values.
for (Entry<String, Integer> entry : knownAuth.entrySet()) {
- AccountsDbUtils.insertOrReplaceMetaAuthTypeAndUid(db, entry.getKey(),
+ DeDatabaseHelper.insertOrReplaceMetaAuthTypeAndUid(db, entry.getKey(),
entry.getValue());
}
- final Map<Long, Account> accountsMap = AccountsDbUtils.findAllAccounts(db);
+ final Map<Long, Account> accountsMap = DeDatabaseHelper.findAllAccounts(db);
try {
accounts.accountCache.clear();
final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
@@ -1160,11 +1082,11 @@ public class AccountManagerService
+ account.type + "'s registered authenticator no longer exist.");
db.beginTransaction();
try {
- AccountsDbUtils.deleteAccount(db, accountId);
+ DeDatabaseHelper.deleteAccount(db, accountId);
// Also delete from CE table if user is unlocked; if user is currently
// locked the account will be removed later by syncDeCeAccountsLocked
if (userUnlocked) {
- AccountsDbUtils.deleteCeAccount(db, accountId);
+ AccountsDb.deleteCeAccount(db, accountId);
}
db.setTransactionSuccessful();
} finally {
@@ -1172,8 +1094,8 @@ public class AccountManagerService
}
accountDeleted = true;
- logRecord(db, DebugDbHelper.ACTION_AUTHENTICATOR_REMOVE, TABLE_ACCOUNTS,
- accountId, accounts);
+ logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
+ AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
accounts.userDataCache.remove(account);
accounts.authTokenCache.remove(account);
@@ -1221,7 +1143,7 @@ public class AccountManagerService
return knownUids;
}
- private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
+ static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Context context,
int userId) {
AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
@@ -1278,11 +1200,12 @@ 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 = AccountsDbUtils.findCeAccountsNotInDe(db);
+ List<Account> accountsToRemove = AccountsDb.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);
+ logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
+ AccountsDb.TABLE_ACCOUNTS);
for (Account account : accountsToRemove) {
removeAccountInternal(accounts, account, Process.myUid());
@@ -1301,7 +1224,7 @@ public class AccountManagerService
private void purgeOldGrants(UserAccounts accounts) {
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- List<Integer> uids = AccountsDbUtils.findAllUidGrants(db);
+ List<Integer> uids = DeDatabaseHelper.findAllUidGrants(db);
for (int uid : uids) {
final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
if (packageExists) {
@@ -1309,7 +1232,7 @@ public class AccountManagerService
}
Log.d(TAG, "deleting grants for UID " + uid
+ " because its package is no longer installed");
- AccountsDbUtils.deleteGrantsByUid(db, uid);
+ DeDatabaseHelper.deleteGrantsByUid(db, uid);
}
}
}
@@ -1334,23 +1257,17 @@ public class AccountManagerService
Log.i(TAG, "Removing database files for user " + userId);
File dbFile = new File(getDeDatabaseName(userId));
- deleteDbFileWarnIfFailed(dbFile);
+ AccountsDb.deleteDbFileWarnIfFailed(dbFile);
// Remove CE file if user is unlocked, or FBE is not enabled
boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
if (!fbeEnabled || userUnlocked) {
File ceDb = new File(getCeDatabaseName(userId));
if (ceDb.exists()) {
- deleteDbFileWarnIfFailed(ceDb);
+ AccountsDb.deleteDbFileWarnIfFailed(ceDb);
}
}
}
- private static void deleteDbFileWarnIfFailed(File dbFile) {
- if (!SQLiteDatabase.deleteDatabase(dbFile)) {
- Log.w(TAG, "Database at " + dbFile + " was not deleted successfully");
- }
- }
-
@VisibleForTesting
void onUserUnlocked(Intent intent) {
onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
@@ -1428,7 +1345,7 @@ public class AccountManagerService
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
- return AccountsDbUtils.findAccountPasswordByNameAndType(db, account.name,
+ return CeDatabaseHelper.findAccountPasswordByNameAndType(db, account.name,
account.type);
}
}
@@ -1459,7 +1376,7 @@ public class AccountManagerService
AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
if (previousNameRef == null) {
final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- String previousName = AccountsDbUtils.findAccountPreviousName(db, account);
+ String previousName = DeDatabaseHelper.findAccountPreviousName(db, account);
previousNameRef = new AtomicReference<>(previousName);
accounts.previousNameCache.put(account, previousNameRef);
return previousName;
@@ -1695,21 +1612,9 @@ public class AccountManagerService
private boolean updateLastAuthenticatedTime(Account account) {
final UserAccounts accounts = getUserAccountsForCaller();
synchronized (accounts.cacheLock) {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- int i = db.update(
- TABLE_ACCOUNTS,
- values,
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
- new String[] {
- account.name, account.type
- });
- if (i > 0) {
- return true;
- }
+ return DeDatabaseHelper.updateAccountLastAuthenticatedTime(
+ accounts.openHelper.getWritableDatabase(), account);
}
- return false;
}
private void completeCloningAccount(IAccountManagerResponse response,
@@ -1780,33 +1685,19 @@ public class AccountManagerService
final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
- long numMatches = DatabaseUtils.longForQuery(db,
- "select count(*) from " + CE_TABLE_ACCOUNTS
- + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.name, account.type});
- if (numMatches > 0) {
+ if (CeDatabaseHelper.findAccountId(db, account) >= 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping since the account already exists");
return false;
}
- ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, account.name);
- values.put(ACCOUNTS_TYPE, account.type);
- values.put(ACCOUNTS_PASSWORD, password);
- long accountId = db.insert(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ long accountId = CeDatabaseHelper.insertAccount(db, account, password);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping the DB insert failed");
return false;
}
// Insert into DE table
- values = new ContentValues();
- values.put(ACCOUNTS_ID, accountId);
- values.put(ACCOUNTS_NAME, account.name);
- values.put(ACCOUNTS_TYPE, account.type);
- values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS,
- System.currentTimeMillis());
- if (db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values) < 0) {
+ if (DeDatabaseHelper.insertAccount(db, account, accountId) < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping the DB insert failed");
return false;
@@ -1814,7 +1705,7 @@ public class AccountManagerService
if (extras != null) {
for (String key : extras.keySet()) {
final String value = extras.getString(key);
- if (AccountsDbUtils.insertExtra(db, accountId, key, value) < 0) {
+ if (CeDatabaseHelper.insertExtra(db, accountId, key, value) < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping since insertExtra failed for key " + key);
return false;
@@ -1823,8 +1714,8 @@ public class AccountManagerService
}
db.setTransactionSuccessful();
- logRecord(db, DebugDbHelper.ACTION_ACCOUNT_ADD, TABLE_ACCOUNTS, accountId,
- accounts, callingUid);
+ logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
+ accountId, accounts, callingUid);
insertAccountIntoCacheLocked(accounts, account);
} finally {
@@ -1872,7 +1763,7 @@ public class AccountManagerService
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "hasFeatures: " + account
+ ", response " + response
- + ", features " + stringArrayToString(features)
+ + ", features " + Arrays.toString(features)
+ ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
@@ -2015,18 +1906,10 @@ public class AccountManagerService
db.beginTransaction();
Account renamedAccount = new Account(newName, accountToRename.type);
try {
- final long accountId = AccountsDbUtils.findAccountId(db, accountToRename);
+ final long accountId = DeDatabaseHelper.findAccountId(db, accountToRename);
if (accountId >= 0) {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, newName);
- final String[] argsAccountId = { String.valueOf(accountId) };
- db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
- // Update NAME/PREVIOUS_NAME in DE accounts table
- values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
- db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
- db.setTransactionSuccessful();
- logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_ACCOUNTS, accountId,
- accounts);
+ CeDatabaseHelper.renameAccount(db, accountId, newName);
+ DeDatabaseHelper.renameAccount(db, accountId, newName, accountToRename.name);
}
} finally {
db.endTransaction();
@@ -2034,10 +1917,8 @@ public class AccountManagerService
/*
* Database transaction was successful. Clean up cached
* data associated with the account in the user profile.
- * The account is now being tracked for remote access.
*/
- renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
-
+ insertAccountIntoCacheLocked(accounts, renamedAccount);
/*
* Extract the data and token caches before removing the
* old account to preserve the user data associated with
@@ -2155,11 +2036,10 @@ public class AccountManagerService
}
}
SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- final long accountId = AccountsDbUtils.findAccountId(db, account);
+ final long accountId = DeDatabaseHelper.findAccountId(db, account);
logRecord(
- db,
- DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE,
- TABLE_ACCOUNTS,
+ AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
+ AccountsDb.TABLE_ACCOUNTS,
accountId,
accounts,
callingUid);
@@ -2196,11 +2076,10 @@ public class AccountManagerService
removeVisibleListFunctionality(account, getUserAccounts(UserHandle.getUserId(callingUid)));
UserAccounts accounts = getUserAccountsForCaller();
SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- final long accountId = AccountsDbUtils.findAccountId(db, account);
+ final long accountId = DeDatabaseHelper.findAccountId(db, account);
logRecord(
- db,
- DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE,
- TABLE_ACCOUNTS,
+ AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
+ AccountsDb.TABLE_ACCOUNTS,
accountId,
accounts,
callingUid);
@@ -2282,12 +2161,12 @@ public class AccountManagerService
// transaction succeeds.
long accountId = -1;
try {
- accountId = AccountsDbUtils.findAccountId(db, account);
+ accountId = DeDatabaseHelper.findAccountId(db, account);
if (accountId >= 0) {
- AccountsDbUtils.deleteAccount(db, accountId);
+ DeDatabaseHelper.deleteAccount(db, accountId);
if (userUnlocked) {
// Delete from CE table
- AccountsDbUtils.deleteCeAccount(db, accountId);
+ AccountsDb.deleteCeAccount(db, accountId);
}
db.setTransactionSuccessful();
isChanged = true;
@@ -2299,9 +2178,9 @@ public class AccountManagerService
removeAccountFromCacheLocked(accounts, account);
// Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
sendAccountsChangedBroadcast(accounts.userId);
- String action = userUnlocked ? DebugDbHelper.ACTION_ACCOUNT_REMOVE
- : DebugDbHelper.ACTION_ACCOUNT_REMOVE_DE;
- logRecord(db, action, TABLE_ACCOUNTS, accountId, accounts);
+ String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
+ : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
+ logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
}
}
long id = Binder.clearCallingIdentity();
@@ -2383,13 +2262,13 @@ public class AccountManagerService
if (authToken == null || accountType == null) {
return;
}
- Cursor cursor = AccountsDbUtils.findAuthtokenForAllAccounts(db, accountType, authToken);
+ Cursor cursor = CeDatabaseHelper.findAuthtokenForAllAccounts(db, accountType, authToken);
try {
while (cursor.moveToNext()) {
String authTokenId = cursor.getString(0);
String accountName = cursor.getString(1);
String authTokenType = cursor.getString(2);
- AccountsDbUtils.deleteAuthToken(db, authTokenId);
+ CeDatabaseHelper.deleteAuthToken(db, authTokenId);
writeAuthTokenIntoCacheLocked(
accounts,
db,
@@ -2433,12 +2312,12 @@ public class AccountManagerService
final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
- long accountId = AccountsDbUtils.findAccountId(db, account);
+ long accountId = DeDatabaseHelper.findAccountId(db, account);
if (accountId < 0) {
return false;
}
- AccountsDbUtils.deleteAuthtokensByAccountIdAndType(db, accountId, type);
- if (AccountsDbUtils.insertAuthToken(db, accountId, type, authToken) >= 0) {
+ CeDatabaseHelper.deleteAuthtokensByAccountIdAndType(db, accountId, type);
+ if (CeDatabaseHelper.insertAuthToken(db, accountId, type, authToken) >= 0) {
db.setTransactionSuccessful();
writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
return true;
@@ -2547,10 +2426,10 @@ public class AccountManagerService
final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
- final long accountId = AccountsDbUtils.findAccountId(db, account);
+ final long accountId = DeDatabaseHelper.findAccountId(db, account);
if (accountId >= 0) {
- AccountsDbUtils.updateAccountPassword(db, accountId, password);
- AccountsDbUtils.deleteAuthTokensByAccountId(db, accountId);
+ CeDatabaseHelper.updateAccountPassword(db, accountId, password);
+ CeDatabaseHelper.deleteAuthTokensByAccountId(db, accountId);
accounts.authTokenCache.remove(account);
accounts.accountTokenCaches.remove(account);
db.setTransactionSuccessful();
@@ -2559,9 +2438,9 @@ public class AccountManagerService
// new password is the same as the old and there were no authtokens to delete.
isChanged = true;
String action = (password == null || password.length() == 0) ?
- DebugDbHelper.ACTION_CLEAR_PASSWORD
- : DebugDbHelper.ACTION_SET_PASSWORD;
- logRecord(db, action, TABLE_ACCOUNTS, accountId, accounts, callingUid);
+ AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
+ : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
+ logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, callingUid);
}
} finally {
db.endTransaction();
@@ -2657,17 +2536,17 @@ public class AccountManagerService
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
db.beginTransaction();
try {
- long accountId = AccountsDbUtils.findAccountId(db, account);
+ long accountId = DeDatabaseHelper.findAccountId(db, account);
if (accountId < 0) {
return;
}
- long extrasId = AccountsDbUtils.findExtrasIdByAccountId(db, accountId, key);
+ long extrasId = CeDatabaseHelper.findExtrasIdByAccountId(db, accountId, key);
if (extrasId < 0) {
- extrasId = AccountsDbUtils.insertExtra(db, accountId, key, value);
+ extrasId = CeDatabaseHelper.insertExtra(db, accountId, key, value);
if (extrasId < 0) {
return;
}
- } else if (!AccountsDbUtils.updateExtra(db, extrasId, value)) {
+ } else if (!CeDatabaseHelper.updateExtra(db, extrasId, value)) {
return;
}
writeUserDataIntoCacheLocked(accounts, db, account, key, value);
@@ -3082,7 +2961,7 @@ public class AccountManagerService
Log.v(TAG, "addAccount: accountType " + accountType
+ ", response " + response
+ ", authTokenType " + authTokenType
- + ", requiredFeatures " + stringArrayToString(requiredFeatures)
+ + ", requiredFeatures " + Arrays.toString(requiredFeatures)
+ ", expectActivityLaunch " + expectActivityLaunch
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
@@ -3123,7 +3002,8 @@ public class AccountManagerService
try {
UserAccounts accounts = getUserAccounts(usrId);
logRecordWithUid(
- accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS, uid);
+ accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
+ uid);
new Session(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
@@ -3137,10 +3017,7 @@ public class AccountManagerService
protected String toDebugString(long now) {
return super.toDebugString(now) + ", addAccount"
+ ", accountType " + accountType
- + ", requiredFeatures "
- + (requiredFeatures != null
- ? TextUtils.join(",", requiredFeatures)
- : null);
+ + ", requiredFeatures " + Arrays.toString(requiredFeatures);
}
}.bind();
} finally {
@@ -3158,7 +3035,7 @@ public class AccountManagerService
Log.v(TAG, "addAccount: accountType " + accountType
+ ", response " + response
+ ", authTokenType " + authTokenType
- + ", requiredFeatures " + stringArrayToString(requiredFeatures)
+ + ", requiredFeatures " + Arrays.toString(requiredFeatures)
+ ", expectActivityLaunch " + expectActivityLaunch
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid()
@@ -3206,7 +3083,8 @@ public class AccountManagerService
try {
UserAccounts accounts = getUserAccounts(userId);
logRecordWithUid(
- accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS, userId);
+ accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
+ userId);
new Session(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
@@ -3245,7 +3123,7 @@ public class AccountManagerService
"startAddAccountSession: accountType " + accountType
+ ", response " + response
+ ", authTokenType " + authTokenType
- + ", requiredFeatures " + stringArrayToString(requiredFeatures)
+ + ", requiredFeatures " + Arrays.toString(requiredFeatures)
+ ", expectActivityLaunch " + expectActivityLaunch
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
@@ -3291,8 +3169,8 @@ public class AccountManagerService
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- logRecordWithUid(accounts, DebugDbHelper.ACTION_CALLED_START_ACCOUNT_ADD,
- TABLE_ACCOUNTS, uid);
+ logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
+ AccountsDb.TABLE_ACCOUNTS, uid);
new StartAccountSession(
accounts,
response,
@@ -3533,8 +3411,8 @@ public class AccountManagerService
UserAccounts accounts = getUserAccounts(userId);
logRecordWithUid(
accounts,
- DebugDbHelper.ACTION_CALLED_ACCOUNT_SESSION_FINISH,
- TABLE_ACCOUNTS,
+ AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
+ AccountsDb.TABLE_ACCOUNTS,
callingUid);
new Session(
accounts,
@@ -4304,14 +4182,15 @@ public class AccountManagerService
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- AccountsDbUtils.deleteSharedAccount(db, account);
- long accountId = AccountsDbUtils.insertSharedAccount(db, account);
+ DeDatabaseHelper.deleteSharedAccount(db, account);
+ long accountId = DeDatabaseHelper.insertSharedAccount(db, account);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping the DB insert failed");
return false;
}
- logRecord(db, DebugDbHelper.ACTION_ACCOUNT_ADD, TABLE_SHARED_ACCOUNTS, accountId, accounts);
+ logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
+ accounts);
return true;
}
@@ -4320,11 +4199,11 @@ public class AccountManagerService
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- long sharedTableAccountId = AccountsDbUtils.findSharedAccountId(db, account);
- int r = AccountsDbUtils.renameSharedAccount(db, account, newName);
+ long sharedTableAccountId = DeDatabaseHelper.findSharedAccountId(db, account);
+ int r = DeDatabaseHelper.renameSharedAccount(db, account, newName);
if (r > 0) {
int callingUid = getCallingUid();
- logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_SHARED_ACCOUNTS,
+ logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
sharedTableAccountId, accounts, callingUid);
// Recursively rename the account.
renameAccountInternal(accounts, account, newName);
@@ -4341,10 +4220,10 @@ public class AccountManagerService
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- long sharedTableAccountId = AccountsDbUtils.findSharedAccountId(db, account);
- boolean deleted = AccountsDbUtils.deleteSharedAccount(db, account);
+ long sharedTableAccountId = DeDatabaseHelper.findSharedAccountId(db, account);
+ boolean deleted = DeDatabaseHelper.deleteSharedAccount(db, account);
if (deleted) {
- logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_SHARED_ACCOUNTS,
+ logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
sharedTableAccountId, accounts, callingUid);
removeAccountInternal(accounts, account, callingUid);
}
@@ -4355,7 +4234,7 @@ public class AccountManagerService
public Account[] getSharedAccountsAsUser(int userId) {
userId = handleIncomingUser(userId);
SQLiteDatabase db = getUserAccounts(userId).openHelper.getReadableDatabase();
- List<Account> accountList = AccountsDbUtils.getSharedAccounts(db);
+ List<Account> accountList = DeDatabaseHelper.getSharedAccounts(db);
Account[] accountArray = new Account[accountList.size()];
accountList.toArray(accountArray);
return accountArray;
@@ -4406,7 +4285,7 @@ public class AccountManagerService
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAccounts: accountType " + type
+ ", response " + response
- + ", features " + stringArrayToString(features)
+ + ", features " + Arrays.toString(features)
+ ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
@@ -4682,15 +4561,10 @@ public class AccountManagerService
if (mAuthDetailsRequired) {
long lastAuthenticatedTime = -1;
if (accountPresent) {
- lastAuthenticatedTime = DatabaseUtils.longForQuery(
- mAccounts.openHelper.getReadableDatabase(),
- "SELECT " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
- + " FROM " +
- TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
- + ACCOUNTS_TYPE + "=?",
- new String[] {
- mAccountName, mAccountType
- });
+ lastAuthenticatedTime = DeDatabaseHelper
+ .findAccountLastAuthenticatedTime(
+ mAccounts.openHelper.getReadableDatabase(),
+ new Account(mAccountName, mAccountType));
}
result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
lastAuthenticatedTime);
@@ -4877,92 +4751,37 @@ public class AccountManagerService
@VisibleForTesting
String getDeDatabaseName(int userId) {
File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
- DE_DATABASE_NAME);
+ AccountsDb.DE_DATABASE_NAME);
return databaseFile.getPath();
}
@VisibleForTesting
String getCeDatabaseName(int userId) {
File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
- CE_DATABASE_NAME);
+ AccountsDb.CE_DATABASE_NAME);
return databaseFile.getPath();
}
- private static class DebugDbHelper{
- private DebugDbHelper() {
- }
-
- private static String TABLE_DEBUG = "debug_table";
-
- // Columns for the table
- private static String ACTION_TYPE = "action_type";
- private static String TIMESTAMP = "time";
- private static String CALLER_UID = "caller_uid";
- private static String TABLE_NAME = "table_name";
- private static String KEY = "primary_key";
-
- // These actions correspond to the occurrence of real actions. Since
- // these are called by the authenticators, the uid associated will be
- // of the authenticator.
- private static String ACTION_SET_PASSWORD = "action_set_password";
- 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";
-
- // These actions don't necessarily correspond to any action on
- // accountDb taking place. As an example, there might be a request for
- // addingAccount, which might not lead to addition of account on grounds
- // of bad authentication. We will still be logging it to keep track of
- // 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.
- private static String ACTION_CALLED_START_ACCOUNT_ADD = "action_called_start_account_add";
- private static String ACTION_CALLED_ACCOUNT_SESSION_FINISH =
- "action_called_account_session_finish";
-
- private static SimpleDateFormat dateFromat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
- private static void createDebugTable(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_DEBUG + " ( "
- + ACCOUNTS_ID + " INTEGER,"
- + ACTION_TYPE + " TEXT NOT NULL, "
- + TIMESTAMP + " DATETIME,"
- + CALLER_UID + " INTEGER NOT NULL,"
- + TABLE_NAME + " TEXT NOT NULL,"
- + KEY + " INTEGER PRIMARY KEY)");
- db.execSQL("CREATE INDEX timestamp_index ON " + TABLE_DEBUG + " (" + TIMESTAMP + ")");
- }
- }
-
private void logRecord(UserAccounts accounts, String action, String tableName) {
- SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- logRecord(db, action, tableName, -1, accounts);
+ logRecord(action, tableName, -1, accounts);
}
private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
- SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- logRecord(db, action, tableName, -1, accounts, uid);
+ logRecord(action, tableName, -1, accounts, uid);
}
/*
* This function receives an opened writable database.
*/
- private void logRecord(SQLiteDatabase db, String action, String tableName, long accountId,
+ private void logRecord(String action, String tableName, long accountId,
UserAccounts userAccount) {
- logRecord(db, action, tableName, accountId, userAccount, getCallingUid());
+ logRecord(action, tableName, accountId, userAccount, getCallingUid());
}
/*
* This function receives an opened writable database and writes to it in a separate thread.
*/
- private void logRecord(SQLiteDatabase db, String action, String tableName, long accountId,
+ private void logRecord(String action, String tableName, long accountId,
UserAccounts userAccount, int callingUid) {
class LogRecordTask implements Runnable {
@@ -4991,7 +4810,7 @@ public class AccountManagerService
SQLiteStatement logStatement = userAccount.statementForLogging;
logStatement.bindLong(1, accountId);
logStatement.bindString(2, action);
- logStatement.bindString(3, DebugDbHelper.dateFromat.format(new Date()));
+ logStatement.bindString(3, mDateFormat.format(new Date()));
logStatement.bindLong(4, callingUid);
logStatement.bindString(5, tableName);
logStatement.bindLong(6, userDebugDbInsertionPoint);
@@ -5014,465 +4833,14 @@ public class AccountManagerService
private void initializeDebugDbSizeAndCompileSqlStatementForLogging(SQLiteDatabase db,
UserAccounts userAccount) {
// Initialize the count if not done earlier.
- int size = (int) getDebugTableRowCount(db);
+ int size = DebugDbHelper.getDebugTableRowCount(db);
if (size >= MAX_DEBUG_DB_SIZE) {
// Table is full, and we need to find the point where to insert.
- userAccount.debugDbInsertionPoint = (int) getDebugTableInsertionPoint(db);
+ userAccount.debugDbInsertionPoint = DebugDbHelper.getDebugTableInsertionPoint(db);
} else {
userAccount.debugDbInsertionPoint = size;
}
- compileSqlStatementForLogging(db, userAccount);
- }
-
- private void compileSqlStatementForLogging(SQLiteDatabase db, UserAccounts userAccount) {
- String sql = "INSERT OR REPLACE INTO " + DebugDbHelper.TABLE_DEBUG
- + " VALUES (?,?,?,?,?,?)";
- userAccount.statementForLogging = db.compileStatement(sql);
- }
-
- private long getDebugTableRowCount(SQLiteDatabase db) {
- String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + DebugDbHelper.TABLE_DEBUG;
- return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
- }
-
- /*
- * Finds the row key where the next insertion should take place. This should
- * be invoked only if the table has reached its full capacity.
- */
- private long getDebugTableInsertionPoint(SQLiteDatabase db) {
- // This query finds the smallest timestamp value (and if 2 records have
- // same timestamp, the choose the lower id).
- String queryCountDebugDbRows = new StringBuilder()
- .append("SELECT ").append(DebugDbHelper.KEY)
- .append(" FROM ").append(DebugDbHelper.TABLE_DEBUG)
- .append(" ORDER BY ")
- .append(DebugDbHelper.TIMESTAMP).append(",").append(DebugDbHelper.KEY)
- .append(" LIMIT 1")
- .toString();
- return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
- }
-
- static class PreNDatabaseHelper extends SQLiteOpenHelper {
- private final Context mContext;
- private final int mUserId;
-
- public PreNDatabaseHelper(Context context, int userId, String preNDatabaseName) {
- super(context, preNDatabaseName, null, PRE_N_DATABASE_VERSION);
- mContext = context;
- mUserId = userId;
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- // We use PreNDatabaseHelper only if pre-N db exists
- throw new IllegalStateException("Legacy database cannot be created - only upgraded!");
- }
-
- private void createSharedAccountsTable(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
- + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + ACCOUNTS_NAME + " TEXT NOT NULL, "
- + ACCOUNTS_TYPE + " TEXT NOT NULL, "
- + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
- }
-
- private void addLastSuccessfullAuthenticatedTimeColumn(SQLiteDatabase db) {
- db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN "
- + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " DEFAULT 0");
- }
-
- private void addOldAccountNameColumn(SQLiteDatabase db) {
- db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN " + ACCOUNTS_PREVIOUS_NAME);
- }
-
- private void addDebugTable(SQLiteDatabase db) {
- DebugDbHelper.createDebugTable(db);
- }
-
- private void createAccountsDeletionTrigger(SQLiteDatabase db) {
- db.execSQL(""
- + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
- + " BEGIN"
- + " DELETE FROM " + TABLE_AUTHTOKENS
- + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
- + " DELETE FROM " + TABLE_EXTRAS
- + " WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
- + " DELETE FROM " + TABLE_GRANTS
- + " WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
- + " END");
- }
-
- private void createGrantsTable(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
- + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
- + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL, "
- + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
- + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
- + "," + GRANTS_GRANTEE_UID + "))");
- }
-
- private void populateMetaTableWithAuthTypeAndUID(SQLiteDatabase db,
- Map<String, Integer> authTypeAndUIDMap) {
- for (Entry<String, Integer> entry : authTypeAndUIDMap.entrySet()) {
- AccountsDbUtils.insertMetaAuthTypeAndUid(db, entry.getKey(), entry.getValue());
- }
- }
-
- /**
- * Pre-N database may need an upgrade before splitting
- */
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
-
- if (oldVersion == 1) {
- // no longer need to do anything since the work is done
- // when upgrading from version 2
- oldVersion++;
- }
-
- if (oldVersion == 2) {
- createGrantsTable(db);
- db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
- createAccountsDeletionTrigger(db);
- oldVersion++;
- }
-
- if (oldVersion == 3) {
- db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
- " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
- oldVersion++;
- }
-
- if (oldVersion == 4) {
- createSharedAccountsTable(db);
- oldVersion++;
- }
-
- if (oldVersion == 5) {
- addOldAccountNameColumn(db);
- oldVersion++;
- }
-
- if (oldVersion == 6) {
- addLastSuccessfullAuthenticatedTimeColumn(db);
- oldVersion++;
- }
-
- if (oldVersion == 7) {
- addDebugTable(db);
- oldVersion++;
- }
-
- if (oldVersion == 8) {
- populateMetaTableWithAuthTypeAndUID(
- db,
- getAuthenticatorTypeAndUIDForUser(mContext, mUserId));
- oldVersion++;
- }
-
- if (oldVersion != newVersion) {
- Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
- }
- }
-
- @Override
- public void onOpen(SQLiteDatabase db) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
- }
- }
-
- static class DeDatabaseHelper extends SQLiteOpenHelper {
-
- private final int mUserId;
- private volatile boolean mCeAttached;
-
- private DeDatabaseHelper(Context context, int userId, String deDatabaseName) {
- super(context, deDatabaseName, null, DE_DATABASE_VERSION);
- mUserId = userId;
- }
-
- /**
- * This call needs to be made while the mCacheLock is held. The way to
- * ensure this is to get the lock any time a method is called ont the DatabaseHelper
- * @param db The database.
- */
- @Override
- public void onCreate(SQLiteDatabase db) {
- Log.i(TAG, "Creating DE database for user " + mUserId);
- db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
- + ACCOUNTS_ID + " INTEGER PRIMARY KEY, "
- + ACCOUNTS_NAME + " TEXT NOT NULL, "
- + ACCOUNTS_TYPE + " TEXT NOT NULL, "
- + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
- + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
- + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-
- db.execSQL("CREATE TABLE " + TABLE_META + " ( "
- + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
- + META_VALUE + " TEXT)");
-
- createGrantsTable(db);
- createSharedAccountsTable(db);
- createAccountsDeletionTrigger(db);
- DebugDbHelper.createDebugTable(db);
- }
-
- private void createSharedAccountsTable(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
- + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + ACCOUNTS_NAME + " TEXT NOT NULL, "
- + ACCOUNTS_TYPE + " TEXT NOT NULL, "
- + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
- }
-
- private void createAccountsDeletionTrigger(SQLiteDatabase db) {
- db.execSQL(""
- + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
- + " BEGIN"
- + " DELETE FROM " + TABLE_GRANTS
- + " WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
- + " END");
- }
-
- private void createGrantsTable(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
- + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
- + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL, "
- + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
- + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
- + "," + GRANTS_GRANTEE_UID + "))");
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
-
- if (oldVersion != newVersion) {
- Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
- }
- }
-
- public void attachCeDatabase(File ceDbFile) {
- SQLiteDatabase db = getWritableDatabase();
- db.execSQL("ATTACH DATABASE '" + ceDbFile.getPath()+ "' AS ceDb");
- mCeAttached = true;
- }
-
- public boolean isCeDatabaseAttached() {
- return mCeAttached;
- }
-
-
- public SQLiteDatabase getReadableDatabaseUserIsUnlocked() {
- if(!mCeAttached) {
- Log.wtf(TAG, "getReadableDatabaseUserIsUnlocked called while user " + mUserId
- + " is still locked. CE database is not yet available.", new Throwable());
- }
- return super.getReadableDatabase();
- }
-
- public SQLiteDatabase getWritableDatabaseUserIsUnlocked() {
- if(!mCeAttached) {
- Log.wtf(TAG, "getWritableDatabaseUserIsUnlocked called while user " + mUserId
- + " is still locked. CE database is not yet available.", new Throwable());
- }
- return super.getWritableDatabase();
- }
-
- @Override
- public void onOpen(SQLiteDatabase db) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DE_DATABASE_NAME);
- }
-
- private void migratePreNDbToDe(File preNDbFile) {
- Log.i(TAG, "Migrate pre-N database to DE preNDbFile=" + preNDbFile);
- SQLiteDatabase db = getWritableDatabase();
- db.execSQL("ATTACH DATABASE '" + preNDbFile.getPath() + "' AS preNDb");
- db.beginTransaction();
- // Copy accounts fields
- db.execSQL("INSERT INTO " + TABLE_ACCOUNTS
- + "(" + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
- + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
- + ") "
- + "SELECT " + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
- + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
- + " FROM preNDb." + TABLE_ACCOUNTS);
- // Copy SHARED_ACCOUNTS
- db.execSQL("INSERT INTO " + TABLE_SHARED_ACCOUNTS
- + "(" + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ") " +
- "SELECT " + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
- + " FROM preNDb." + TABLE_SHARED_ACCOUNTS);
- // Copy DEBUG_TABLE
- db.execSQL("INSERT INTO " + DebugDbHelper.TABLE_DEBUG
- + "(" + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
- + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
- + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY + ") " +
- "SELECT " + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
- + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
- + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY
- + " FROM preNDb." + DebugDbHelper.TABLE_DEBUG);
- // Copy GRANTS
- db.execSQL("INSERT INTO " + TABLE_GRANTS
- + "(" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
- + GRANTS_GRANTEE_UID + ") " +
- "SELECT " + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
- + GRANTS_GRANTEE_UID + " FROM preNDb." + TABLE_GRANTS);
- // Copy META
- db.execSQL("INSERT INTO " + TABLE_META
- + "(" + META_KEY + "," + META_VALUE + ") "
- + "SELECT " + META_KEY + "," + META_VALUE + " FROM preNDb." + TABLE_META);
- db.setTransactionSuccessful();
- db.endTransaction();
-
- db.execSQL("DETACH DATABASE preNDb");
- }
-
- static DeDatabaseHelper create(
- Context context,
- int userId,
- File preNDatabaseFile,
- File deDatabaseFile) {
- boolean newDbExists = deDatabaseFile.exists();
- DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId,
- deDatabaseFile.getPath());
- // If the db just created, and there is a legacy db, migrate it
- if (!newDbExists && preNDatabaseFile.exists()) {
- // Migrate legacy db to the latest version - PRE_N_DATABASE_VERSION
- PreNDatabaseHelper preNDatabaseHelper = new PreNDatabaseHelper(context, userId,
- preNDatabaseFile.getPath());
- // Open the database to force upgrade if required
- preNDatabaseHelper.getWritableDatabase();
- preNDatabaseHelper.close();
- // Move data without SPII to DE
- deDatabaseHelper.migratePreNDbToDe(preNDatabaseFile);
- }
- return deDatabaseHelper;
- }
- }
-
- static class CeDatabaseHelper extends SQLiteOpenHelper {
-
- public CeDatabaseHelper(Context context, String ceDatabaseName) {
- super(context, ceDatabaseName, null, CE_DATABASE_VERSION);
- }
-
- /**
- * This call needs to be made while the mCacheLock is held.
- * @param db The database.
- */
- @Override
- public void onCreate(SQLiteDatabase db) {
- Log.i(TAG, "Creating CE database " + getDatabaseName());
- db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
- + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + ACCOUNTS_NAME + " TEXT NOT NULL, "
- + ACCOUNTS_TYPE + " TEXT NOT NULL, "
- + ACCOUNTS_PASSWORD + " TEXT, "
- + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-
- db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
- + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
- + AUTHTOKENS_TYPE + " TEXT NOT NULL, "
- + AUTHTOKENS_AUTHTOKEN + " TEXT, "
- + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
-
- db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
- + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + EXTRAS_ACCOUNTS_ID + " INTEGER, "
- + EXTRAS_KEY + " TEXT NOT NULL, "
- + EXTRAS_VALUE + " TEXT, "
- + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
-
- createAccountsDeletionTrigger(db);
- }
-
- private void createAccountsDeletionTrigger(SQLiteDatabase db) {
- db.execSQL(""
- + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
- + " BEGIN"
- + " DELETE FROM " + TABLE_AUTHTOKENS
- + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
- + " DELETE FROM " + TABLE_EXTRAS
- + " WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
- + " END");
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- Log.i(TAG, "Upgrade CE from version " + oldVersion + " to version " + newVersion);
-
- if (oldVersion == 9) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "onUpgrade upgrading to v10");
- }
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_META);
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_SHARED_ACCOUNTS);
- // Recreate the trigger, since the old one references the table to be removed
- db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "Delete");
- createAccountsDeletionTrigger(db);
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
- db.execSQL("DROP TABLE IF EXISTS " + DebugDbHelper.TABLE_DEBUG);
- oldVersion ++;
- }
-
- if (oldVersion != newVersion) {
- Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
- }
- }
-
- @Override
- public void onOpen(SQLiteDatabase db) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + CE_DATABASE_NAME);
- }
-
-
- /**
- * 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.
- * @param context
- * @param userId id of the user where the database is located
- */
- static CeDatabaseHelper create(
- Context context,
- int userId,
- File preNDatabaseFile,
- File ceDatabaseFile) {
- boolean newDbExists = ceDatabaseFile.exists();
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "CeDatabaseHelper.create userId=" + userId + " oldDbExists="
- + preNDatabaseFile.exists() + " newDbExists=" + newDbExists);
- }
- boolean removeOldDb = false;
- if (!newDbExists && preNDatabaseFile.exists()) {
- removeOldDb = migratePreNDbToCe(preNDatabaseFile, ceDatabaseFile);
- }
- // Try to open and upgrade if necessary
- CeDatabaseHelper ceHelper = new CeDatabaseHelper(context, ceDatabaseFile.getPath());
- ceHelper.getWritableDatabase();
- ceHelper.close();
- if (removeOldDb) {
- Slog.i(TAG, "Migration complete - removing pre-N db " + preNDatabaseFile);
- if (!SQLiteDatabase.deleteDatabase(preNDatabaseFile)) {
- Slog.e(TAG, "Cannot remove pre-N db " + preNDatabaseFile);
- }
- }
- return ceHelper;
- }
-
- private static boolean migratePreNDbToCe(File oldDbFile, File ceDbFile) {
- Slog.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
- try {
- FileUtils.copyFileOrThrow(oldDbFile, ceDbFile);
- } catch (IOException e) {
- Slog.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
- // Try to remove potentially damaged file if I/O error occurred
- deleteDbFileWarnIfFailed(ceDbFile);
- return false;
- }
- return true;
- }
+ userAccount.statementForLogging = DebugDbHelper.compileSqlStatementForLogging(db);
}
public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
@@ -5525,7 +4893,7 @@ public class AccountManagerService
if (isCheckinRequest) {
// This is a checkin request. *Only* upload the account types and the count of each.
- AccountsDbUtils.dumpAccountsTable(db, fout);
+ DeDatabaseHelper.dumpAccountsTable(db, fout);
} else {
Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
Process.myUid(), null);
@@ -5536,7 +4904,7 @@ public class AccountManagerService
// Add debug information.
fout.println();
- AccountsDbUtils.dumpDebugTable(db, fout);
+ DebugDbHelper.dumpDebugTable(db, fout);
fout.println();
synchronized (mSessions) {
final long now = SystemClock.elapsedRealtime();
@@ -5807,19 +5175,15 @@ public class AccountManagerService
UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- final String query;
- final String[] args;
-
+ long grantsCount;
if (authTokenType != null) {
- query = COUNT_OF_MATCHING_GRANTS;
- args = new String[] {String.valueOf(callerUid), authTokenType,
- account.name, account.type};
+ grantsCount = DeDatabaseHelper.findMatchingGrantsCount(db, callerUid, authTokenType,
+ account);
} else {
- query = COUNT_OF_MATCHING_GRANTS_ANY_TOKEN;
- args = new String[] {String.valueOf(callerUid), account.name,
- account.type};
+ grantsCount = DeDatabaseHelper.findMatchingGrantsCountAnyToken(db, callerUid,
+ account);
}
- final boolean permissionGranted = DatabaseUtils.longForQuery(db, query, args) != 0;
+ final boolean permissionGranted = grantsCount > 0;
if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
// TODO: Skip this check when running automated tests. Replace this
@@ -5945,9 +5309,9 @@ public class AccountManagerService
UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- long accountId = AccountsDbUtils.findAccountId(db, account);
+ long accountId = DeDatabaseHelper.findAccountId(db, account);
if (accountId >= 0) {
- AccountsDbUtils.insertGrant(db, accountId, authTokenType, uid);
+ DeDatabaseHelper.insertGrant(db, accountId, authTokenType, uid);
}
cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
UserHandle.of(accounts.userId));
@@ -5980,9 +5344,9 @@ public class AccountManagerService
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
db.beginTransaction();
try {
- long accountId = AccountsDbUtils.findAccountId(db, account);
+ long accountId = DeDatabaseHelper.findAccountId(db, account);
if (accountId >= 0) {
- AccountsDbUtils.deleteGrantsByAccountIdAuthTokenTypeAndUid(
+ DeDatabaseHelper.deleteGrantsByAccountIdAuthTokenTypeAndUid(
db, accountId, authTokenType, uid);
db.setTransactionSuccessful();
}
@@ -6001,10 +5365,6 @@ public class AccountManagerService
}
}
- static final private String stringArrayToString(String[] value) {
- return value != null ? ("[" + TextUtils.join(",", value) + "]") : null;
- }
-
private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
if (oldAccountsForType != null) {
@@ -6151,7 +5511,7 @@ public class AccountManagerService
Account account, String key, String value) {
Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
if (userDataForAccount == null) {
- userDataForAccount = AccountsDbUtils.findUserExtrasForAccount(db, account);
+ userDataForAccount = CeDatabaseHelper.findUserExtrasForAccount(db, account);
accounts.userDataCache.put(account, userDataForAccount);
}
if (value == null) {
@@ -6177,7 +5537,7 @@ public class AccountManagerService
Account account, String key, String value) {
Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
if (authTokensForAccount == null) {
- authTokensForAccount = AccountsDbUtils.findAuthTokensByAccount(db, account);
+ authTokensForAccount = CeDatabaseHelper.findAuthTokensByAccount(db, account);
accounts.authTokenCache.put(account, authTokensForAccount);
}
if (value == null) {
@@ -6194,8 +5554,7 @@ public class AccountManagerService
if (authTokensForAccount == null) {
// need to populate the cache for this account
final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
- authTokensForAccount = AccountsDbUtils
- .findAuthTokensByAccount(db, account);
+ authTokensForAccount = CeDatabaseHelper.findAuthTokensByAccount(db, account);
accounts.authTokenCache.put(account, authTokensForAccount);
}
return authTokensForAccount.get(authTokenType);
@@ -6208,7 +5567,7 @@ public class AccountManagerService
if (userDataForAccount == null) {
// need to populate the cache for this account
final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
- userDataForAccount = AccountsDbUtils.findUserExtrasForAccount(db, account);
+ userDataForAccount = CeDatabaseHelper.findUserExtrasForAccount(db, account);
accounts.userDataCache.put(account, userDataForAccount);
}
return userDataForAccount.get(key);
@@ -6248,418 +5607,6 @@ public class AccountManagerService
}
}
- static class AccountsDbUtils {
-
- static String findAccountPasswordByNameAndType(SQLiteDatabase db, String name,
- String type) {
- Cursor cursor = db.query(CE_TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
- new String[]{name, type}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getString(0);
- }
- return null;
- } finally {
- cursor.close();
- }
- }
-
- static Map<Long, Account> findAllAccounts(SQLiteDatabase db) {
- LinkedHashMap<Long, Account> map = new LinkedHashMap<>();
- Cursor cursor = db.query(TABLE_ACCOUNTS,
- new String[] {ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
- null, null, null, null, ACCOUNTS_ID);
- try {
- while (cursor.moveToNext()) {
- final long accountId = cursor.getLong(0);
- final String accountType = cursor.getString(1);
- final String accountName = cursor.getString(2);
-
- final Account account = new Account(accountName, accountType);
- map.put(accountId, account);
- }
- } finally {
- cursor.close();
- }
- return map;
- }
-
- static String findAccountPreviousName(SQLiteDatabase db, Account account) {
- Cursor cursor = db.query(
- TABLE_ACCOUNTS,
- new String[]{ ACCOUNTS_PREVIOUS_NAME },
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[] { account.name, account.type },
- null,
- null,
- null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getString(0);
- }
- } finally {
- cursor.close();
- }
- return null;
- }
-
- 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();
- }
- }
-
- static boolean deleteAccount(SQLiteDatabase db, long accountId) {
- return db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
- }
-
- static boolean deleteCeAccount(SQLiteDatabase db, long accountId) {
- return db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
- }
-
- /**
- * Returns information about auth tokens and their account for the specified query parameters.
- * Output is in the format:
- * <pre><code> | AUTHTOKEN_ID | ACCOUNT_NAME | AUTH_TOKEN_TYPE |</code></pre>
- */
- static Cursor findAuthtokenForAllAccounts(SQLiteDatabase db, String accountType,
- String authToken) {
- return db.rawQuery(
- "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
- + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
- + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
- + " FROM " + CE_TABLE_ACCOUNTS
- + " JOIN " + CE_TABLE_AUTHTOKENS
- + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
- + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
- + " WHERE " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_AUTHTOKEN
- + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
- new String[]{authToken, accountType});
- }
-
- static boolean deleteAuthtokensByAccountIdAndType(SQLiteDatabase db, long accountId,
- String authtokenType) {
- return db.delete(CE_TABLE_AUTHTOKENS,
- AUTHTOKENS_ACCOUNTS_ID + "=?" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
- new String[] {String.valueOf(accountId), authtokenType}) > 0;
- }
-
- static boolean deleteAuthToken(SQLiteDatabase db, String authTokenId) {
- return db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "= ?",
- new String[] {authTokenId}) > 0;
- }
-
- static long insertAuthToken(SQLiteDatabase db, long accountId, String authTokenType,
- String authToken) {
- ContentValues values = new ContentValues();
- values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
- values.put(AUTHTOKENS_TYPE, authTokenType);
- values.put(AUTHTOKENS_AUTHTOKEN, authToken);
- return db.insert(CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values);
- }
-
- static Map<String, String> findAuthTokensByAccount(final SQLiteDatabase db, Account account) {
- HashMap<String, String> authTokensForAccount = new HashMap<>();
- Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
- COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
- SELECTION_AUTHTOKENS_BY_ACCOUNT,
- new String[]{account.name, account.type},
- null, null, null);
- try {
- while (cursor.moveToNext()) {
- final String type = cursor.getString(0);
- final String authToken = cursor.getString(1);
- authTokensForAccount.put(type, authToken);
- }
- } finally {
- cursor.close();
- }
- return authTokensForAccount;
- }
-
- static int updateAccountPassword(SQLiteDatabase db, long accountId, String password) {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_PASSWORD, password);
- return db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?",
- new String[] {String.valueOf(accountId)});
- }
-
- static boolean deleteAuthTokensByAccountId(SQLiteDatabase db, long accountId) {
- return db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?",
- new String[] {String.valueOf(accountId)}) > 0;
- }
-
- static long insertSharedAccount(SQLiteDatabase db, Account account) {
- ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, account.name);
- values.put(ACCOUNTS_TYPE, account.type);
- return db.insert(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME, values);
- }
-
- static boolean deleteSharedAccount(SQLiteDatabase db, Account account) {
- return db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
- new String[] {account.name, account.type}) > 0;
- }
-
- static int renameSharedAccount(SQLiteDatabase db, Account account, String newName) {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, newName);
- return db.update(TABLE_SHARED_ACCOUNTS,
- values,
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[] { account.name, account.type });
- }
-
- static List<Account> getSharedAccounts(SQLiteDatabase db) {
- ArrayList<Account> accountList = new ArrayList<>();
- Cursor cursor = null;
- try {
- cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[] {ACCOUNTS_NAME, ACCOUNTS_TYPE},
- null, null, null, null, null);
- if (cursor != null && cursor.moveToFirst()) {
- int nameIndex = cursor.getColumnIndex(ACCOUNTS_NAME);
- int typeIndex = cursor.getColumnIndex(ACCOUNTS_TYPE);
- do {
- accountList.add(new Account(cursor.getString(nameIndex),
- cursor.getString(typeIndex)));
- } while (cursor.moveToNext());
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return accountList;
- }
-
- static long findSharedAccountId(SQLiteDatabase db, Account account) {
- Cursor cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{ACCOUNTS_ID},
- "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getLong(0);
- }
- return -1;
- } finally {
- cursor.close();
- }
- }
-
- static long findAccountId(SQLiteDatabase db, Account account) {
- Cursor cursor = db.query(
- TABLE_ACCOUNTS, new String[] {ACCOUNTS_ID},
- "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getLong(0);
- }
- return -1;
- } finally {
- cursor.close();
- }
- }
-
- static long findExtrasIdByAccountId(SQLiteDatabase db, long accountId, String key) {
- Cursor cursor = db.query(
- CE_TABLE_EXTRAS, new String[] {EXTRAS_ID},
- EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
- new String[]{key}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getLong(0);
- }
- return -1;
- } finally {
- cursor.close();
- }
- }
-
- static boolean updateExtra(SQLiteDatabase db, long extrasId, String value) {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_VALUE, value);
- int rows = db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=?",
- new String[]{String.valueOf(extrasId)});
- return rows == 1;
- }
-
- static long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_KEY, key);
- values.put(EXTRAS_ACCOUNTS_ID, accountId);
- values.put(EXTRAS_VALUE, value);
- return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
- }
-
- static Map<String, String> findUserExtrasForAccount(SQLiteDatabase db, Account account) {
- Map<String, String> userExtrasForAccount = new HashMap<>();
- Cursor cursor = db.query(CE_TABLE_EXTRAS,
- COLUMNS_EXTRAS_KEY_AND_VALUE,
- SELECTION_USERDATA_BY_ACCOUNT,
- new String[] {account.name, account.type},
- null, null, null);
- try {
- while (cursor.moveToNext()) {
- final String tmpkey = cursor.getString(0);
- final String value = cursor.getString(1);
- userExtrasForAccount.put(tmpkey, value);
- }
- } finally {
- cursor.close();
- }
- return userExtrasForAccount;
- }
-
- static long insertGrant(SQLiteDatabase db, long accountId, String authTokenType, int uid) {
- ContentValues values = new ContentValues();
- values.put(GRANTS_ACCOUNTS_ID, accountId);
- values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
- values.put(GRANTS_GRANTEE_UID, uid);
- return db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
- }
-
- static boolean deleteGrantsByUid(SQLiteDatabase db, int uid) {
- return db.delete(TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
- new String[] {Integer.toString(uid)}) > 0;
- }
-
- static boolean deleteGrantsByAccountIdAuthTokenTypeAndUid(SQLiteDatabase db, long accountId, String authTokenType, long uid) {
- return db.delete(TABLE_GRANTS,
- GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
- + GRANTS_GRANTEE_UID + "=?",
- new String[] {String.valueOf(accountId), authTokenType, String.valueOf(uid)}) > 0;
- }
-
- static List<Integer> findAllUidGrants(SQLiteDatabase db) {
- List<Integer> result = new ArrayList<>();
- final Cursor cursor = db.query(TABLE_GRANTS,
- new String[] {GRANTS_GRANTEE_UID},
- null, null, GRANTS_GRANTEE_UID, null, null);
- try {
- while (cursor.moveToNext()) {
- final int uid = cursor.getInt(0);
- result.add(uid);
- }
- } finally {
- cursor.close();
- }
- return result;
- }
-
- static long findMatchingGrantsCount(SQLiteDatabase db,
- int uid, String authTokenType, Account account) {
- String[] args = { String.valueOf(uid), authTokenType,
- account.name, account.type};
- return DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args);
- }
-
- static long insertMetaAuthTypeAndUid(SQLiteDatabase db, String authenticatorType, int uid) {
- ContentValues values = new ContentValues();
- values.put(META_KEY,
- META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
- values.put(META_VALUE, uid);
- return db.insert(TABLE_META, null, values);
- }
-
- static long insertOrReplaceMetaAuthTypeAndUid(SQLiteDatabase db, String authenticatorType,
- int uid) {
- ContentValues values = new ContentValues();
- values.put(META_KEY,
- META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
- values.put(META_VALUE, uid);
- return db.insertWithOnConflict(TABLE_META, null, values,
- SQLiteDatabase.CONFLICT_REPLACE);
- }
-
-
- static Map<String, Integer> findMetaAuthUid(SQLiteDatabase db) {
- Cursor metaCursor = db.query(
- TABLE_META,
- new String[] {META_KEY, META_VALUE},
- SELECTION_META_BY_AUTHENTICATOR_TYPE,
- new String[] {META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + "%"},
- null /* groupBy */,
- null /* having */,
- META_KEY);
- Map<String, Integer> map = new LinkedHashMap<>();
- try {
- while (metaCursor.moveToNext()) {
- String type = TextUtils.split(metaCursor.getString(0), META_KEY_DELIMITER)[1];
- String uidStr = metaCursor.getString(1);
- if (TextUtils.isEmpty(type) || TextUtils.isEmpty(uidStr)) {
- // Should never happen.
- Slog.e(TAG, "Auth type empty: " + TextUtils.isEmpty(type)
- + ", uid empty: " + TextUtils.isEmpty(uidStr));
- continue;
- }
- int uid = Integer.parseInt(metaCursor.getString(1));
- map.put(type, uid);
- }
- } finally {
- metaCursor.close();
- }
- return map;
- }
-
- static boolean deleteMetaByAuthTypeAndUid(SQLiteDatabase db, String type, int uid) {
- return db.delete(
- TABLE_META,
- META_KEY + "=? AND " + META_VALUE + "=?",
- new String[] {
- META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
- String.valueOf(uid)}
- ) > 0;
- }
-
- static void dumpAccountsTable(SQLiteDatabase db, PrintWriter pw) {
- Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
- null, null, ACCOUNTS_TYPE, null, null);
- try {
- while (cursor.moveToNext()) {
- // print type,count
- pw.println(cursor.getString(0) + "," + cursor.getString(1));
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- static void dumpDebugTable(SQLiteDatabase db, PrintWriter pw) {
- Cursor cursor = db.query(DebugDbHelper.TABLE_DEBUG, null,
- null, null, null, null, DebugDbHelper.TIMESTAMP);
- pw.println("AccountId, Action_Type, timestamp, UID, TableName, Key");
- pw.println("Accounts History");
- try {
- while (cursor.moveToNext()) {
- // print type,count
- pw.println(cursor.getString(0) + "," + cursor.getString(1) + "," +
- cursor.getString(2) + "," + cursor.getString(3) + ","
- + cursor.getString(4) + "," + cursor.getString(5));
- }
- } finally {
- cursor.close();
- }
- }
- }
-
private final class AccountAccessTracker extends IAccountAccessTracker.Stub {
@Override
public void onAccountAccessed() throws RemoteException {
diff --git a/services/core/java/com/android/server/accounts/AccountsDb.java b/services/core/java/com/android/server/accounts/AccountsDb.java
new file mode 100644
index 000000000000..6ef521ede4c1
--- /dev/null
+++ b/services/core/java/com/android/server/accounts/AccountsDb.java
@@ -0,0 +1,1174 @@
+/*
+ * Copyright (C) 2016 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 com.android.server.accounts;
+
+import android.accounts.Account;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteStatement;
+import android.os.FileUtils;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Persistence layer abstraction for accessing accounts_ce/accounts_de databases.
+ */
+class AccountsDb {
+ private static final String TAG = "AccountsDb";
+
+ private static final String DATABASE_NAME = "accounts.db";
+ private static final int PRE_N_DATABASE_VERSION = 9;
+ private static final int CE_DATABASE_VERSION = 10;
+ private static final int DE_DATABASE_VERSION = 1;
+
+
+ static final String TABLE_ACCOUNTS = "accounts";
+ private static final String ACCOUNTS_ID = "_id";
+ private static final String ACCOUNTS_NAME = "name";
+ private static final String ACCOUNTS_TYPE = "type";
+ private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
+ private static final String ACCOUNTS_PASSWORD = "password";
+ private static final String ACCOUNTS_PREVIOUS_NAME = "previous_name";
+ private static final String ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS =
+ "last_password_entry_time_millis_epoch";
+
+ private static final String TABLE_AUTHTOKENS = "authtokens";
+ private static final String AUTHTOKENS_ID = "_id";
+ private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
+ private static final String AUTHTOKENS_TYPE = "type";
+ private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
+
+ private static final String TABLE_GRANTS = "grants";
+ private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
+ private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
+ private static final String GRANTS_GRANTEE_UID = "uid";
+
+ private static final String TABLE_EXTRAS = "extras";
+ private static final String EXTRAS_ID = "_id";
+ private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
+ private static final String EXTRAS_KEY = "key";
+ private static final String EXTRAS_VALUE = "value";
+
+ private static final String TABLE_META = "meta";
+ private static final String META_KEY = "key";
+ private static final String META_VALUE = "value";
+
+ static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
+ private static final String SHARED_ACCOUNTS_ID = "_id";
+
+ private static String TABLE_DEBUG = "debug_table";
+
+ // Columns for debug_table table
+ private static String DEBUG_TABLE_ACTION_TYPE = "action_type";
+ private static String DEBUG_TABLE_TIMESTAMP = "time";
+ private static String DEBUG_TABLE_CALLER_UID = "caller_uid";
+ private static String DEBUG_TABLE_TABLE_NAME = "table_name";
+ private static String DEBUG_TABLE_KEY = "primary_key";
+
+ // These actions correspond to the occurrence of real actions. Since
+ // these are called by the authenticators, the uid associated will be
+ // of the authenticator.
+ static String DEBUG_ACTION_SET_PASSWORD = "action_set_password";
+ static String DEBUG_ACTION_CLEAR_PASSWORD = "action_clear_password";
+ static String DEBUG_ACTION_ACCOUNT_ADD = "action_account_add";
+ static String DEBUG_ACTION_ACCOUNT_REMOVE = "action_account_remove";
+ static String DEBUG_ACTION_ACCOUNT_REMOVE_DE = "action_account_remove_de";
+ static String DEBUG_ACTION_AUTHENTICATOR_REMOVE = "action_authenticator_remove";
+ static String DEBUG_ACTION_ACCOUNT_RENAME = "action_account_rename";
+
+ // These actions don't necessarily correspond to any action on
+ // accountDb taking place. As an example, there might be a request for
+ // addingAccount, which might not lead to addition of account on grounds
+ // of bad authentication. We will still be logging it to keep track of
+ // who called.
+ static String DEBUG_ACTION_CALLED_ACCOUNT_ADD = "action_called_account_add";
+ static String DEBUG_ACTION_CALLED_ACCOUNT_REMOVE = "action_called_account_remove";
+ static String DEBUG_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.
+ static String DEBUG_ACTION_CALLED_START_ACCOUNT_ADD = "action_called_start_account_add";
+ static String DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH =
+ "action_called_account_session_finish";
+
+ static final String CE_DATABASE_NAME = "accounts_ce.db";
+ static final String DE_DATABASE_NAME = "accounts_de.db";
+ private static final String CE_DB_PREFIX = "ceDb.";
+ private static final String CE_TABLE_ACCOUNTS = CE_DB_PREFIX + TABLE_ACCOUNTS;
+ private static final String CE_TABLE_AUTHTOKENS = CE_DB_PREFIX + TABLE_AUTHTOKENS;
+ private static final String CE_TABLE_EXTRAS = CE_DB_PREFIX + TABLE_EXTRAS;
+
+ private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
+ new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
+
+ private static final String COUNT_OF_MATCHING_GRANTS = ""
+ + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
+ + " AND " + GRANTS_GRANTEE_UID + "=?"
+ + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
+ + " AND " + ACCOUNTS_NAME + "=?"
+ + " AND " + ACCOUNTS_TYPE + "=?";
+
+ private static final String COUNT_OF_MATCHING_GRANTS_ANY_TOKEN = ""
+ + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
+ + " AND " + GRANTS_GRANTEE_UID + "=?"
+ + " AND " + ACCOUNTS_NAME + "=?"
+ + " AND " + ACCOUNTS_TYPE + "=?";
+
+ private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
+ AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
+
+ private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
+ AUTHTOKENS_AUTHTOKEN};
+
+ private static final String SELECTION_USERDATA_BY_ACCOUNT =
+ EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
+ private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
+
+ private static final String ACCOUNT_ACCESS_GRANTS = ""
+ + "SELECT " + AccountsDb.ACCOUNTS_NAME + ", "
+ + AccountsDb.GRANTS_GRANTEE_UID
+ + " FROM " + AccountsDb.TABLE_ACCOUNTS
+ + ", " + AccountsDb.TABLE_GRANTS
+ + " WHERE " + AccountsDb.GRANTS_ACCOUNTS_ID
+ + "=" + AccountsDb.ACCOUNTS_ID;
+
+ private static final String META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX =
+ "auth_uid_for_type:";
+ private static final String META_KEY_DELIMITER = ":";
+ private static final String SELECTION_META_BY_AUTHENTICATOR_TYPE = META_KEY + " LIKE ?";
+
+ static class CeDatabaseHelper extends SQLiteOpenHelper {
+
+ CeDatabaseHelper(Context context, String ceDatabaseName) {
+ super(context, ceDatabaseName, null, CE_DATABASE_VERSION);
+ }
+
+ /**
+ * This call needs to be made while the mCacheLock is held.
+ * @param db The database.
+ */
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ Log.i(TAG, "Creating CE database " + getDatabaseName());
+ db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + ACCOUNTS_PASSWORD + " TEXT, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
+ + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + AUTHTOKENS_TYPE + " TEXT NOT NULL, "
+ + AUTHTOKENS_AUTHTOKEN + " TEXT, "
+ + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
+ + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + EXTRAS_ACCOUNTS_ID + " INTEGER, "
+ + EXTRAS_KEY + " TEXT NOT NULL, "
+ + EXTRAS_VALUE + " TEXT, "
+ + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
+
+ createAccountsDeletionTrigger(db);
+ }
+
+ private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_AUTHTOKENS
+ + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " DELETE FROM " + TABLE_EXTRAS
+ + " WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.i(TAG, "Upgrade CE from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion == 9) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "onUpgrade upgrading to v10");
+ }
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_META);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_SHARED_ACCOUNTS);
+ // Recreate the trigger, since the old one references the table to be removed
+ db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "Delete");
+ createAccountsDeletionTrigger(db);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_DEBUG);
+ oldVersion ++;
+ }
+
+ if (oldVersion != newVersion) {
+ Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+ }
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + CE_DATABASE_NAME);
+ }
+
+
+ /**
+ * 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.
+ * @param userId id of the user where the database is located
+ */
+ static CeDatabaseHelper create(
+ Context context,
+ int userId,
+ File preNDatabaseFile,
+ File ceDatabaseFile) {
+ boolean newDbExists = ceDatabaseFile.exists();
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "CeDatabaseHelper.create userId=" + userId + " oldDbExists="
+ + preNDatabaseFile.exists() + " newDbExists=" + newDbExists);
+ }
+ boolean removeOldDb = false;
+ if (!newDbExists && preNDatabaseFile.exists()) {
+ removeOldDb = migratePreNDbToCe(preNDatabaseFile, ceDatabaseFile);
+ }
+ // Try to open and upgrade if necessary
+ CeDatabaseHelper ceHelper = new CeDatabaseHelper(context, ceDatabaseFile.getPath());
+ ceHelper.getWritableDatabase();
+ ceHelper.close();
+ if (removeOldDb) {
+ Slog.i(TAG, "Migration complete - removing pre-N db " + preNDatabaseFile);
+ if (!SQLiteDatabase.deleteDatabase(preNDatabaseFile)) {
+ Slog.e(TAG, "Cannot remove pre-N db " + preNDatabaseFile);
+ }
+ }
+ return ceHelper;
+ }
+
+ private static boolean migratePreNDbToCe(File oldDbFile, File ceDbFile) {
+ Slog.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
+ try {
+ FileUtils.copyFileOrThrow(oldDbFile, ceDbFile);
+ } catch (IOException e) {
+ Slog.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
+ // Try to remove potentially damaged file if I/O error occurred
+ deleteDbFileWarnIfFailed(ceDbFile);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns information about auth tokens and their account for the specified query
+ * parameters.
+ * Output is in the format:
+ * <pre><code> | AUTHTOKEN_ID | ACCOUNT_NAME | AUTH_TOKEN_TYPE |</code></pre>
+ */
+ static Cursor findAuthtokenForAllAccounts(SQLiteDatabase db, String accountType,
+ String authToken) {
+ return db.rawQuery(
+ "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+ + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
+ + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+ + " FROM " + CE_TABLE_ACCOUNTS
+ + " JOIN " + CE_TABLE_AUTHTOKENS
+ + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+ + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
+ + " WHERE " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_AUTHTOKEN
+ + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+ new String[]{authToken, accountType});
+ }
+
+ static boolean deleteAuthtokensByAccountIdAndType(SQLiteDatabase db, long accountId,
+ String authtokenType) {
+ return db.delete(CE_TABLE_AUTHTOKENS,
+ AUTHTOKENS_ACCOUNTS_ID + "=?" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+ new String[]{String.valueOf(accountId), authtokenType}) > 0;
+ }
+
+ static boolean deleteAuthToken(SQLiteDatabase db, String authTokenId) {
+ return db.delete(
+ CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "= ?",
+ new String[]{authTokenId}) > 0;
+ }
+
+ static long insertAuthToken(SQLiteDatabase db, long accountId, String authTokenType,
+ String authToken) {
+ ContentValues values = new ContentValues();
+ values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
+ values.put(AUTHTOKENS_TYPE, authTokenType);
+ values.put(AUTHTOKENS_AUTHTOKEN, authToken);
+ return db.insert(
+ CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values);
+ }
+
+ static Map<String, String> findAuthTokensByAccount(final SQLiteDatabase db,
+ Account account) {
+ HashMap<String, String> authTokensForAccount = new HashMap<>();
+ Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
+ COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
+ SELECTION_AUTHTOKENS_BY_ACCOUNT,
+ new String[]{account.name, account.type},
+ null, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ final String type = cursor.getString(0);
+ final String authToken = cursor.getString(1);
+ authTokensForAccount.put(type, authToken);
+ }
+ } finally {
+ cursor.close();
+ }
+ return authTokensForAccount;
+ }
+
+ static int updateAccountPassword(SQLiteDatabase db, long accountId, String password) {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_PASSWORD, password);
+ return db.update(
+ CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?",
+ new String[]{String.valueOf(accountId)});
+ }
+
+ static boolean renameAccount(SQLiteDatabase db, long accountId, String newName) {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, newName);
+ final String[] argsAccountId = {String.valueOf(accountId)};
+ return db.update(
+ CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId) > 0;
+ }
+
+ static boolean deleteAuthTokensByAccountId(SQLiteDatabase db, long accountId) {
+ return db.delete(
+ CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?",
+ new String[]{String.valueOf(accountId)}) > 0;
+ }
+
+ static long findExtrasIdByAccountId(SQLiteDatabase db, long accountId, String key) {
+ Cursor cursor = db.query(
+ CE_TABLE_EXTRAS, new String[]{EXTRAS_ID},
+ EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+ new String[]{key}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ static boolean updateExtra(SQLiteDatabase db, long extrasId, String value) {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_VALUE, value);
+ int rows = db.update(
+ TABLE_EXTRAS, values, EXTRAS_ID + "=?",
+ new String[]{String.valueOf(extrasId)});
+ return rows == 1;
+ }
+
+ static long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_KEY, key);
+ values.put(EXTRAS_ACCOUNTS_ID, accountId);
+ values.put(EXTRAS_VALUE, value);
+ return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
+ }
+
+ static Map<String, String> findUserExtrasForAccount(SQLiteDatabase db, Account account) {
+ Map<String, String> userExtrasForAccount = new HashMap<>();
+ Cursor cursor = db.query(CE_TABLE_EXTRAS,
+ COLUMNS_EXTRAS_KEY_AND_VALUE,
+ SELECTION_USERDATA_BY_ACCOUNT,
+ new String[]{account.name, account.type},
+ null, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ final String tmpkey = cursor.getString(0);
+ final String value = cursor.getString(1);
+ userExtrasForAccount.put(tmpkey, value);
+ }
+ } finally {
+ cursor.close();
+ }
+ return userExtrasForAccount;
+ }
+
+ static long findAccountId(SQLiteDatabase db, Account account) {
+ Cursor cursor = db.query(
+ CE_TABLE_ACCOUNTS, new String[]{
+ ACCOUNTS_ID},
+ "name=? AND type=?", new String[]{account.name, account.type}, null, null,
+ null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ static String findAccountPasswordByNameAndType(SQLiteDatabase db, String name,
+ String type) {
+ Cursor cursor = db.query(CE_TABLE_ACCOUNTS, new String[]{
+ ACCOUNTS_PASSWORD},
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[]{name, type}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ static long insertAccount(SQLiteDatabase db, Account account, String password) {
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ values.put(ACCOUNTS_PASSWORD, password);
+ return db.insert(
+ CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ }
+
+ }
+
+ static class DeDatabaseHelper extends SQLiteOpenHelper {
+
+ private final int mUserId;
+ private volatile boolean mCeAttached;
+
+ private DeDatabaseHelper(Context context, int userId, String deDatabaseName) {
+ super(context, deDatabaseName, null, DE_DATABASE_VERSION);
+ mUserId = userId;
+ }
+
+ /**
+ * This call needs to be made while the mCacheLock is held. The way to
+ * ensure this is to get the lock any time a method is called ont the DatabaseHelper
+ * @param db The database.
+ */
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ Log.i(TAG, "Creating DE database for user " + mUserId);
+ db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
+ + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_META + " ( "
+ + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
+ + META_VALUE + " TEXT)");
+
+ createGrantsTable(db);
+ createSharedAccountsTable(db);
+ createAccountsDeletionTrigger(db);
+ DebugDbHelper.createDebugTable(db);
+ }
+
+ private void createSharedAccountsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+ }
+
+ private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_GRANTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ private void createGrantsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
+ + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL, "
+ + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
+ + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+ + "," + GRANTS_GRANTEE_UID + "))");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion != newVersion) {
+ Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+ }
+ }
+
+ public void attachCeDatabase(File ceDbFile) {
+ SQLiteDatabase db = getWritableDatabase();
+ db.execSQL("ATTACH DATABASE '" + ceDbFile.getPath()+ "' AS ceDb");
+ mCeAttached = true;
+ }
+
+ public boolean isCeDatabaseAttached() {
+ return mCeAttached;
+ }
+
+
+ public SQLiteDatabase getReadableDatabaseUserIsUnlocked() {
+ if(!mCeAttached) {
+ Log.wtf(TAG, "getReadableDatabaseUserIsUnlocked called while user " + mUserId
+ + " is still locked. CE database is not yet available.", new Throwable());
+ }
+ return super.getReadableDatabase();
+ }
+
+ public SQLiteDatabase getWritableDatabaseUserIsUnlocked() {
+ if(!mCeAttached) {
+ Log.wtf(TAG, "getWritableDatabaseUserIsUnlocked called while user " + mUserId
+ + " is still locked. CE database is not yet available.", new Throwable());
+ }
+ return super.getWritableDatabase();
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DE_DATABASE_NAME);
+ }
+
+ private void migratePreNDbToDe(File preNDbFile) {
+ Log.i(TAG, "Migrate pre-N database to DE preNDbFile=" + preNDbFile);
+ SQLiteDatabase db = getWritableDatabase();
+ db.execSQL("ATTACH DATABASE '" + preNDbFile.getPath() + "' AS preNDb");
+ db.beginTransaction();
+ // Copy accounts fields
+ db.execSQL("INSERT INTO " + TABLE_ACCOUNTS
+ + "(" + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+ + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + ") "
+ + "SELECT " + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+ + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + " FROM preNDb." + TABLE_ACCOUNTS);
+ // Copy SHARED_ACCOUNTS
+ db.execSQL("INSERT INTO " + TABLE_SHARED_ACCOUNTS
+ + "(" + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ") " +
+ "SELECT " + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
+ + " FROM preNDb." + TABLE_SHARED_ACCOUNTS);
+ // Copy DEBUG_TABLE
+ db.execSQL("INSERT INTO " + TABLE_DEBUG
+ + "(" + ACCOUNTS_ID + "," + DEBUG_TABLE_ACTION_TYPE + ","
+ + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_CALLER_UID + ","
+ + DEBUG_TABLE_TABLE_NAME + "," + DEBUG_TABLE_KEY + ") " +
+ "SELECT " + ACCOUNTS_ID + "," + DEBUG_TABLE_ACTION_TYPE + ","
+ + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_CALLER_UID + ","
+ + DEBUG_TABLE_TABLE_NAME + "," + DEBUG_TABLE_KEY
+ + " FROM preNDb." + TABLE_DEBUG);
+ // Copy GRANTS
+ db.execSQL("INSERT INTO " + TABLE_GRANTS
+ + "(" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+ + GRANTS_GRANTEE_UID + ") " +
+ "SELECT " + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+ + GRANTS_GRANTEE_UID + " FROM preNDb." + TABLE_GRANTS);
+ // Copy META
+ db.execSQL("INSERT INTO " + TABLE_META
+ + "(" + META_KEY + "," + META_VALUE + ") "
+ + "SELECT " + META_KEY + "," + META_VALUE + " FROM preNDb." + TABLE_META);
+ db.setTransactionSuccessful();
+ db.endTransaction();
+
+ db.execSQL("DETACH DATABASE preNDb");
+ }
+
+ static boolean deleteAccount(SQLiteDatabase db, long accountId) {
+ return db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
+ }
+
+ static long insertSharedAccount(SQLiteDatabase db, Account account) {
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ return db.insert(
+ TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME, values);
+ }
+
+ static boolean deleteSharedAccount(SQLiteDatabase db, Account account) {
+ return db
+ .delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[]{account.name, account.type}) > 0;
+ }
+
+ static int renameSharedAccount(SQLiteDatabase db, Account account, String newName) {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, newName);
+ return db.update(TABLE_SHARED_ACCOUNTS,
+ values,
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
+ + "=?",
+ new String[]{account.name, account.type});
+ }
+
+ static List<Account> getSharedAccounts(SQLiteDatabase db) {
+ ArrayList<Account> accountList = new ArrayList<>();
+ Cursor cursor = null;
+ try {
+ cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{
+ ACCOUNTS_NAME, ACCOUNTS_TYPE},
+ null, null, null, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ int nameIndex = cursor.getColumnIndex(ACCOUNTS_NAME);
+ int typeIndex = cursor.getColumnIndex(ACCOUNTS_TYPE);
+ do {
+ accountList.add(new Account(cursor.getString(nameIndex),
+ cursor.getString(typeIndex)));
+ } while (cursor.moveToNext());
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return accountList;
+ }
+
+ static long findSharedAccountId(SQLiteDatabase db, Account account) {
+ Cursor cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{
+ ACCOUNTS_ID},
+ "name=? AND type=?", new String[]{account.name, account.type}, null, null,
+ null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ static long findAccountLastAuthenticatedTime(SQLiteDatabase db, Account account) {
+ return DatabaseUtils.longForQuery(
+ db,
+ "SELECT " + AccountsDb.ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + " FROM " +
+ TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
+ + ACCOUNTS_TYPE + "=?",
+ new String[] {account.name, account.type});
+ }
+
+ static boolean updateAccountLastAuthenticatedTime(SQLiteDatabase db, Account account) {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
+ int rowCount = db.update(
+ TABLE_ACCOUNTS,
+ values,
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[] {
+ account.name, account.type
+ });
+ return rowCount > 0;
+ }
+
+
+ static void dumpAccountsTable(SQLiteDatabase db, PrintWriter pw) {
+ Cursor cursor = db.query(
+ TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
+ null, null, ACCOUNTS_TYPE, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ // print type,count
+ pw.println(cursor.getString(0) + "," + cursor.getString(1));
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ static long findAccountId(SQLiteDatabase db, Account account) {
+ Cursor cursor = db.query(
+ TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
+ "name=? AND type=?", new String[]{account.name, account.type}, null, null,
+ null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ static Map<Long, Account> findAllAccounts(SQLiteDatabase db) {
+ LinkedHashMap<Long, Account> map = new LinkedHashMap<>();
+ Cursor cursor = db.query(TABLE_ACCOUNTS,
+ new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
+ null, null, null, null, ACCOUNTS_ID);
+ try {
+ while (cursor.moveToNext()) {
+ final long accountId = cursor.getLong(0);
+ final String accountType = cursor.getString(1);
+ final String accountName = cursor.getString(2);
+
+ final Account account = new Account(accountName, accountType);
+ map.put(accountId, account);
+ }
+ } finally {
+ cursor.close();
+ }
+ return map;
+ }
+
+ static String findAccountPreviousName(SQLiteDatabase db, Account account) {
+ Cursor cursor = db.query(
+ TABLE_ACCOUNTS,
+ new String[]{ACCOUNTS_PREVIOUS_NAME},
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
+ + "=?",
+ new String[]{account.name, account.type},
+ null,
+ null,
+ null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ } finally {
+ cursor.close();
+ }
+ return null;
+ }
+
+ static long insertAccount(SQLiteDatabase db, Account account, long accountId) {
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_ID, accountId);
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
+ return db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ }
+
+ static boolean renameAccount(SQLiteDatabase db, long accountId, String newName,
+ String previousName) {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, newName);
+ values.put(ACCOUNTS_PREVIOUS_NAME, previousName);
+ final String[] argsAccountId = {String.valueOf(accountId)};
+ return db.update(
+ TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId) > 0;
+ }
+
+ static boolean deleteGrantsByAccountIdAuthTokenTypeAndUid(SQLiteDatabase db, long accountId,
+ String authTokenType, long uid) {
+ return db.delete(TABLE_GRANTS,
+ GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
+ + GRANTS_GRANTEE_UID + "=?",
+ new String[]{String.valueOf(accountId), authTokenType, String.valueOf(uid)})
+ > 0;
+ }
+
+ static List<Integer> findAllUidGrants(SQLiteDatabase db) {
+ List<Integer> result = new ArrayList<>();
+ final Cursor cursor = db.query(TABLE_GRANTS,
+ new String[]{GRANTS_GRANTEE_UID},
+ null, null, GRANTS_GRANTEE_UID, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ final int uid = cursor.getInt(0);
+ result.add(uid);
+ }
+ } finally {
+ cursor.close();
+ }
+ return result;
+ }
+
+ static long findMatchingGrantsCount(SQLiteDatabase db,
+ int uid, String authTokenType, Account account) {
+ String[] args = {String.valueOf(uid), authTokenType,
+ account.name, account.type};
+ return DatabaseUtils
+ .longForQuery(db, COUNT_OF_MATCHING_GRANTS, args);
+ }
+
+ static long findMatchingGrantsCountAnyToken(SQLiteDatabase db,
+ int uid, Account account) {
+ String[] args = {String.valueOf(uid), account.name, account.type};
+ return DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS_ANY_TOKEN, args);
+ }
+
+ static long insertGrant(SQLiteDatabase db, long accountId, String authTokenType, int uid) {
+ ContentValues values = new ContentValues();
+ values.put(GRANTS_ACCOUNTS_ID, accountId);
+ values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
+ values.put(GRANTS_GRANTEE_UID, uid);
+ return db.insert(
+ TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
+ }
+
+ static boolean deleteGrantsByUid(SQLiteDatabase db, int uid) {
+ return db.delete(
+ TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
+ new String[]{Integer.toString(uid)}) > 0;
+ }
+
+ static long insertMetaAuthTypeAndUid(SQLiteDatabase db, String authenticatorType, int uid) {
+ ContentValues values = new ContentValues();
+ values.put(META_KEY,
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
+ values.put(META_VALUE, uid);
+ return db.insert(TABLE_META, null, values);
+ }
+
+ static long insertOrReplaceMetaAuthTypeAndUid(SQLiteDatabase db, String authenticatorType,
+ int uid) {
+ ContentValues values = new ContentValues();
+ values.put(META_KEY,
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
+ values.put(META_VALUE, uid);
+ return db.insertWithOnConflict(TABLE_META, null, values,
+ SQLiteDatabase.CONFLICT_REPLACE);
+ }
+
+ static Map<String, Integer> findMetaAuthUid(SQLiteDatabase db) {
+ Cursor metaCursor = db.query(
+ TABLE_META,
+ new String[]{META_KEY, META_VALUE},
+ SELECTION_META_BY_AUTHENTICATOR_TYPE,
+ new String[]{META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + "%"},
+ null /* groupBy */,
+ null /* having */,
+ META_KEY);
+ Map<String, Integer> map = new LinkedHashMap<>();
+ try {
+ while (metaCursor.moveToNext()) {
+ String type = TextUtils
+ .split(metaCursor.getString(0), META_KEY_DELIMITER)[1];
+ String uidStr = metaCursor.getString(1);
+ if (TextUtils.isEmpty(type) || TextUtils.isEmpty(uidStr)) {
+ // Should never happen.
+ Slog.e(TAG, "Auth type empty: " + TextUtils.isEmpty(type)
+ + ", uid empty: " + TextUtils.isEmpty(uidStr));
+ continue;
+ }
+ int uid = Integer.parseInt(metaCursor.getString(1));
+ map.put(type, uid);
+ }
+ } finally {
+ metaCursor.close();
+ }
+ return map;
+ }
+
+ static boolean deleteMetaByAuthTypeAndUid(SQLiteDatabase db, String type, int uid) {
+ return db.delete(
+ TABLE_META,
+ META_KEY + "=? AND " + META_VALUE + "=?",
+ new String[]{
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
+ String.valueOf(uid)}
+ ) > 0;
+ }
+
+ static List<Pair<String, Integer>> findAllAccountGrants(SQLiteDatabase db) {
+ try (Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null)) {
+ if (cursor == null || !cursor.moveToFirst()) {
+ return Collections.emptyList();
+ }
+ List<Pair<String, Integer>> results = new ArrayList<>();
+ do {
+ final String accountName = cursor.getString(0);
+ final int uid = cursor.getInt(1);
+ results.add(Pair.create(accountName, uid));
+ } while (cursor.moveToNext());
+ return results;
+ }
+ }
+
+ static DeDatabaseHelper create(
+ Context context,
+ int userId,
+ File preNDatabaseFile,
+ File deDatabaseFile) {
+ boolean newDbExists = deDatabaseFile.exists();
+ DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId,
+ deDatabaseFile.getPath());
+ // If the db just created, and there is a legacy db, migrate it
+ if (!newDbExists && preNDatabaseFile.exists()) {
+ // Migrate legacy db to the latest version - PRE_N_DATABASE_VERSION
+ PreNDatabaseHelper
+ preNDatabaseHelper = new PreNDatabaseHelper(context, userId,
+ preNDatabaseFile.getPath());
+ // Open the database to force upgrade if required
+ preNDatabaseHelper.getWritableDatabase();
+ preNDatabaseHelper.close();
+ // Move data without SPII to DE
+ deDatabaseHelper.migratePreNDbToDe(preNDatabaseFile);
+ }
+ return deDatabaseHelper;
+ }
+ }
+
+ static class PreNDatabaseHelper extends SQLiteOpenHelper {
+ private final Context mContext;
+ private final int mUserId;
+
+ public PreNDatabaseHelper(Context context, int userId, String preNDatabaseName) {
+ super(context, preNDatabaseName, null, PRE_N_DATABASE_VERSION);
+ mContext = context;
+ mUserId = userId;
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ // We use PreNDatabaseHelper only if pre-N db exists
+ throw new IllegalStateException("Legacy database cannot be created - only upgraded!");
+ }
+
+ private void createSharedAccountsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+ }
+
+ private void addLastSuccessfullAuthenticatedTimeColumn(SQLiteDatabase db) {
+ db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN "
+ + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " DEFAULT 0");
+ }
+
+ private void addOldAccountNameColumn(SQLiteDatabase db) {
+ db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN " + ACCOUNTS_PREVIOUS_NAME);
+ }
+
+ private void addDebugTable(SQLiteDatabase db) {
+ DebugDbHelper.createDebugTable(db);
+ }
+
+ private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_AUTHTOKENS
+ + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " DELETE FROM " + TABLE_EXTRAS
+ + " WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " DELETE FROM " + TABLE_GRANTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ private void createGrantsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
+ + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL, "
+ + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
+ + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+ + "," + GRANTS_GRANTEE_UID + "))");
+ }
+
+ private void populateMetaTableWithAuthTypeAndUID(SQLiteDatabase db,
+ Map<String, Integer> authTypeAndUIDMap) {
+ for (Map.Entry<String, Integer> entry : authTypeAndUIDMap.entrySet()) {
+ DeDatabaseHelper.insertMetaAuthTypeAndUid(db, entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Pre-N database may need an upgrade before splitting
+ */
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion == 1) {
+ // no longer need to do anything since the work is done
+ // when upgrading from version 2
+ oldVersion++;
+ }
+
+ if (oldVersion == 2) {
+ createGrantsTable(db);
+ db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
+ createAccountsDeletionTrigger(db);
+ oldVersion++;
+ }
+
+ if (oldVersion == 3) {
+ db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
+ " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
+ oldVersion++;
+ }
+
+ if (oldVersion == 4) {
+ createSharedAccountsTable(db);
+ oldVersion++;
+ }
+
+ if (oldVersion == 5) {
+ addOldAccountNameColumn(db);
+ oldVersion++;
+ }
+
+ if (oldVersion == 6) {
+ addLastSuccessfullAuthenticatedTimeColumn(db);
+ oldVersion++;
+ }
+
+ if (oldVersion == 7) {
+ addDebugTable(db);
+ oldVersion++;
+ }
+
+ if (oldVersion == 8) {
+ populateMetaTableWithAuthTypeAndUID(
+ db,
+ AccountManagerService.getAuthenticatorTypeAndUIDForUser(mContext, mUserId));
+ oldVersion++;
+ }
+
+ if (oldVersion != newVersion) {
+ Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+ }
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
+ }
+ }
+
+ static class DebugDbHelper{
+ private DebugDbHelper() {
+ }
+
+
+ private static void createDebugTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_DEBUG + " ( "
+ + ACCOUNTS_ID + " INTEGER,"
+ + DEBUG_TABLE_ACTION_TYPE + " TEXT NOT NULL, "
+ + DEBUG_TABLE_TIMESTAMP + " DATETIME,"
+ + DEBUG_TABLE_CALLER_UID + " INTEGER NOT NULL,"
+ + DEBUG_TABLE_TABLE_NAME + " TEXT NOT NULL,"
+ + DEBUG_TABLE_KEY + " INTEGER PRIMARY KEY)");
+ db.execSQL("CREATE INDEX timestamp_index ON " + TABLE_DEBUG + " ("
+ + DEBUG_TABLE_TIMESTAMP + ")");
+ }
+
+ static SQLiteStatement compileSqlStatementForLogging(SQLiteDatabase db) {
+ String sql = "INSERT OR REPLACE INTO " + AccountsDb.TABLE_DEBUG
+ + " VALUES (?,?,?,?,?,?)";
+ return db.compileStatement(sql);
+ }
+
+ static int getDebugTableRowCount(SQLiteDatabase db) {
+ String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + TABLE_DEBUG;
+ return (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+ }
+
+ /*
+ * Finds the row key where the next insertion should take place. This should
+ * be invoked only if the table has reached its full capacity.
+ */
+ static int getDebugTableInsertionPoint(SQLiteDatabase db) {
+ // This query finds the smallest timestamp value (and if 2 records have
+ // same timestamp, the choose the lower id).
+ String queryCountDebugDbRows = "SELECT " + DEBUG_TABLE_KEY +
+ " FROM " + TABLE_DEBUG +
+ " ORDER BY " + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_KEY +
+ " LIMIT 1";
+ return (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+ }
+
+ static void dumpDebugTable(SQLiteDatabase db, PrintWriter pw) {
+ Cursor cursor = db.query(TABLE_DEBUG, null,
+ null, null, null, null, DEBUG_TABLE_TIMESTAMP);
+ pw.println("AccountId, Action_Type, timestamp, UID, TableName, Key");
+ pw.println("Accounts History");
+ try {
+ while (cursor.moveToNext()) {
+ // print type,count
+ pw.println(cursor.getString(0) + "," + cursor.getString(1) + "," +
+ cursor.getString(2) + "," + cursor.getString(3) + ","
+ + cursor.getString(4) + "," + cursor.getString(5));
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ }
+
+ 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();
+ }
+ }
+
+ static boolean deleteCeAccount(SQLiteDatabase db, long accountId) {
+ return db.delete(
+ CE_TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
+ }
+
+ static void deleteDbFileWarnIfFailed(File dbFile) {
+ if (!SQLiteDatabase.deleteDatabase(dbFile)) {
+ Log.w(TAG, "Database at " + dbFile + " was not deleted successfully");
+ }
+ }
+}