From 0cb370ba1ed7dfd10ac24be390700534409694da Mon Sep 17 00:00:00 2001 From: Shoki Inoka Date: Thu, 9 Jan 2020 14:48:49 +0900 Subject: [PATCH] Startup WAP PUSH service before handling SMS messages SMS message handling which has been received while the device is locked starts just after unlocking the device. Then WAP PUSH service may not finish starting and WAP PUSH SMS message may not be processed. To resolve the problem, enable to bind WapPushManager during DirectBoot and ensures that SMS messages are processed when unlocked. And change the storage of database used by WapPushManager to support DirectBoot. Test: manual - Confirm that WapPushOverSms#onServiceConnected() is called during DirectBoot. Confirm that WapPushManager#WapPushManager() is called when unlocking the screen. Test: auto - Passed WapPushTest#testDataBaseMigration. Bug: 141654363 Change-Id: I3eebfea6a6da920f9aca674073c2cd3563cbd658 --- packages/WAPPushManager/AndroidManifest.xml | 3 +- .../com/android/smspush/WapPushManager.java | 131 +++++++++++++----- .../smspush/unitTests/WapPushTest.java | 57 +++++++- 3 files changed, 148 insertions(+), 43 deletions(-) diff --git a/packages/WAPPushManager/AndroidManifest.xml b/packages/WAPPushManager/AndroidManifest.xml index 14e6e91e3a25..3da5093c57ec 100644 --- a/packages/WAPPushManager/AndroidManifest.xml +++ b/packages/WAPPushManager/AndroidManifest.xml @@ -25,7 +25,8 @@ + android:allowClearUserData="false" + android:directBootAware="true"> diff --git a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java index dc2707b6ff8b..951e64fab015 100755 --- a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java +++ b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java @@ -26,17 +26,21 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.database.Cursor; -import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; import android.os.Build; import android.os.IBinder; import android.os.PowerManager; import android.os.RemoteException; +import android.os.UserManager; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IWapPushManager; import com.android.internal.telephony.WapPushManagerParams; +import java.io.File; + /** * The WapPushManager service is implemented to process incoming * WAP Push messages and to maintain the Receiver Application/Application @@ -67,8 +71,13 @@ public class WapPushManager extends Service { /** * Inner class that deals with application ID table */ - private class WapPushManDBHelper extends SQLiteOpenHelper { - WapPushManDBHelper(Context context) { + @VisibleForTesting + public static class WapPushManDBHelper extends SQLiteOpenHelper { + /** + * Constructor + */ + @VisibleForTesting + public WapPushManDBHelper(Context context) { super(context, DATABASE_NAME, null, WAP_PUSH_MANAGER_VERSION); if (LOCAL_LOGV) Log.v(LOG_TAG, "helper instance created."); } @@ -269,10 +278,6 @@ public class WapPushManager extends Service { int app_type, boolean need_signature, boolean further_processing) { WapPushManDBHelper dbh = getDatabase(mContext); SQLiteDatabase db = dbh.getWritableDatabase(); - WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, x_app_id, content_type); - boolean ret = false; - boolean insert = false; - int sq = 0; if (!appTypeCheck(app_type)) { Log.w(LOG_TAG, "invalid app_type " + app_type + ". app_type must be " @@ -280,34 +285,8 @@ public class WapPushManager extends Service { + WapPushManagerParams.APP_TYPE_SERVICE); return false; } - - if (lastapp == null) { - insert = true; - sq = 0; - } else if (!lastapp.packageName.equals(package_name) || - !lastapp.className.equals(class_name)) { - insert = true; - sq = lastapp.installOrder + 1; - } - - if (insert) { - ContentValues values = new ContentValues(); - - values.put("x_wap_application", x_app_id); - values.put("content_type", content_type); - values.put("package_name", package_name); - values.put("class_name", class_name); - values.put("app_type", app_type); - values.put("need_signature", need_signature ? 1 : 0); - values.put("further_processing", further_processing ? 1 : 0); - values.put("install_order", sq); - db.insert(APPID_TABLE_NAME, null, values); - if (LOCAL_LOGV) Log.v(LOG_TAG, "add:" + x_app_id + ":" + content_type - + " " + package_name + "." + class_name - + ", newsq:" + sq); - ret = true; - } - + boolean ret = insertPackage(dbh, db, x_app_id, content_type, package_name, class_name, + app_type, need_signature, further_processing); db.close(); return ret; @@ -404,11 +383,91 @@ public class WapPushManager extends Service { protected WapPushManDBHelper getDatabase(Context context) { if (mDbHelper == null) { if (LOCAL_LOGV) Log.v(LOG_TAG, "create new db inst."); - mDbHelper = new WapPushManDBHelper(context); + mDbHelper = new WapPushManDBHelper(context.createDeviceProtectedStorageContext()); } + // Migrate existing legacy database into the device encrypted storage. + migrateWapPushManDBIfNeeded(context); return mDbHelper; } + /** + * Inserts a package information into a database + */ + @VisibleForTesting + public boolean insertPackage(WapPushManDBHelper dbh, SQLiteDatabase db, String appId, + String contentType, String packageName, String className, int appType, + boolean needSignature, boolean furtherProcessing) { + + WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, appId, contentType); + boolean insert = false; + int sq = 0; + + if (lastapp == null) { + insert = true; + sq = 0; + } else if (!lastapp.packageName.equals(packageName) + || !lastapp.className.equals(className)) { + insert = true; + sq = lastapp.installOrder + 1; + } + + if (insert) { + ContentValues values = new ContentValues(); + + values.put("x_wap_application", appId); + values.put("content_type", contentType); + values.put("package_name", packageName); + values.put("class_name", className); + values.put("app_type", appType); + values.put("need_signature", needSignature ? 1 : 0); + values.put("further_processing", furtherProcessing ? 1 : 0); + values.put("install_order", sq); + db.insert(APPID_TABLE_NAME, null, values); + if (LOCAL_LOGV) { + Log.v(LOG_TAG, "add:" + appId + ":" + contentType + " " + packageName + + "." + className + ", newsq:" + sq); + } + return true; + } + return false; + } + + /** + * Migrates a legacy database into the device encrypted storage + */ + private void migrateWapPushManDBIfNeeded(Context context) { + UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + File file = context.getDatabasePath(DATABASE_NAME); + if (!userManager.isUserUnlocked() || !file.exists()) { + // Check if the device is unlocked because a legacy database can't access during + // DirectBoot. + return; + } + + // Migration steps below: + // 1. Merge the package info to legacy database if there is any package info which is + // registered during DirectBoot. + // 2. Move the data base to the device encryped storage. + WapPushManDBHelper legacyDbHelper = new WapPushManDBHelper(context); + SQLiteDatabase legacyDb = legacyDbHelper.getWritableDatabase(); + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + Cursor cur = db.query(APPID_TABLE_NAME, null, null, null, null, null, null); + while (cur.moveToNext()) { + insertPackage(legacyDbHelper, legacyDb, + cur.getString(cur.getColumnIndex("x_wap_application")), + cur.getString(cur.getColumnIndex("content_type")), + cur.getString(cur.getColumnIndex("package_name")), + cur.getString(cur.getColumnIndex("class_name")), + cur.getInt(cur.getColumnIndex("app_type")), + cur.getInt(cur.getColumnIndex("need_signature")) == 1, + cur.getInt(cur.getColumnIndex("further_processing")) == 1); + } + cur.close(); + legacyDb.close(); + db.close(); + context.createDeviceProtectedStorageContext().moveDatabaseFrom(context, DATABASE_NAME); + Log.i(LOG_TAG, "Migrated the legacy database."); + } /** * This method is used for testing diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java index f7afc57f3199..b9dac4e2b28e 100644 --- a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java +++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java @@ -21,6 +21,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.database.sqlite.SQLiteDatabase; import android.os.IBinder; import android.os.RemoteException; import android.provider.Telephony.Sms.Intents; @@ -33,7 +34,9 @@ import com.android.internal.telephony.WspTypeDecoder; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.util.HexDump; import com.android.smspush.WapPushManager; +import com.android.smspush.WapPushManager.WapPushManDBHelper; +import java.io.File; import java.util.Random; /** @@ -467,8 +470,9 @@ public class WapPushTest extends ServiceTestCase { try { super.setUp(); // get verifier - getContext().bindService(new Intent(IDataVerify.class.getName()), - mConn, Context.BIND_AUTO_CREATE); + Intent intent = new Intent(IDataVerify.class.getName()); + intent.setPackage("com.android.smspush.unitTests"); + getContext().bindService(intent, mConn, Context.BIND_AUTO_CREATE); } catch (Exception e) { Log.w(LOG_TAG, "super exception"); } @@ -552,15 +556,15 @@ public class WapPushTest extends ServiceTestCase { } /** - * Add sqlite injection test + * Sqlite injection test */ - public void testAddPackage0() { + public void testSqliteInjection() { String inject = "' union select 0,'com.android.settings','com.android.settings.Settings',0,0,0--"; - // insert new data + // update data IWapPushManager iwapman = getInterface(); try { - assertFalse(iwapman.addPackage( + assertFalse(iwapman.updatePackage( inject, Integer.toString(mContentTypeValue), mPackageName, mClassName, @@ -2528,4 +2532,45 @@ public class WapPushTest extends ServiceTestCase { mMessageBody = originalMessageBody; } + /** + * DataBase migration test. + */ + public void testDataBaseMigration() { + IWapPushManager iwapman = getInterface(); + WapPushManager wpman = getService(); + Context context = getContext(); + + addPackageToLegacyDB(mAppIdValue, mContentTypeValue, mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, true, true); + addPackageToLegacyDB(mAppIdValue + 10, mContentTypeValue, mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, true, true); + + File oldDbFile = context.getDatabasePath("wappush.db"); + assertTrue(oldDbFile.exists()); + assertTrue(wpman.verifyData(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), + mPackageName, mClassName, + WapPushManagerParams.APP_TYPE_SERVICE, true, true)); + assertFalse(oldDbFile.exists()); + + // Clean up DB + try { + iwapman.deletePackage(Integer.toString(mAppIdValue), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + iwapman.deletePackage(Integer.toString(mAppIdValue + 10), + Integer.toString(mContentTypeValue), mPackageName, mClassName); + } catch (RemoteException e) { + assertTrue(false); + } + } + + private void addPackageToLegacyDB(int appId, int contextType, String packagename, + String classnName, int appType, boolean signature, boolean furtherProcessing) { + WapPushManager wpman = getService(); + WapPushManDBHelper dbh = new WapPushManDBHelper(getContext()); + SQLiteDatabase db = dbh.getWritableDatabase(); + + wpman.insertPackage(dbh, db, Integer.toString(appId), Integer.toString(contextType), + packagename, classnName, appType, signature, furtherProcessing); + } }