Fixed subscription database cache out of sync
The subscription reloading from database could cause cache
to be out-of-sync. Fixed by making reloading synchronous and
only reload when necessary (e.g. Backup restore actually changes
the database).
Fix: 290295550
Fix: 290176403
Test: atest SubscriptionManagerServiceTest TelephonyProviderTests
Test: Manually test backup/restore
Test: Telephony basic functionality tests
Test: Re-tested passed on b/290295550#comment23
Test: Re-tested passed on b/290176403#comment28
Merged-In: Iee0355a4069ce6d5c85ecc1bd727bc457c3bb902
Change-Id: Iee0355a4069ce6d5c85ecc1bd727bc457c3bb902
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
index b90dc5e..124437c 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
@@ -2018,21 +2018,21 @@
}
/**
- * Reload the database from content provider to the cache.
+ * Reload the database from content provider to the cache. This must be a synchronous operation
+ * to prevent cache/database out-of-sync. Callers should be cautious to call this method because
+ * it might take longer time to complete.
*/
- public void reloadDatabase() {
- if (mAsyncMode) {
- post(this::loadDatabaseInternal);
- } else {
- loadDatabaseInternal();
- }
+ public void reloadDatabaseSync() {
+ logl("reloadDatabaseSync");
+ // Synchronously load the database into the cache.
+ loadDatabaseInternal();
}
/**
* Load the database from content provider to the cache.
*/
private void loadDatabaseInternal() {
- log("loadDatabaseInternal");
+ logl("loadDatabaseInternal");
try (Cursor cursor = mContext.getContentResolver().query(
SimInfo.CONTENT_URI, null, null, null, null)) {
mReadWriteLock.writeLock().lock();
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 8e773c0..3872b2c 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -1420,12 +1420,15 @@
}
// Attempt to restore SIM specific settings when SIM is loaded.
- mContext.getContentResolver().call(
+ Bundle result = mContext.getContentResolver().call(
SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI,
SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME,
iccId, null);
- log("Reload the database.");
- mSubscriptionDatabaseManager.reloadDatabase();
+ if (result != null && result.getBoolean(
+ SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_DATABASE_UPDATED)) {
+ logl("Sim specific settings changed the database.");
+ mSubscriptionDatabaseManager.reloadDatabaseSync();
+ }
}
log("updateSubscription: " + mSubscriptionDatabaseManager
@@ -3707,12 +3710,16 @@
Bundle bundle = new Bundle();
bundle.putByteArray(SubscriptionManager.KEY_SIM_SPECIFIC_SETTINGS_DATA, data);
logl("restoreAllSimSpecificSettingsFromBackup");
- mContext.getContentResolver().call(
+ Bundle result = mContext.getContentResolver().call(
SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI,
SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME,
null, bundle);
- // After restoring, we need to reload the content provider into the cache.
- mSubscriptionDatabaseManager.reloadDatabase();
+
+ if (result != null && result.getBoolean(
+ SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_DATABASE_UPDATED)) {
+ logl("Sim specific settings changed the database.");
+ mSubscriptionDatabaseManager.reloadDatabaseSync();
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
index 9898353..0358809 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
@@ -269,6 +269,8 @@
private final List<String> mAllColumns;
+ private boolean mDatabaseChanged;
+
SubscriptionProvider() {
mAllColumns = SimInfo.getAllColumns();
}
@@ -378,7 +380,17 @@
@Override
public Bundle call(String method, @Nullable String args, @Nullable Bundle bundle) {
- return new Bundle();
+ Bundle result = new Bundle();
+ if (method.equals(SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME)) {
+ result.putBoolean(
+ SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_DATABASE_UPDATED,
+ mDatabaseChanged);
+ }
+ return result;
+ }
+
+ public void setRestoreDatabaseChanged(boolean changed) {
+ mDatabaseChanged = changed;
}
}
@@ -422,7 +434,7 @@
.that(mDatabaseManagerUT.getSubscriptionInfoInternal(subId)).isEqualTo(subInfo);
// Load subscription info from the database.
- mDatabaseManagerUT.reloadDatabase();
+ mDatabaseManagerUT.reloadDatabaseSync();
processAllMessages();
// Verify the database value is same as the inserted one.
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
index 3abfac7..ba6f046 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -69,8 +69,10 @@
import android.app.AppOpsManager;
import android.app.PropertyInvalidatedCache;
import android.compat.testing.PlatformCompatChangeRule;
+import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -2212,16 +2214,40 @@
}
@Test
- public void testRestoreAllSimSpecificSettingsFromBackup() {
+ public void testRestoreAllSimSpecificSettingsFromBackup() throws Exception {
assertThrows(SecurityException.class, ()
-> mSubscriptionManagerServiceUT.restoreAllSimSpecificSettingsFromBackup(
new byte[0]));
+ insertSubscription(FAKE_SUBSCRIPTION_INFO1);
mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
- // TODO: Briefly copy the logic from TelephonyProvider to
- // SubscriptionDatabaseManagerTest.SubscriptionProvider
+
+ // getSubscriptionDatabaseManager().setWifiCallingEnabled(1, 0);
+
+ // Simulate restoration altered the database directly.
+ ContentValues cvs = new ContentValues();
+ cvs.put(SimInfo.COLUMN_WFC_IMS_ENABLED, 0);
+ mSubscriptionProvider.update(Uri.withAppendedPath(SimInfo.CONTENT_URI, "1"), cvs, null,
+ null);
+
+ // Setting this to false to prevent database reload.
+ mSubscriptionProvider.setRestoreDatabaseChanged(false);
mSubscriptionManagerServiceUT.restoreAllSimSpecificSettingsFromBackup(
new byte[0]);
+
+ SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT
+ .getSubscriptionInfoInternal(1);
+ // Since reload didn't happen, WFC should remains enabled.
+ assertThat(subInfo.getWifiCallingEnabled()).isEqualTo(1);
+
+ // Now the database reload should happen
+ mSubscriptionProvider.setRestoreDatabaseChanged(true);
+ mSubscriptionManagerServiceUT.restoreAllSimSpecificSettingsFromBackup(
+ new byte[0]);
+
+ subInfo = mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1);
+ // Since reload didn't happen, WFC should remains enabled.
+ assertThat(subInfo.getWifiCallingEnabled()).isEqualTo(0);
}
@Test