Merge "Lazely initialize AccountManager debug table."
am: 18cccec624
Change-Id: If7e12145dfa8e104777956bdab9a743f3f860e24
This commit is contained in:
@@ -241,9 +241,6 @@ public class AccountManagerService
|
|||||||
private final HashMap<Account, AtomicReference<String>> previousNameCache =
|
private final HashMap<Account, AtomicReference<String>> previousNameCache =
|
||||||
new HashMap<Account, AtomicReference<String>>();
|
new HashMap<Account, AtomicReference<String>>();
|
||||||
|
|
||||||
private int debugDbInsertionPoint = -1;
|
|
||||||
private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
|
|
||||||
|
|
||||||
UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
|
UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
synchronized (dbLock) {
|
synchronized (dbLock) {
|
||||||
@@ -1299,7 +1296,6 @@ public class AccountManagerService
|
|||||||
File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
|
File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
|
||||||
File deDbFile = new File(mInjector.getDeDatabaseName(userId));
|
File deDbFile = new File(mInjector.getDeDatabaseName(userId));
|
||||||
accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
|
accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
|
||||||
initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
|
|
||||||
mUsers.append(userId, accounts);
|
mUsers.append(userId, accounts);
|
||||||
purgeOldGrants(accounts);
|
purgeOldGrants(accounts);
|
||||||
validateAccounts = true;
|
validateAccounts = true;
|
||||||
@@ -1399,7 +1395,7 @@ public class AccountManagerService
|
|||||||
if (accounts != null) {
|
if (accounts != null) {
|
||||||
synchronized (accounts.dbLock) {
|
synchronized (accounts.dbLock) {
|
||||||
synchronized (accounts.cacheLock) {
|
synchronized (accounts.cacheLock) {
|
||||||
accounts.statementForLogging.close();
|
accounts.accountsDb.closeDebugStatement();
|
||||||
accounts.accountsDb.close();
|
accounts.accountsDb.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5121,7 +5117,11 @@ public class AccountManagerService
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
SQLiteStatement logStatement = userAccount.statementForLogging;
|
synchronized (userAccount.accountsDb.mDebugStatementLock) {
|
||||||
|
SQLiteStatement logStatement = userAccount.accountsDb.getStatementForLogging();
|
||||||
|
if (logStatement == null) {
|
||||||
|
return; // Can't log.
|
||||||
|
}
|
||||||
logStatement.bindLong(1, accountId);
|
logStatement.bindLong(1, accountId);
|
||||||
logStatement.bindString(2, action);
|
logStatement.bindString(2, action);
|
||||||
logStatement.bindString(3, mDateFormat.format(new Date()));
|
logStatement.bindString(3, mDateFormat.format(new Date()));
|
||||||
@@ -5140,22 +5140,13 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
long insertionPoint = userAccount.accountsDb.reserveDebugDbInsertionPoint();
|
||||||
|
if (insertionPoint != -1) {
|
||||||
LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
|
LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
|
||||||
callingUid, userAccount.debugDbInsertionPoint);
|
callingUid, insertionPoint);
|
||||||
userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
|
|
||||||
% AccountsDb.MAX_DEBUG_DB_SIZE;
|
|
||||||
mHandler.post(logTask);
|
mHandler.post(logTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This should only be called once to compile the sql statement for logging
|
|
||||||
* and to find the insertion point.
|
|
||||||
*/
|
|
||||||
private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
|
|
||||||
userAccount.debugDbInsertionPoint = userAccount.accountsDb
|
|
||||||
.calculateDebugTableInsertionPoint();
|
|
||||||
userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
|
public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
|
||||||
|
|||||||
@@ -17,11 +17,13 @@
|
|||||||
package com.android.server.accounts;
|
package com.android.server.accounts;
|
||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.DatabaseUtils;
|
import android.database.DatabaseUtils;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.database.sqlite.SQLiteStatement;
|
import android.database.sqlite.SQLiteStatement;
|
||||||
import android.os.FileUtils;
|
import android.os.FileUtils;
|
||||||
@@ -56,7 +58,6 @@ class AccountsDb implements AutoCloseable {
|
|||||||
private static final int CE_DATABASE_VERSION = 10;
|
private static final int CE_DATABASE_VERSION = 10;
|
||||||
private static final int DE_DATABASE_VERSION = 3; // Added visibility support in O
|
private static final int DE_DATABASE_VERSION = 3; // Added visibility support in O
|
||||||
|
|
||||||
|
|
||||||
static final String TABLE_ACCOUNTS = "accounts";
|
static final String TABLE_ACCOUNTS = "accounts";
|
||||||
private static final String ACCOUNTS_ID = "_id";
|
private static final String ACCOUNTS_ID = "_id";
|
||||||
private static final String ACCOUNTS_NAME = "name";
|
private static final String ACCOUNTS_NAME = "name";
|
||||||
@@ -183,6 +184,10 @@ class AccountsDb implements AutoCloseable {
|
|||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final File mPreNDatabaseFile;
|
private final File mPreNDatabaseFile;
|
||||||
|
|
||||||
|
final Object mDebugStatementLock = new Object();
|
||||||
|
private volatile long mDebugDbInsertionPoint = -1;
|
||||||
|
private volatile SQLiteStatement mDebugStatementForLogging; // not thread safe.
|
||||||
|
|
||||||
AccountsDb(DeDatabaseHelper deDatabase, Context context, File preNDatabaseFile) {
|
AccountsDb(DeDatabaseHelper deDatabase, Context context, File preNDatabaseFile) {
|
||||||
mDeDatabase = deDatabase;
|
mDeDatabase = deDatabase;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
@@ -1278,7 +1283,8 @@ class AccountsDb implements AutoCloseable {
|
|||||||
* Finds the row key where the next insertion should take place. Returns number of rows
|
* Finds the row key where the next insertion should take place. Returns number of rows
|
||||||
* if it is less {@link #MAX_DEBUG_DB_SIZE}, otherwise finds the lowest number available.
|
* if it is less {@link #MAX_DEBUG_DB_SIZE}, otherwise finds the lowest number available.
|
||||||
*/
|
*/
|
||||||
int calculateDebugTableInsertionPoint() {
|
long calculateDebugTableInsertionPoint() {
|
||||||
|
try {
|
||||||
SQLiteDatabase db = mDeDatabase.getReadableDatabase();
|
SQLiteDatabase db = mDeDatabase.getReadableDatabase();
|
||||||
String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + TABLE_DEBUG;
|
String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + TABLE_DEBUG;
|
||||||
int size = (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
|
int size = (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
|
||||||
@@ -1288,21 +1294,61 @@ class AccountsDb implements AutoCloseable {
|
|||||||
|
|
||||||
// This query finds the smallest timestamp value (and if 2 records have
|
// This query finds the smallest timestamp value (and if 2 records have
|
||||||
// same timestamp, the choose the lower id).
|
// same timestamp, the choose the lower id).
|
||||||
queryCountDebugDbRows = "SELECT " + DEBUG_TABLE_KEY +
|
queryCountDebugDbRows =
|
||||||
" FROM " + TABLE_DEBUG +
|
"SELECT " + DEBUG_TABLE_KEY
|
||||||
" ORDER BY " + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_KEY +
|
+ " FROM " + TABLE_DEBUG
|
||||||
" LIMIT 1";
|
+ " ORDER BY " + DEBUG_TABLE_TIMESTAMP + ","
|
||||||
return (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
|
+ DEBUG_TABLE_KEY
|
||||||
|
+ " LIMIT 1";
|
||||||
|
return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
|
||||||
|
} catch (SQLiteException e) {
|
||||||
|
Log.e(TAG, "Failed to open debug table" + e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLiteStatement compileSqlStatementForLogging() {
|
SQLiteStatement compileSqlStatementForLogging() {
|
||||||
// TODO b/31708085 Fix debug logging - it eagerly opens database for write without a need
|
|
||||||
SQLiteDatabase db = mDeDatabase.getWritableDatabase();
|
SQLiteDatabase db = mDeDatabase.getWritableDatabase();
|
||||||
String sql = "INSERT OR REPLACE INTO " + AccountsDb.TABLE_DEBUG
|
String sql = "INSERT OR REPLACE INTO " + AccountsDb.TABLE_DEBUG
|
||||||
+ " VALUES (?,?,?,?,?,?)";
|
+ " VALUES (?,?,?,?,?,?)";
|
||||||
return db.compileStatement(sql);
|
return db.compileStatement(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns statement for logging or {@code null} on database open failure.
|
||||||
|
* Returned value must be guarded by {link #debugStatementLock}
|
||||||
|
*/
|
||||||
|
@Nullable SQLiteStatement getStatementForLogging() {
|
||||||
|
if (mDebugStatementForLogging != null) {
|
||||||
|
return mDebugStatementForLogging;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mDebugStatementForLogging = compileSqlStatementForLogging();
|
||||||
|
return mDebugStatementForLogging;
|
||||||
|
} catch (SQLiteException e) {
|
||||||
|
Log.e(TAG, "Failed to open debug table" + e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeDebugStatement() {
|
||||||
|
synchronized (mDebugStatementLock) {
|
||||||
|
if (mDebugStatementForLogging != null) {
|
||||||
|
mDebugStatementForLogging.close();
|
||||||
|
mDebugStatementForLogging = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long reserveDebugDbInsertionPoint() {
|
||||||
|
if (mDebugDbInsertionPoint == -1) {
|
||||||
|
mDebugDbInsertionPoint = calculateDebugTableInsertionPoint();
|
||||||
|
return mDebugDbInsertionPoint;
|
||||||
|
}
|
||||||
|
mDebugDbInsertionPoint = (mDebugDbInsertionPoint + 1) % MAX_DEBUG_DB_SIZE;
|
||||||
|
return mDebugDbInsertionPoint;
|
||||||
|
}
|
||||||
|
|
||||||
void dumpDebugTable(PrintWriter pw) {
|
void dumpDebugTable(PrintWriter pw) {
|
||||||
SQLiteDatabase db = mDeDatabase.getReadableDatabase();
|
SQLiteDatabase db = mDeDatabase.getReadableDatabase();
|
||||||
Cursor cursor = db.query(TABLE_DEBUG, null,
|
Cursor cursor = db.query(TABLE_DEBUG, null,
|
||||||
|
|||||||
@@ -17,12 +17,21 @@
|
|||||||
|
|
||||||
package com.android.server.accounts;
|
package com.android.server.accounts;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteStatement;
|
||||||
|
import android.os.Build;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
import android.os.Build;
|
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
@@ -30,17 +39,15 @@ import org.junit.After;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.PrintWriter;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link AccountsDb}.
|
* Tests for {@link AccountsDb}.
|
||||||
* <p>Run with:<pre>
|
* <p>Run with:<pre>
|
||||||
@@ -63,8 +70,11 @@ public class AccountsDbTest {
|
|||||||
private File deDb;
|
private File deDb;
|
||||||
private File ceDb;
|
private File ceDb;
|
||||||
|
|
||||||
|
@Mock private PrintWriter mMockWriter;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
Context context = InstrumentationRegistry.getContext();
|
Context context = InstrumentationRegistry.getContext();
|
||||||
preNDb = new File(context.getCacheDir(), PREN_DB);
|
preNDb = new File(context.getCacheDir(), PREN_DB);
|
||||||
ceDb = new File(context.getCacheDir(), CE_DB);
|
ceDb = new File(context.getCacheDir(), CE_DB);
|
||||||
@@ -443,4 +453,33 @@ public class AccountsDbTest {
|
|||||||
assertTrue(mAccountsDb.deleteDeAccount(accId)); // Trigger should remove visibility.
|
assertTrue(mAccountsDb.deleteDeAccount(accId)); // Trigger should remove visibility.
|
||||||
assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
|
assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDumpDebugTable() {
|
||||||
|
long accId = 10;
|
||||||
|
long insertionPoint = mAccountsDb.reserveDebugDbInsertionPoint();
|
||||||
|
|
||||||
|
SQLiteStatement logStatement = mAccountsDb.getStatementForLogging();
|
||||||
|
|
||||||
|
logStatement.bindLong(1, accId);
|
||||||
|
logStatement.bindString(2, "action");
|
||||||
|
logStatement.bindString(3, "date");
|
||||||
|
logStatement.bindLong(4, 10);
|
||||||
|
logStatement.bindString(5, "table");
|
||||||
|
logStatement.bindLong(6, insertionPoint);
|
||||||
|
logStatement.execute();
|
||||||
|
|
||||||
|
mAccountsDb.dumpDebugTable(mMockWriter);
|
||||||
|
|
||||||
|
verify(mMockWriter, times(3)).println(anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReserveDebugDbInsertionPoint() {
|
||||||
|
long insertionPoint = mAccountsDb.reserveDebugDbInsertionPoint();
|
||||||
|
long insertionPoint2 = mAccountsDb.reserveDebugDbInsertionPoint();
|
||||||
|
|
||||||
|
assertEquals(0, insertionPoint);
|
||||||
|
assertEquals(1, insertionPoint2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user