aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/com/android/providers/contacts/AbstractContactsProvider.java205
-rw-r--r--src/com/android/providers/contacts/ContactDirectoryManager.java16
-rw-r--r--src/com/android/providers/contacts/ContactsProvider2.java24
-rw-r--r--src/com/android/providers/contacts/ProfileProvider.java8
4 files changed, 166 insertions, 87 deletions
diff --git a/src/com/android/providers/contacts/AbstractContactsProvider.java b/src/com/android/providers/contacts/AbstractContactsProvider.java
index 1bc59e7e..ebf0a1b9 100644
--- a/src/com/android/providers/contacts/AbstractContactsProvider.java
+++ b/src/com/android/providers/contacts/AbstractContactsProvider.java
@@ -17,7 +17,6 @@
package com.android.providers.contacts;
import com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns;
-import com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
@@ -130,6 +129,11 @@ public abstract class AbstractContactsProvider extends ContentProvider
protected final SparseLongArray mUpdateInBatchStats = new SparseLongArray();
protected final SparseLongArray mDeleteInBatchStats = new SparseLongArray();
+ private final SparseLongArray mOperationDurationMicroStats = new SparseLongArray();
+
+ private final ThreadLocal<Integer> mOperationNest = ThreadLocal.withInitial(() -> 0);
+ private final ThreadLocal<Long> mOperationStartNs = ThreadLocal.withInitial(() -> 0L);
+
@Override
public boolean onCreate() {
Context context = getContext();
@@ -159,6 +163,12 @@ public abstract class AbstractContactsProvider extends ContentProvider
synchronized (mStatsLock) {
stats.put(callingUid, stats.get(callingUid) + 1);
mAllCallingUids.put(callingUid, true);
+
+ final int nest = mOperationNest.get();
+ mOperationNest.set(nest + 1);
+ if (nest == 0) {
+ mOperationStartNs.set(SystemClock.elapsedRealtimeNanos());
+ }
}
}
@@ -169,6 +179,19 @@ public abstract class AbstractContactsProvider extends ContentProvider
incrementStats(inBatch ? statsInBatch : statsNonBatch);
}
+ protected void finishOperation() {
+ final int callingUid = Binder.getCallingUid();
+ synchronized (mStatsLock) {
+ final int nest = mOperationNest.get();
+ mOperationNest.set(nest - 1);
+ if (nest == 1) {
+ final long duration = SystemClock.elapsedRealtimeNanos() - mOperationStartNs.get();
+ mOperationDurationMicroStats.put(callingUid,
+ mOperationDurationMicroStats.get(callingUid) + duration / 1000L);
+ }
+ }
+ }
+
public ContactsTransaction getCurrentTransaction() {
return mTransactionHolder.get();
}
@@ -176,119 +199,139 @@ public abstract class AbstractContactsProvider extends ContentProvider
@Override
public Uri insert(Uri uri, ContentValues values) {
incrementStats(mInsertStats, mInsertInBatchStats);
- ContactsTransaction transaction = startTransaction(false);
try {
- Uri result = insertInTransaction(uri, values);
- if (result != null) {
- transaction.markDirty();
+ ContactsTransaction transaction = startTransaction(false);
+ try {
+ Uri result = insertInTransaction(uri, values);
+ if (result != null) {
+ transaction.markDirty();
+ }
+ transaction.markSuccessful(false);
+ return result;
+ } finally {
+ endTransaction(false);
}
- transaction.markSuccessful(false);
- return result;
} finally {
- endTransaction(false);
+ finishOperation();
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
incrementStats(mDeleteStats, mDeleteInBatchStats);
- ContactsTransaction transaction = startTransaction(false);
try {
- int deleted = deleteInTransaction(uri, selection, selectionArgs);
- if (deleted > 0) {
- transaction.markDirty();
+ ContactsTransaction transaction = startTransaction(false);
+ try {
+ int deleted = deleteInTransaction(uri, selection, selectionArgs);
+ if (deleted > 0) {
+ transaction.markDirty();
+ }
+ transaction.markSuccessful(false);
+ return deleted;
+ } finally {
+ endTransaction(false);
}
- transaction.markSuccessful(false);
- return deleted;
} finally {
- endTransaction(false);
+ finishOperation();
}
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
incrementStats(mUpdateStats, mUpdateInBatchStats);
- ContactsTransaction transaction = startTransaction(false);
try {
- int updated = updateInTransaction(uri, values, selection, selectionArgs);
- if (updated > 0) {
- transaction.markDirty();
+ ContactsTransaction transaction = startTransaction(false);
+ try {
+ int updated = updateInTransaction(uri, values, selection, selectionArgs);
+ if (updated > 0) {
+ transaction.markDirty();
+ }
+ transaction.markSuccessful(false);
+ return updated;
+ } finally {
+ endTransaction(false);
}
- transaction.markSuccessful(false);
- return updated;
} finally {
- endTransaction(false);
+ finishOperation();
}
}
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
incrementStats(mBatchStats);
- ContactsTransaction transaction = startTransaction(true);
- int numValues = values.length;
- int opCount = 0;
try {
- for (int i = 0; i < numValues; i++) {
- insert(uri, values[i]);
- if (++opCount >= BULK_INSERTS_PER_YIELD_POINT) {
- opCount = 0;
- try {
- yield(transaction);
- } catch (RuntimeException re) {
- transaction.markYieldFailed();
- throw re;
+ ContactsTransaction transaction = startTransaction(true);
+ int numValues = values.length;
+ int opCount = 0;
+ try {
+ for (int i = 0; i < numValues; i++) {
+ insert(uri, values[i]);
+ if (++opCount >= BULK_INSERTS_PER_YIELD_POINT) {
+ opCount = 0;
+ try {
+ yield(transaction);
+ } catch (RuntimeException re) {
+ transaction.markYieldFailed();
+ throw re;
+ }
}
}
+ transaction.markSuccessful(true);
+ } finally {
+ endTransaction(true);
}
- transaction.markSuccessful(true);
+ return numValues;
} finally {
- endTransaction(true);
+ finishOperation();
}
- return numValues;
}
@Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
incrementStats(mBatchStats);
- if (VERBOSE_LOGGING) {
- Log.v(TAG, "applyBatch: " + operations.size() + " ops");
- }
- int ypCount = 0;
- int opCount = 0;
- ContactsTransaction transaction = startTransaction(true);
try {
- final int numOperations = operations.size();
- final ContentProviderResult[] results = new ContentProviderResult[numOperations];
- for (int i = 0; i < numOperations; i++) {
- if (++opCount >= MAX_OPERATIONS_PER_YIELD_POINT) {
- throw new OperationApplicationException(
- "Too many content provider operations between yield points. "
- + "The maximum number of operations per yield point is "
- + MAX_OPERATIONS_PER_YIELD_POINT, ypCount);
- }
- final ContentProviderOperation operation = operations.get(i);
- if (i > 0 && operation.isYieldAllowed()) {
- if (VERBOSE_LOGGING) {
- Log.v(TAG, "applyBatch: " + opCount + " ops finished; about to yield...");
+ if (VERBOSE_LOGGING) {
+ Log.v(TAG, "applyBatch: " + operations.size() + " ops");
+ }
+ int ypCount = 0;
+ int opCount = 0;
+ ContactsTransaction transaction = startTransaction(true);
+ try {
+ final int numOperations = operations.size();
+ final ContentProviderResult[] results = new ContentProviderResult[numOperations];
+ for (int i = 0; i < numOperations; i++) {
+ if (++opCount >= MAX_OPERATIONS_PER_YIELD_POINT) {
+ throw new OperationApplicationException(
+ "Too many content provider operations between yield points. "
+ + "The maximum number of operations per yield point is "
+ + MAX_OPERATIONS_PER_YIELD_POINT, ypCount);
}
- opCount = 0;
- try {
- if (yield(transaction)) {
- ypCount++;
+ final ContentProviderOperation operation = operations.get(i);
+ if (i > 0 && operation.isYieldAllowed()) {
+ if (VERBOSE_LOGGING) {
+ Log.v(TAG, "applyBatch: " + opCount + " ops finished; about to yield...");
+ }
+ opCount = 0;
+ try {
+ if (yield(transaction)) {
+ ypCount++;
+ }
+ } catch (RuntimeException re) {
+ transaction.markYieldFailed();
+ throw re;
}
- } catch (RuntimeException re) {
- transaction.markYieldFailed();
- throw re;
}
- }
- results[i] = operation.apply(this, results, i);
+ results[i] = operation.apply(this, results, i);
+ }
+ transaction.markSuccessful(true);
+ return results;
+ } finally {
+ endTransaction(true);
}
- transaction.markSuccessful(true);
- return results;
} finally {
- endTransaction(true);
+ finishOperation();
}
}
@@ -426,20 +469,22 @@ public abstract class AbstractContactsProvider extends ContentProvider
synchronized (mStatsLock) {
pw.println();
pw.println(" Client activities:");
- pw.println(" UID Query Insert Update Delete Batch Insert Update Delete:");
+ pw.println(" UID Query Insert Update Delete Batch Insert Update Delete"
+ + " Sec");
for (int i = 0; i < mAllCallingUids.size(); i++) {
- final int pid = mAllCallingUids.keyAt(i);
+ final int uid = mAllCallingUids.keyAt(i);
pw.println(String.format(
- " %-9d %6d %6d %6d %6d %6d %6d %6d %6d",
- pid,
- mQueryStats.get(pid),
- mInsertStats.get(pid),
- mUpdateStats.get(pid),
- mDeleteStats.get(pid),
- mBatchStats.get(pid),
- mInsertInBatchStats.get(pid),
- mUpdateInBatchStats.get(pid),
- mDeleteInBatchStats.get(pid)
+ " %-9d %6d %6d %6d %6d %6d %6d %6d %6d %12.3f",
+ uid,
+ mQueryStats.get(uid),
+ mInsertStats.get(uid),
+ mUpdateStats.get(uid),
+ mDeleteStats.get(uid),
+ mBatchStats.get(uid),
+ mInsertInBatchStats.get(uid),
+ mUpdateInBatchStats.get(uid),
+ mDeleteInBatchStats.get(uid),
+ (mOperationDurationMicroStats.get(uid) / 1000000.0)
));
}
}
diff --git a/src/com/android/providers/contacts/ContactDirectoryManager.java b/src/com/android/providers/contacts/ContactDirectoryManager.java
index cb6dc4a1..33e541d3 100644
--- a/src/com/android/providers/contacts/ContactDirectoryManager.java
+++ b/src/com/android/providers/contacts/ContactDirectoryManager.java
@@ -104,6 +104,8 @@ public class ContactDirectoryManager {
private final Context mContext;
private final PackageManager mPackageManager;
+ private volatile boolean mDirectoriesForceUpdated = false;
+
public ContactDirectoryManager(ContactsProvider2 contactsProvider) {
mContactsProvider = contactsProvider;
mContext = contactsProvider.getContext();
@@ -114,6 +116,10 @@ public class ContactDirectoryManager {
return (ContactsDatabaseHelper) mContactsProvider.getDatabaseHelper();
}
+ public void setDirectoriesForceUpdated(boolean updated) {
+ mDirectoriesForceUpdated = updated;
+ }
+
/**
* Scans through existing directories to see if the cached resource IDs still
* match their original resource names. If not - plays it safe by refreshing all directories.
@@ -230,6 +236,9 @@ public class ContactDirectoryManager {
Log.d(TAG, "scanAllPackagesIfNeeded()");
}
final long start = SystemClock.elapsedRealtime();
+ // Reset directory updated flag to false. If it's changed to true
+ // then we need to rescan directories.
+ mDirectoriesForceUpdated = false;
final int count = scanAllPackages();
getDbHelper().setProperty(DbProperties.DIRECTORY_SCAN_COMPLETE, "1");
final long end = SystemClock.elapsedRealtime();
@@ -238,6 +247,13 @@ public class ContactDirectoryManager {
// Announce the change to listeners of the contacts authority
mContactsProvider.notifyChange(/* syncToNetwork =*/false,
/* syncToMetadataNetwork =*/false);
+
+ // We schedule a rescan if update(DIRECTORIES) is called while we're scanning all packages.
+ if (mDirectoriesForceUpdated) {
+ mDirectoriesForceUpdated = false;
+ mContactsProvider.scheduleRescanDirectories();
+ }
+
return count;
}
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 66580797..0d2dd9ed 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -252,6 +252,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9;
private static final int BACKGROUND_TASK_CLEANUP_PHOTOS = 10;
private static final int BACKGROUND_TASK_CLEAN_DELETE_LOG = 11;
+ private static final int BACKGROUND_TASK_RESCAN_DIRECTORY = 12;
protected static final int STATUS_NORMAL = 0;
protected static final int STATUS_UPGRADING = 1;
@@ -1779,6 +1780,11 @@ public class ContactsProvider2 extends AbstractContactsProvider
break;
}
+ case BACKGROUND_TASK_RESCAN_DIRECTORY: {
+ updateDirectoriesInBackground(true);
+ break;
+ }
+
case BACKGROUND_TASK_UPDATE_LOCALE: {
updateLocaleInBackground();
break;
@@ -4233,6 +4239,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
}
case DIRECTORIES: {
+ mContactDirectoryManager.setDirectoriesForceUpdated(true);
scanPackagesByUid(Binder.getCallingUid());
count = 1;
break;
@@ -4936,6 +4943,10 @@ public class ContactsProvider2 extends AbstractContactsProvider
scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS);
}
+ public void scheduleRescanDirectories() {
+ scheduleBackgroundTask(BACKGROUND_TASK_RESCAN_DIRECTORY);
+ }
+
interface RawContactsBackupQuery {
String TABLE = Tables.RAW_CONTACTS;
String[] COLUMNS = new String[] {
@@ -5529,12 +5540,15 @@ public class ContactsProvider2 extends AbstractContactsProvider
cancellationSignal);
}
incrementStats(mQueryStats);
+ try {
+ // Otherwise proceed with a normal query against the contacts DB.
+ switchToContactMode();
- // Otherwise proceed with a normal query against the contacts DB.
- switchToContactMode();
-
- return queryDirectoryIfNecessary(uri, projection, selection, selectionArgs, sortOrder,
- cancellationSignal);
+ return queryDirectoryIfNecessary(uri, projection, selection, selectionArgs, sortOrder,
+ cancellationSignal);
+ } finally {
+ finishOperation();
+ }
}
private boolean isCallerFromSameUser() {
diff --git a/src/com/android/providers/contacts/ProfileProvider.java b/src/com/android/providers/contacts/ProfileProvider.java
index 00e7715f..6c84e4b0 100644
--- a/src/com/android/providers/contacts/ProfileProvider.java
+++ b/src/com/android/providers/contacts/ProfileProvider.java
@@ -71,8 +71,12 @@ public class ProfileProvider extends AbstractContactsProvider {
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder, CancellationSignal cancellationSignal) {
incrementStats(mQueryStats);
- return mDelegate.queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1,
- cancellationSignal);
+ try {
+ return mDelegate.queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1,
+ cancellationSignal);
+ } finally {
+ finishOperation();
+ }
}
@Override