[automerger skipped] Merge "Merge redfin/bramble support." am: d4e1aeac69 -s ours am: f4318b3ccb -s ours am: 5e7b02bc18 -s ours
am skip reason: Change-Id Id98937603168f422d71acc1006f66b8570a0e0c1 with SHA-1 af2d2d4b17 is in history
Original change: https://android-review.googlesource.com/c/platform/packages/providers/TelephonyProvider/+/1466030
Change-Id: I4bbbcfb8170da640e7aaa7bf3009be88e356b095
diff --git a/src/com/android/providers/telephony/TelephonyBackupAgent.java b/src/com/android/providers/telephony/TelephonyBackupAgent.java
index 958c929..6ce5da1 100644
--- a/src/com/android/providers/telephony/TelephonyBackupAgent.java
+++ b/src/com/android/providers/telephony/TelephonyBackupAgent.java
@@ -631,12 +631,16 @@
ContentValues[] values = new ContentValues[bulkInsertSize];
while (jsonReader.hasNext()) {
ContentValues cv = readSmsValuesFromReader(jsonReader);
- if (doesSmsExist(cv)) {
- continue;
- }
- values[(msgCount++) % bulkInsertSize] = cv;
- if (msgCount % bulkInsertSize == 0) {
- mContentResolver.bulkInsert(Telephony.Sms.CONTENT_URI, values);
+ try {
+ if (mSmsProviderQuery.doesSmsExist(cv)) {
+ continue;
+ }
+ values[(msgCount++) % bulkInsertSize] = cv;
+ if (msgCount % bulkInsertSize == 0) {
+ mContentResolver.bulkInsert(Telephony.Sms.CONTENT_URI, values);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "putSmsMessagesToProvider", e);
}
}
if (msgCount % bulkInsertSize > 0) {
@@ -655,16 +659,20 @@
if (DEBUG) {
Log.d(TAG, "putMmsMessagesToProvider " + mms);
}
- if (doesMmsExist(mms)) {
- if (DEBUG) {
- Log.e(TAG, String.format("Mms: %s already exists", mms.toString()));
- } else {
- Log.w(TAG, "Mms: Found duplicate MMS");
+ try {
+ if (doesMmsExist(mms)) {
+ if (DEBUG) {
+ Log.e(TAG, String.format("Mms: %s already exists", mms.toString()));
+ } else {
+ Log.w(TAG, "Mms: Found duplicate MMS");
+ }
+ continue;
}
- continue;
+ total++;
+ addMmsMessage(mms);
+ } catch (Exception e) {
+ Log.e(TAG, "putMmsMessagesToProvider", e);
}
- total++;
- addMmsMessage(mms);
}
Log.d(TAG, "putMmsMessagesToProvider handled " + total + " new messages.");
}
@@ -673,15 +681,34 @@
static final String[] PROJECTION_ID = {BaseColumns._ID};
private static final int ID_IDX = 0;
- private boolean doesSmsExist(ContentValues smsValues) {
- final String where = String.format(Locale.US, "%s = %d and %s = %s",
- Telephony.Sms.DATE, smsValues.getAsLong(Telephony.Sms.DATE),
- Telephony.Sms.BODY,
- DatabaseUtils.sqlEscapeString(smsValues.getAsString(Telephony.Sms.BODY)));
- try (Cursor cursor = mContentResolver.query(Telephony.Sms.CONTENT_URI, PROJECTION_ID, where,
- null, null)) {
- return cursor != null && cursor.getCount() > 0;
+ /**
+ * Interface to allow mocking method for testing.
+ */
+ public interface SmsProviderQuery {
+ boolean doesSmsExist(ContentValues smsValues);
+ }
+
+ private SmsProviderQuery mSmsProviderQuery = new SmsProviderQuery() {
+ @Override
+ public boolean doesSmsExist(ContentValues smsValues) {
+ // The SMS body might contain '\0' characters (U+0000) such as in the case of
+ // http://b/160801497 . SQLite does not allow '\0' in String literals, but as of SQLite
+ // version 3.32.2 2020-06-04, it does allow them as selectionArgs; therefore, we're
+ // using the latter approach here.
+ final String selection = String.format(Locale.US, "%s=%d AND %s=?",
+ Telephony.Sms.DATE, smsValues.getAsLong(Telephony.Sms.DATE),
+ Telephony.Sms.BODY);
+ String[] selectionArgs = new String[] { smsValues.getAsString(Telephony.Sms.BODY)};
+ try (Cursor cursor = mContentResolver.query(Telephony.Sms.CONTENT_URI, PROJECTION_ID,
+ selection, selectionArgs, null)) {
+ return cursor != null && cursor.getCount() > 0;
+ }
}
+ };
+
+ @VisibleForTesting
+ public void setSmsProviderQuery(SmsProviderQuery smsProviderQuery) {
+ mSmsProviderQuery = smsProviderQuery;
}
private boolean doesMmsExist(Mms mms) {
diff --git a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
index 643a18f..00bb15e 100644
--- a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
@@ -615,6 +615,35 @@
}
/**
+ * Test that crashing for one sms does not block restore of other messages.
+ * @throws Exception
+ */
+ public void testRestoreSms_WithException() throws Exception {
+ mTelephonyBackupAgent.initUnknownSender();
+ JsonReader jsonReader = new JsonReader(new StringReader(addRandomDataToJson(mAllSmsJson)));
+ FakeSmsProvider smsProvider = new FakeSmsProvider(mSmsRows, false);
+ mMockContentResolver.addProvider("sms", smsProvider);
+ TelephonyBackupAgent.SmsProviderQuery smsProviderQuery =
+ new TelephonyBackupAgent.SmsProviderQuery() {
+ int mIteration = 0;
+ @Override
+ public boolean doesSmsExist(ContentValues smsValues) {
+ if (mIteration == 0) {
+ mIteration++;
+ throw new RuntimeException("fake crash for first message");
+ }
+ return false;
+ }
+ };
+ mTelephonyBackupAgent.setSmsProviderQuery(smsProviderQuery);
+
+ mTelephonyBackupAgent.putSmsMessagesToProvider(jsonReader);
+ // the "- 1" is due to exception thrown for one of the messages
+ assertEquals(mSmsRows.length - 1, smsProvider.getRowsAdded());
+ assertEquals(mThreadProvider.mIsThreadArchived, mThreadProvider.mUpdateThreadsArchived);
+ }
+
+ /**
* Test restore mms with the empty json array "[]".
* @throws Exception
*/
@@ -750,11 +779,17 @@
private class FakeSmsProvider extends MockContentProvider {
private int nextRow = 0;
private ContentValues[] mSms;
+ private boolean mCheckInsertedValues = true;
public FakeSmsProvider(ContentValues[] sms) {
this.mSms = sms;
}
+ public FakeSmsProvider(ContentValues[] sms, boolean checkInsertedValues) {
+ this.mSms = sms;
+ mCheckInsertedValues = checkInsertedValues;
+ }
+
@Override
public Uri insert(Uri uri, ContentValues values) {
assertEquals(Telephony.Sms.CONTENT_URI, uri);
@@ -770,7 +805,7 @@
modifiedValues.put(Telephony.Sms.ADDRESS, TelephonyBackupAgent.UNKNOWN_SENDER);
}
- assertEquals(modifiedValues, values);
+ if (mCheckInsertedValues) assertEquals(modifiedValues, values);
return null;
}