Fix bug of permanently deleting SmsProvider rows doesn't work.
When SmsProvider#delete is called to delete rows permanently, it
directs to the wrong database thus always fails. This change is to
fix the problem.
Bug: 77974098
Test: unittest
Change-Id: Ic2235daeec01f75e8666d3af85a3581aa61931ea
Merged-In: Ic2235daeec01f75e8666d3af85a3581aa61931ea
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index 4b84fe5..da371bf 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -889,30 +889,32 @@
"content_url TEXT," +
"offset INTEGER);";
+ /**
+ * This table is used by the SMS dispatcher to hold
+ * incomplete partial messages until all the parts arrive.
+ */
+ @VisibleForTesting
+ public static String CREATE_RAW_TABLE_STRING =
+ "CREATE TABLE raw (" +
+ "_id INTEGER PRIMARY KEY," +
+ "date INTEGER," +
+ "reference_number INTEGER," + // one per full message
+ "count INTEGER," + // the number of parts
+ "sequence INTEGER," + // the part number of this message
+ "destination_port INTEGER," +
+ "address TEXT," +
+ "sub_id INTEGER DEFAULT " + SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " +
+ "pdu TEXT," + // the raw PDU for this part
+ "deleted INTEGER DEFAULT 0," + // bool to indicate if row is deleted
+ "message_body TEXT," + // message body
+ "display_originating_addr TEXT);";
+ // email address if from an email gateway, otherwise same as address
private void createSmsTables(SQLiteDatabase db) {
// N.B.: Whenever the columns here are changed, the columns in
// {@ref MmsSmsProvider} must be changed to match.
db.execSQL(CREATE_SMS_TABLE_STRING);
- /**
- * This table is used by the SMS dispatcher to hold
- * incomplete partial messages until all the parts arrive.
- */
- db.execSQL("CREATE TABLE raw (" +
- "_id INTEGER PRIMARY KEY," +
- "date INTEGER," +
- "reference_number INTEGER," + // one per full message
- "count INTEGER," + // the number of parts
- "sequence INTEGER," + // the part number of this message
- "destination_port INTEGER," +
- "address TEXT," +
- "sub_id INTEGER DEFAULT " + SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " +
- "pdu TEXT," + // the raw PDU for this part
- "deleted INTEGER DEFAULT 0," + // bool to indicate if row is deleted
- "message_body TEXT," + // message body
- "display_originating_addr TEXT);"
- // email address if from an email gateway, otherwise same as address
- );
+ db.execSQL(CREATE_RAW_TABLE_STRING);
db.execSQL(CREATE_ATTACHMENTS_TABLE_STRING);
diff --git a/src/com/android/providers/telephony/SmsProvider.java b/src/com/android/providers/telephony/SmsProvider.java
index 37a1044..2b40d7e 100644
--- a/src/com/android/providers/telephony/SmsProvider.java
+++ b/src/com/android/providers/telephony/SmsProvider.java
@@ -43,6 +43,8 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.HashMap;
@@ -90,6 +92,8 @@
@Override
public boolean onCreate() {
setAppOps(AppOpsManager.OP_READ_SMS, AppOpsManager.OP_WRITE_SMS);
+ // So we have two database files. One in de, one in ce. Here only "raw" table is in
+ // mDeOpenHelper, other tables are all in mCeOpenHelper.
mDeOpenHelper = MmsSmsDatabaseHelper.getInstanceForDe(getContext());
mCeOpenHelper = MmsSmsDatabaseHelper.getInstanceForCe(getContext());
TelephonyBackupAgent.DeferredSmsMmsRestoreService.startIfFilesExist(getContext());
@@ -280,7 +284,8 @@
}
private SQLiteOpenHelper getDBOpenHelper(int match) {
- if (match == SMS_RAW_MESSAGE) {
+ // Raw table is stored on de database. Other tables are stored in ce database.
+ if (match == SMS_RAW_MESSAGE || match == SMS_RAW_MESSAGE_PERMANENT_DELETE) {
return mDeOpenHelper;
}
return mCeOpenHelper;
@@ -843,9 +848,12 @@
}
// Db open helper for tables stored in CE(Credential Encrypted) storage.
- private SQLiteOpenHelper mCeOpenHelper;
- // Db open helper for tables stored in DE(Device Encrypted) storage.
- private SQLiteOpenHelper mDeOpenHelper;
+ @VisibleForTesting
+ public SQLiteOpenHelper mCeOpenHelper;
+ // Db open helper for tables stored in DE(Device Encrypted) storage. It's currently only used
+ // to store raw table.
+ @VisibleForTesting
+ public SQLiteOpenHelper mDeOpenHelper;
private final static String TAG = "SmsProvider";
private final static String VND_ANDROID_SMS = "vnd.android.cursor.item/sms";
diff --git a/tests/src/com/android/providers/telephony/SmsProviderTest.java b/tests/src/com/android/providers/telephony/SmsProviderTest.java
index 8fba85b..ba63203 100644
--- a/tests/src/com/android/providers/telephony/SmsProviderTest.java
+++ b/tests/src/com/android/providers/telephony/SmsProviderTest.java
@@ -17,12 +17,14 @@
package com.android.providers.telephony;
import android.app.AppOpsManager;
+import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.database.Cursor;
import android.net.Uri;
import android.provider.Telephony;
import android.telephony.TelephonyManager;
@@ -58,6 +60,20 @@
private int notifyChangeCount;
+ private final String mFakePdu = "123abc";
+ private final String mFakeAddress = "FakeAddress";
+ private final String mFakeOriginatingAddr = "FakeDisplayAddress";
+ private final String mFakeMessageBody = "FakeMessageBody";
+ private final int mFakeRefNumber = 123;
+ private final int mFakeSequence = 1;
+ private final int mFakeCount = 1;
+ private final int mFakePort = 1 << 19;
+ private final long mDate = 0;
+
+ private final Uri mRawUri =
+ Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
+ private final Uri mRawUriPermanentDelete =
+ Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");
/**
* This is used to give the SmsProviderTest a mocked context which takes a
@@ -170,4 +186,86 @@
assertEquals(Uri.parse("content://sms/attachments/1"),
mContentResolver.insert(Uri.parse("content://sms/attachments"), values));
}
-}
\ No newline at end of file
+
+ @Test
+ @SmallTest
+ public void testRawTableInsert() {
+ // insert test contentValues
+ assertEquals(Uri.parse("content://sms/raw/1"),
+ mContentResolver.insert(mRawUri, getFakeRawValue()));
+
+ // Query and confirm contents.
+ Cursor cursor = mContentResolver.query(mRawUri, null, null, null, null);
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals(mFakePdu, cursor.getString(cursor.getColumnIndex("pdu")));
+ assertEquals(mFakeAddress, cursor.getString(cursor.getColumnIndex("address")));
+ assertEquals(mFakeOriginatingAddr,
+ cursor.getString(cursor.getColumnIndex("display_originating_addr")));
+ assertEquals(mFakeMessageBody, cursor.getString(cursor.getColumnIndex("message_body")));
+ assertEquals(mDate, cursor.getInt(cursor.getColumnIndex("date")));
+ assertEquals(mFakePort, cursor.getInt(cursor.getColumnIndex("destination_port")));
+ assertEquals(mFakeRefNumber, cursor.getInt(cursor.getColumnIndex("reference_number")));
+ assertEquals(mFakeSequence, cursor.getInt(cursor.getColumnIndex("sequence")));
+ assertEquals(mFakeCount, cursor.getInt(cursor.getColumnIndex("count")));
+ assertEquals(0, cursor.getInt(cursor.getColumnIndex("deleted")));
+
+ // Insert another two.
+ assertEquals(Uri.parse("content://sms/raw/2"),
+ mContentResolver.insert(mRawUri, getFakeRawValue()));
+ assertEquals(Uri.parse("content://sms/raw/3"),
+ mContentResolver.insert(mRawUri, getFakeRawValue()));
+
+ cursor.close();
+ }
+
+ @Test
+ @SmallTest
+ public void testRawTableDelete() throws Exception {
+ assertEquals(Uri.parse("content://sms/raw/1"),
+ mContentResolver.insert(mRawUri, getFakeRawValue()));
+
+ // Mark as deleted.
+ String where = "reference_number=?";
+ String[] whereArgs = {Integer.toString(mFakeRefNumber)};
+ assertEquals(1, mContentResolver.delete(mRawUri, where, whereArgs));
+
+ // The row should still be in table, with column "deleted" to be 1.
+ Cursor cursor = mSmsProviderTestable.mDeOpenHelper.getReadableDatabase().query(
+ "raw", null, null, null, null, null, null);
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals(1, cursor.getInt(cursor.getColumnIndex("deleted")));
+ cursor.close();
+
+ // The deleted row should be purged.
+ cursor = mContentResolver.query(mRawUri, null, null, null, null);
+ assertEquals(0, cursor.getCount());
+
+ // Permanent delete all rows.
+ assertEquals(Uri.parse("content://sms/raw/1"),
+ mContentResolver.insert(mRawUri, getFakeRawValue()));
+ assertEquals(Uri.parse("content://sms/raw/2"),
+ mContentResolver.insert(mRawUri, getFakeRawValue()));
+ assertEquals(2, mContentResolver.delete(mRawUriPermanentDelete, null, null));
+ cursor = mSmsProviderTestable.mDeOpenHelper.getReadableDatabase().query(
+ "raw", null, null, null, null, null, null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
+ }
+
+ private ContentValues getFakeRawValue() {
+ ContentValues values = new ContentValues();
+ values.put("pdu", mFakePdu);
+ values.put("date", mDate);
+ values.put("destination_port", mFakePort);
+ values.put("address", mFakeAddress);
+ values.put("display_originating_addr", mFakeOriginatingAddr);
+ values.put("reference_number", mFakeRefNumber);
+ values.put("sequence", mFakeSequence);
+ values.put("count", mFakeCount);
+ values.put("message_body", mFakeMessageBody);
+
+ return values;
+ }
+}
diff --git a/tests/src/com/android/providers/telephony/SmsProviderTestable.java b/tests/src/com/android/providers/telephony/SmsProviderTestable.java
index 9c3372e..3c077fa 100644
--- a/tests/src/com/android/providers/telephony/SmsProviderTestable.java
+++ b/tests/src/com/android/providers/telephony/SmsProviderTestable.java
@@ -25,30 +25,18 @@
public class SmsProviderTestable extends SmsProvider {
private static final String TAG = "SmsProviderTestable";
- private InMemorySmsProviderDbHelper mDbHelper;
-
@Override
public boolean onCreate() {
Log.d(TAG, "onCreate called: mDbHelper = new InMemorySmsProviderDbHelper()");
- mDbHelper = new InMemorySmsProviderDbHelper();
+ mCeOpenHelper = new InMemorySmsProviderDbHelper();
+ mDeOpenHelper = new InMemorySmsProviderDbHelper();
return true;
}
- @Override
- SQLiteDatabase getReadableDatabase(int match) {
- Log.d(TAG, "getReadableDatabase called");
- return mDbHelper.getReadableDatabase();
- }
-
- @Override
- SQLiteDatabase getWritableDatabase(int match) {
- Log.d(TAG, "getWritableDatabase called");
- return mDbHelper.getWritableDatabase();
- }
-
// close mDbHelper database object
protected void closeDatabase() {
- mDbHelper.close();
+ mCeOpenHelper.close();
+ mDeOpenHelper.close();
}
/**
@@ -70,6 +58,7 @@
// Set up the sms tables
Log.d(TAG, "InMemorySmsProviderDbHelper onCreate creating the sms tables");
db.execSQL(MmsSmsDatabaseHelper.CREATE_SMS_TABLE_STRING);
+ db.execSQL(MmsSmsDatabaseHelper.CREATE_RAW_TABLE_STRING);
db.execSQL(MmsSmsDatabaseHelper.CREATE_ATTACHMENTS_TABLE_STRING);
}