aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Gunn <tgunn@google.com>2021-05-25 16:43:23 -0700
committerTyler Gunn <tgunn@google.com>2021-05-25 16:43:23 -0700
commit7f70b88e9759b2cdbe3c18a8321df569bbb8d509 (patch)
treeaa97994dadf566dabb900488a30c8c102351623f
parent1a4b0cc01b9738939a5173b6016b00860615a1fd (diff)
downloadContactsProvider-7f70b88e9759b2cdbe3c18a8321df569bbb8d509.tar.gz
Fix issue with call log last modified not being updated.
In the past a security update was done which replaced usage of the DbModifierWithNotification class with SQLiteQueryBuilders. This solved the security issue but caused all the code in the DbModifierWithNotification update and delete methods to no longer run. This includes notifying of new written voicemails, updating the last modified date for rows, and notifying content observers. We cleaned up the content observer issue in QPR, so it was time to swing back and clean the rest up. In the end it just makes more sense to use SQLiteQueryBuilder instances in DbModifierWithNotification for the user-provided queries; this lets the rest of the update code which resided in that class still operate in the same manner as it used to. Test: Run unit tests Test: Run CTS tests Test: Add new CTS test to verify call log last modified gets updated. Fixes: 177421643 Change-Id: Idc73df91cb1a0f4e77a4c5d2a288ab6ff2f6fc77
-rw-r--r--src/com/android/providers/contacts/CallLogProvider.java52
-rw-r--r--src/com/android/providers/contacts/DbModifierWithNotification.java32
2 files changed, 41 insertions, 43 deletions
diff --git a/src/com/android/providers/contacts/CallLogProvider.java b/src/com/android/providers/contacts/CallLogProvider.java
index b1337975..c832e9b4 100644
--- a/src/com/android/providers/contacts/CallLogProvider.java
+++ b/src/com/android/providers/contacts/CallLogProvider.java
@@ -193,7 +193,7 @@ public class CallLogProvider extends ContentProvider {
CALL_COMPOSER_PICTURE);
}
- private static final ArrayMap<String, String> sCallsProjectionMap;
+ public static final ArrayMap<String, String> sCallsProjectionMap;
static {
// Calls projection map
@@ -806,19 +806,8 @@ public class CallLogProvider extends ContentProvider {
SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
checkVoicemailPermissionAndAddRestriction(uri, selectionBuilder, false /*isQuery*/);
-
- final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(Tables.CALLS);
- qb.setProjectionMap(sCallsProjectionMap);
- qb.setStrict(true);
- // If the caller doesn't have READ_VOICEMAIL, make sure they can't
- // do any SQL shenanigans to get access to the voicemails. If the caller does have the
- // READ_VOICEMAIL permission, then they have sufficient permissions to access any data in
- // the database, so the strict check is unnecessary.
- if (!mVoicemailPermissions.callerHasReadAccess(getCallingPackage())) {
- qb.setStrictGrammar(true);
- }
-
+ boolean hasReadVoicemailPermission = mVoicemailPermissions.callerHasReadAccess(
+ getCallingPackage());
final SQLiteDatabase db = mDbHelper.getWritableDatabase();
final int matchedUriId = sURIMatcher.match(uri);
switch (matchedUriId) {
@@ -833,11 +822,8 @@ public class CallLogProvider extends ContentProvider {
throw new UnsupportedOperationException("Cannot update URL: " + uri);
}
- int rowsUpdated = qb.update(db, values, selectionBuilder.build(), selectionArgs);
- if (rowsUpdated > 0) {
- DbModifierWithNotification.notifyCallLogChange(getContext());
- }
- return rowsUpdated;
+ return createDatabaseModifier(db, hasReadVoicemailPermission).update(uri, Tables.CALLS,
+ values, selectionBuilder.build(), selectionArgs);
}
private int deleteInternal(Uri uri, String selection, String[] selectionArgs) {
@@ -852,29 +838,14 @@ public class CallLogProvider extends ContentProvider {
SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
checkVoicemailPermissionAndAddRestriction(uri, selectionBuilder, false /*isQuery*/);
- final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(Tables.CALLS);
- qb.setProjectionMap(sCallsProjectionMap);
- qb.setStrict(true);
- // If the caller doesn't have READ_VOICEMAIL, make sure they can't
- // do any SQL shenanigans to get access to the voicemails. If the caller does have the
- // READ_VOICEMAIL permission, then they have sufficient permissions to access any data in
- // the database, so the strict check is unnecessary.
- if (!mVoicemailPermissions.callerHasReadAccess(getCallingPackage())) {
- qb.setStrictGrammar(true);
- }
-
+ boolean hasReadVoicemailPermission =
+ mVoicemailPermissions.callerHasReadAccess(getCallingPackage());
final SQLiteDatabase db = mDbHelper.getWritableDatabase();
final int matchedUriId = sURIMatcher.match(uri);
switch (matchedUriId) {
case CALLS:
- // TODO: Special case - We may want to forward the delete request on user 0 to the
- // shadow provider too.
- int deletedCount = qb.delete(db, selectionBuilder.build(), selectionArgs);
- if (deletedCount > 0) {
- DbModifierWithNotification.notifyCallLogChange(getContext());
- }
- return deletedCount;
+ return createDatabaseModifier(db, hasReadVoicemailPermission).delete(Tables.CALLS,
+ selectionBuilder.build(), selectionArgs);
case CALL_COMPOSER_PICTURE:
// TODO(hallliu): implement deletion of file when the corresponding calllog entry
// gets deleted as well.
@@ -892,8 +863,9 @@ public class CallLogProvider extends ContentProvider {
* Returns a {@link DatabaseModifier} that takes care of sending necessary notifications
* after the operation is performed.
*/
- private DatabaseModifier createDatabaseModifier(SQLiteDatabase db) {
- return new DbModifierWithNotification(Tables.CALLS, db, getContext());
+ private DatabaseModifier createDatabaseModifier(SQLiteDatabase db, boolean hasReadVoicemail) {
+ return new DbModifierWithNotification(Tables.CALLS, db, null, hasReadVoicemail,
+ getContext());
}
/**
diff --git a/src/com/android/providers/contacts/DbModifierWithNotification.java b/src/com/android/providers/contacts/DbModifierWithNotification.java
index 03ebd1f1..dc74c0ab 100644
--- a/src/com/android/providers/contacts/DbModifierWithNotification.java
+++ b/src/com/android/providers/contacts/DbModifierWithNotification.java
@@ -27,6 +27,7 @@ import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils.InsertHelper;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Binder;
import android.provider.CallLog.Calls;
@@ -65,6 +66,7 @@ public class DbModifierWithNotification implements DatabaseModifier {
Voicemails.DELETED + " == 0";
private final String mTableName;
private final SQLiteDatabase mDb;
+ private final boolean mHasReadVoicemailPermission;
private final InsertHelper mInsertHelper;
private final Context mContext;
private final Uri mBaseUri;
@@ -86,8 +88,14 @@ public class DbModifierWithNotification implements DatabaseModifier {
private DbModifierWithNotification(String tableName, SQLiteDatabase db,
InsertHelper insertHelper, Context context) {
+ this(tableName, db, insertHelper, true /* hasReadVoicemail */, context);
+ }
+
+ public DbModifierWithNotification(String tableName, SQLiteDatabase db,
+ InsertHelper insertHelper, boolean hasReadVoicemailPermission, Context context) {
mTableName = tableName;
mDb = db;
+ mHasReadVoicemailPermission = hasReadVoicemailPermission;
mInsertHelper = insertHelper;
mContext = context;
mBaseUri = mTableName.equals(Tables.VOICEMAIL_STATUS) ?
@@ -196,7 +204,16 @@ public class DbModifierWithNotification implements DatabaseModifier {
if (values.isEmpty()) {
return 0;
}
- int count = mDb.update(table, values, whereClause, whereArgs);
+
+ final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ qb.setTables(mTableName);
+ qb.setProjectionMap(CallLogProvider.sCallsProjectionMap);
+ qb.setStrict(true);
+ if (!mHasReadVoicemailPermission) {
+ qb.setStrictGrammar(true);
+ }
+ int count = qb.update(mDb, values, whereClause, whereArgs);
+
if (count > 0 && isVoicemailContent || Tables.VOICEMAIL_STATUS.equals(table)) {
notifyVoicemailChange(mBaseUri, packagesModified);
}
@@ -269,14 +286,23 @@ public class DbModifierWithNotification implements DatabaseModifier {
// If the deletion is being made by the package that inserted the voicemail or by
// CP2 (cleanup after uninstall), then we don't need to wait for sync, so just delete it.
final int count;
+
+ final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ qb.setTables(mTableName);
+ qb.setProjectionMap(CallLogProvider.sCallsProjectionMap);
+ qb.setStrict(true);
+ if (!mHasReadVoicemailPermission) {
+ qb.setStrictGrammar(true);
+ }
+
if (mIsCallsTable && isVoicemail && !isSelfModifyingOrInternal(packagesModified)) {
ContentValues values = new ContentValues();
values.put(VoicemailContract.Voicemails.DIRTY, 1);
values.put(VoicemailContract.Voicemails.DELETED, 1);
values.put(VoicemailContract.Voicemails.LAST_MODIFIED, getTimeMillis());
- count = mDb.update(table, values, whereClause, whereArgs);
+ count = qb.update(mDb, values, whereClause, whereArgs);
} else {
- count = mDb.delete(table, whereClause, whereArgs);
+ count = qb.delete(mDb, whereClause, whereArgs);
}
if (count > 0 && isVoicemail) {