Do exception handling per SMS while restoring messages.
Instead of doing it per backup file which can contain
up to 1000 messages.
Test: atest TelephonyBackupAgentTest
Test: manually tested restore from cloud
Bug: 160801497
Bug: 164485894
Change-Id: Iee030405c88b7fde65abb13ceb83863db798b22c
diff --git a/src/com/android/providers/telephony/TelephonyBackupAgent.java b/src/com/android/providers/telephony/TelephonyBackupAgent.java
index 5c764c8..6fa4bf9 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,30 @@
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) {
+ 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;
+ }
}
+ };
+
+ @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 b1cd5e4..a576c44 100644
--- a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
@@ -616,6 +616,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
*/
@@ -751,11 +780,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);
@@ -771,7 +806,7 @@
modifiedValues.put(Telephony.Sms.ADDRESS, TelephonyBackupAgent.UNKNOWN_SENDER);
}
- assertEquals(modifiedValues, values);
+ if (mCheckInsertedValues) assertEquals(modifiedValues, values);
return null;
}