Merge "Merge Android 12"
diff --git a/Android.bp b/Android.bp
index 3b65737..cd24b24 100644
--- a/Android.bp
+++ b/Android.bp
@@ -32,3 +32,11 @@
     name: "telephonyprovider-assets-carrierlist",
     srcs: ["assets/latest_carrier_id/carrier_list.*"],
 }
+
+// used to share src with unit test app
+filegroup {
+    name: "telephonyprovider-shared-srcs",
+    srcs: [
+        "src/**/*.java",
+    ],
+}
diff --git a/assets/latest_carrier_id/carrier_list.pb b/assets/latest_carrier_id/carrier_list.pb
index 4170a56..3bb6f2b 100644
--- a/assets/latest_carrier_id/carrier_list.pb
+++ b/assets/latest_carrier_id/carrier_list.pb
Binary files differ
diff --git a/assets/latest_carrier_id/carrier_list.textpb b/assets/latest_carrier_id/carrier_list.textpb
index cd08eff..75e0864 100644
--- a/assets/latest_carrier_id/carrier_list.textpb
+++ b/assets/latest_carrier_id/carrier_list.textpb
Binary files differ
diff --git a/assets/sdk28_carrier_id/carrier_list.pb b/assets/sdk28_carrier_id/carrier_list.pb
index aa7da64..91d6640 100644
--- a/assets/sdk28_carrier_id/carrier_list.pb
+++ b/assets/sdk28_carrier_id/carrier_list.pb
Binary files differ
diff --git a/assets/sdk28_carrier_id/carrier_list.textpb b/assets/sdk28_carrier_id/carrier_list.textpb
index 6d08b5e..0cd3a99 100644
--- a/assets/sdk28_carrier_id/carrier_list.textpb
+++ b/assets/sdk28_carrier_id/carrier_list.textpb
Binary files differ
diff --git a/assets/sdk29_carrier_id/carrier_list.pb b/assets/sdk29_carrier_id/carrier_list.pb
index 44507d8..5e78f39 100644
--- a/assets/sdk29_carrier_id/carrier_list.pb
+++ b/assets/sdk29_carrier_id/carrier_list.pb
Binary files differ
diff --git a/assets/sdk29_carrier_id/carrier_list.textpb b/assets/sdk29_carrier_id/carrier_list.textpb
index 131b714..6c1420c 100644
--- a/assets/sdk29_carrier_id/carrier_list.textpb
+++ b/assets/sdk29_carrier_id/carrier_list.textpb
Binary files differ
diff --git a/assets/sdk30_carrier_id/carrier_list.pb b/assets/sdk30_carrier_id/carrier_list.pb
index 9287167..946634d 100644
--- a/assets/sdk30_carrier_id/carrier_list.pb
+++ b/assets/sdk30_carrier_id/carrier_list.pb
Binary files differ
diff --git a/assets/sdk30_carrier_id/carrier_list.textpb b/assets/sdk30_carrier_id/carrier_list.textpb
index 67daa47..e301ad0 100644
--- a/assets/sdk30_carrier_id/carrier_list.textpb
+++ b/assets/sdk30_carrier_id/carrier_list.textpb
Binary files differ
diff --git a/assets/sdk31_carrier_id/carrier_list.pb b/assets/sdk31_carrier_id/carrier_list.pb
index 12d57d2..d038016 100644
--- a/assets/sdk31_carrier_id/carrier_list.pb
+++ b/assets/sdk31_carrier_id/carrier_list.pb
Binary files differ
diff --git a/assets/sdk31_carrier_id/carrier_list.textpb b/assets/sdk31_carrier_id/carrier_list.textpb
index aee2bff..62398c0 100644
--- a/assets/sdk31_carrier_id/carrier_list.textpb
+++ b/assets/sdk31_carrier_id/carrier_list.textpb
Binary files differ
diff --git a/src/com/android/providers/telephony/CarrierIdProvider.java b/src/com/android/providers/telephony/CarrierIdProvider.java
index 3e751aa..9b6c2c0 100644
--- a/src/com/android/providers/telephony/CarrierIdProvider.java
+++ b/src/com/android/providers/telephony/CarrierIdProvider.java
@@ -189,14 +189,17 @@
                 + CarrierId.All.MCCMNC + ");";
     }
 
+    static {
+        s_urlMatcher.addURI(AUTHORITY, "all", URL_ALL);
+        s_urlMatcher.addURI(AUTHORITY, "all/update_db", URL_ALL_UPDATE_FROM_PB);
+        s_urlMatcher.addURI(AUTHORITY, "all/get_version", URL_ALL_GET_VERSION);
+    }
+
     @Override
     public boolean onCreate() {
         Log.d(TAG, "onCreate");
         mDbHelper = new CarrierIdDatabaseHelper(getContext());
         mDbHelper.getReadableDatabase();
-        s_urlMatcher.addURI(AUTHORITY, "all", URL_ALL);
-        s_urlMatcher.addURI(AUTHORITY, "all/update_db", URL_ALL_UPDATE_FROM_PB);
-        s_urlMatcher.addURI(AUTHORITY, "all/get_version", URL_ALL_GET_VERSION);
         updateDatabaseFromPb(mDbHelper.getWritableDatabase());
         return true;
     }
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index 068f209..a9494fb 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -526,6 +526,15 @@
     @Override
     public void onCreate(SQLiteDatabase db) {
         localLog("onCreate: Creating all SMS-MMS tables.");
+
+        createMmsTables(db);
+        createSmsTables(db);
+        createCommonTables(db);
+        createCommonTriggers(db);
+        createMmsTriggers(db);
+        createWordsTables(db);
+        createIndices(db);
+
         // if FBE is not supported, or if this onCreate is for CE partition database
         if (!StorageManager.isFileEncryptedNativeOrEmulated()
                 || (mContext != null && mContext.isCredentialProtectedStorage())) {
@@ -546,13 +555,6 @@
 
             mContext.sendBroadcast(intent);
         }
-        createMmsTables(db);
-        createSmsTables(db);
-        createCommonTables(db);
-        createCommonTriggers(db);
-        createMmsTriggers(db);
-        createWordsTables(db);
-        createIndices(db);
     }
 
     private static void localLog(String logMsg) {
diff --git a/src/com/android/providers/telephony/TelephonyBackupAgent.java b/src/com/android/providers/telephony/TelephonyBackupAgent.java
index 6ce5da1..34fed99 100644
--- a/src/com/android/providers/telephony/TelephonyBackupAgent.java
+++ b/src/com/android/providers/telephony/TelephonyBackupAgent.java
@@ -36,6 +36,7 @@
 import android.os.Build;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
+import android.preference.PreferenceManager;
 import android.provider.BaseColumns;
 import android.provider.Telephony;
 import android.telephony.PhoneNumberUtils;
@@ -50,6 +51,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.PhoneFactory;
 
 import com.google.android.mms.ContentType;
 import com.google.android.mms.pdu.CharacterSets;
@@ -114,6 +116,15 @@
     private static final boolean DEBUG = false;
     private static volatile boolean sIsRestoring;
 
+    // SharedPreferences keys
+    private static final String NUM_SMS_RESTORED = "num_sms_restored";
+    private static final String NUM_SMS_EXCEPTIONS = "num_sms_exceptions";
+    private static final String NUM_SMS_FILES_STORED = "num_sms_files_restored";
+    private static final String NUM_SMS_FILES_WITH_EXCEPTIONS = "num_sms_files_with_exceptions";
+    private static final String NUM_MMS_RESTORED = "num_mms_restored";
+    private static final String NUM_MMS_EXCEPTIONS = "num_mms_exceptions";
+    private static final String NUM_MMS_FILES_STORED = "num_mms_files_restored";
+    private static final String NUM_MMS_FILES_WITH_EXCEPTIONS = "num_mms_files_with_exceptions";
 
     // Copied from packages/apps/Messaging/src/com/android/messaging/sms/MmsUtils.java.
     private static final int DEFAULT_DURATION = 5000; //ms
@@ -316,7 +327,7 @@
     @Override
     public void onCreate() {
         super.onCreate();
-
+        Log.d(TAG, "onCreate");
         final SubscriptionManager subscriptionManager = SubscriptionManager.from(this);
         if (subscriptionManager != null) {
             final List<SubscriptionInfo> subInfo =
@@ -505,6 +516,28 @@
 
     public static class DeferredSmsMmsRestoreService extends IntentService {
         private static final String TAG = "DeferredSmsMmsRestoreService";
+        private static boolean sSharedPrefsAddedToLocalLogs = false;
+
+        public static void addAllSharedPrefToLocalLog(Context context) {
+            if (sSharedPrefsAddedToLocalLogs) return;
+            localLog("addAllSharedPrefToLocalLog");
+            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+            Map<String, ?> allPref = sp.getAll();
+            if (allPref.keySet() == null || allPref.keySet().size() == 0) return;
+            for (String key : allPref.keySet()) {
+                try {
+                    localLog(key + ":" + allPref.get(key).toString());
+                } catch (Exception e) {
+                    localLog("Skipping over key " + key + " due to exception " + e);
+                }
+            }
+            sSharedPrefsAddedToLocalLogs = true;
+        }
+
+        public static void localLog(String logMsg) {
+            Log.d(TAG, logMsg);
+            PhoneFactory.localLog(TAG, logMsg);
+        }
 
         private final Comparator<File> mFileComparator = new Comparator<File>() {
             @Override
@@ -515,6 +548,7 @@
 
         public DeferredSmsMmsRestoreService() {
             super(TAG);
+            Log.d(TAG, "DeferredSmsMmsRestoreService");
             setIntentRedelivery(true);
         }
 
@@ -523,6 +557,7 @@
 
         @Override
         protected void onHandleIntent(Intent intent) {
+            Log.d(TAG, "onHandleIntent");
             try {
                 mWakeLock.acquire();
                 sIsRestoring = true;
@@ -545,6 +580,7 @@
                     } catch (Exception e) {
                         // Either IOException or RuntimeException.
                         Log.e(TAG, "onHandleIntent", e);
+                        localLog("onHandleIntent: Exception " + e);
                     } finally {
                         file.delete();
                     }
@@ -552,11 +588,12 @@
                 if (didRestore) {
                   // Tell the default sms app to do a full sync now that the messages have been
                   // restored.
-                  Log.d(TAG, "onHandleIntent done - notifying default sms app");
+                  localLog("onHandleIntent: done - notifying default sms app");
                   ProviderUtil.notifyIfNotDefaultSmsApp(null /*uri*/, null /*calling package*/,
                       this);
                 }
            } finally {
+                addAllSharedPrefToLocalLog(this);
                 sIsRestoring = false;
                 mWakeLock.release();
             }
@@ -565,6 +602,12 @@
         @Override
         public void onCreate() {
             super.onCreate();
+            Log.d(TAG, "onCreate");
+            try {
+                PhoneFactory.addLocalLog(TAG, 32);
+            } catch (IllegalArgumentException e) {
+                // ignore
+            }
             mTelephonyBackupAgent = new TelephonyBackupAgent();
             mTelephonyBackupAgent.attach(this);
             mTelephonyBackupAgent.onCreate();
@@ -583,8 +626,15 @@
         }
 
         static void startIfFilesExist(Context context) {
+            try {
+                PhoneFactory.addLocalLog(TAG, 32);
+            } catch (IllegalArgumentException e) {
+                // ignore
+            }
             File[] files = getFilesToRestore(context);
             if (files == null || files.length == 0) {
+                Log.d(TAG, "startIfFilesExist: no files to restore");
+                addAllSharedPrefToLocalLog(context);
                 return;
             }
             context.startService(new Intent(context, DeferredSmsMmsRestoreService.class));
@@ -618,7 +668,7 @@
                 Log.d(TAG, "Restoring text MMS");
                 putMmsMessagesToProvider(jsonReader);
             } else {
-                Log.e(TAG, "Unknown file to restore:" + fileName);
+                DeferredSmsMmsRestoreService.localLog("Unknown file to restore:" + fileName);
             }
         }
     }
@@ -627,6 +677,7 @@
     void putSmsMessagesToProvider(JsonReader jsonReader) throws IOException {
         jsonReader.beginArray();
         int msgCount = 0;
+        int numExceptions = 0;
         final int bulkInsertSize = mMaxMsgPerFile;
         ContentValues[] values = new ContentValues[bulkInsertSize];
         while (jsonReader.hasNext()) {
@@ -639,8 +690,10 @@
                 if (msgCount % bulkInsertSize == 0) {
                     mContentResolver.bulkInsert(Telephony.Sms.CONTENT_URI, values);
                 }
-            } catch (Exception e) {
+            } catch (RuntimeException e) {
                 Log.e(TAG, "putSmsMessagesToProvider", e);
+                DeferredSmsMmsRestoreService.localLog("putSmsMessagesToProvider: Exception " + e);
+                numExceptions++;
             }
         }
         if (msgCount % bulkInsertSize > 0) {
@@ -648,12 +701,37 @@
                     Arrays.copyOf(values, msgCount % bulkInsertSize));
         }
         jsonReader.endArray();
+        incremenentSharedPref(true, msgCount, numExceptions);
+    }
+
+    void incremenentSharedPref(boolean sms, int msgCount, int numExceptions) {
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+        SharedPreferences.Editor editor = sp.edit();
+        if (sms) {
+            editor.putInt(NUM_SMS_RESTORED, sp.getInt(NUM_SMS_RESTORED, 0) + msgCount);
+            editor.putInt(NUM_SMS_EXCEPTIONS, sp.getInt(NUM_SMS_EXCEPTIONS, 0) + numExceptions);
+            editor.putInt(NUM_SMS_FILES_STORED, sp.getInt(NUM_SMS_FILES_STORED, 0) + 1);
+            if (numExceptions > 0) {
+                editor.putInt(NUM_SMS_FILES_WITH_EXCEPTIONS,
+                        sp.getInt(NUM_SMS_FILES_WITH_EXCEPTIONS, 0) + 1);
+            }
+        } else {
+            editor.putInt(NUM_MMS_RESTORED, sp.getInt(NUM_MMS_RESTORED, 0) + msgCount);
+            editor.putInt(NUM_MMS_EXCEPTIONS, sp.getInt(NUM_MMS_EXCEPTIONS, 0) + numExceptions);
+            editor.putInt(NUM_MMS_FILES_STORED, sp.getInt(NUM_MMS_FILES_STORED, 0) + 1);
+            if (numExceptions > 0) {
+                editor.putInt(NUM_MMS_FILES_WITH_EXCEPTIONS,
+                        sp.getInt(NUM_MMS_FILES_WITH_EXCEPTIONS, 0) + 1);
+            }
+        }
+        editor.commit();
     }
 
     @VisibleForTesting
     void putMmsMessagesToProvider(JsonReader jsonReader) throws IOException {
         jsonReader.beginArray();
         int total = 0;
+        int numExceptions = 0;
         while (jsonReader.hasNext()) {
             final Mms mms = readMmsFromReader(jsonReader);
             if (DEBUG) {
@@ -672,9 +750,12 @@
                 addMmsMessage(mms);
             } catch (Exception e) {
                 Log.e(TAG, "putMmsMessagesToProvider", e);
+                numExceptions++;
+                DeferredSmsMmsRestoreService.localLog("putMmsMessagesToProvider: Exception " + e);
             }
         }
         Log.d(TAG, "putMmsMessagesToProvider handled " + total + " new messages.");
+        incremenentSharedPref(false, total, numExceptions);
     }
 
     @VisibleForTesting
@@ -706,9 +787,17 @@
         }
     };
 
+    /**
+     * Sets a temporary {@code SmsProviderQuery} for testing; note that this method
+     * is not thread safe.
+     *
+     * @return the previous {@code SmsProviderQuery}
+     */
     @VisibleForTesting
-    public void setSmsProviderQuery(SmsProviderQuery smsProviderQuery) {
+    public SmsProviderQuery getAndSetSmsProviderQuery(SmsProviderQuery smsProviderQuery) {
+        SmsProviderQuery result = mSmsProviderQuery;
         mSmsProviderQuery = smsProviderQuery;
+        return result;
     }
 
     private boolean doesMmsExist(Mms mms) {
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 4dc815d..0ff9fc6 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -69,21 +69,17 @@
 import static android.provider.Telephony.Carriers.USER_VISIBLE;
 import static android.provider.Telephony.Carriers.WAIT_TIME_RETRY;
 import static android.provider.Telephony.Carriers._ID;
-import static java.nio.charset.StandardCharsets.UTF_8;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.app.compat.CompatChanges;
 import android.content.ComponentName;
 import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
-import android.content.OperationApplicationException;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.UriMatcher;
@@ -115,6 +111,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.AtomicFile;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Xml;
@@ -129,7 +126,6 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -139,11 +135,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.Integer;
-import java.lang.NoSuchFieldException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -568,8 +562,8 @@
                 + Telephony.SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED + " INTEGER DEFAULT 0,"
                 + Telephony.SimInfo.COLUMN_RCS_CONFIG + " BLOB,"
                 + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS + " TEXT,"
-                + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING + " INTEGER DEFAULT 0,"
                 + Telephony.SimInfo.COLUMN_VOIMS_OPT_IN_STATUS + " INTEGER DEFAULT 0,"
+                + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING + " INTEGER DEFAULT 0,"
                 + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS + " TEXT"
                 + ");";
     }
@@ -1654,12 +1648,12 @@
                 try {
                     // Try to update the siminfo table. It might not be there.
                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
-                            + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING
+                            + Telephony.SimInfo.COLUMN_VOIMS_OPT_IN_STATUS
                             + " INTEGER DEFAULT 0;");
                 } catch (SQLiteException e) {
                     if (DBG) {
-                        log("onUpgrade failed to updated " + SIMINFO_TABLE
-                                + " to add d2d status sharing column. ");
+                        log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. "
+                                + "The table will get created in onOpen.");
                     }
                 }
                 oldVersion = 49 << 16 | 6;
@@ -1669,12 +1663,12 @@
                 try {
                     // Try to update the siminfo table. It might not be there.
                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
-                            + Telephony.SimInfo.COLUMN_VOIMS_OPT_IN_STATUS
+                            + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING
                             + " INTEGER DEFAULT 0;");
                 } catch (SQLiteException e) {
                     if (DBG) {
-                        log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
-                                "The table will get created in onOpen.");
+                        log("onUpgrade failed to updated " + SIMINFO_TABLE
+                                + " to add d2d status sharing column. ");
                     }
                 }
                 oldVersion = 50 << 16 | 6;
@@ -2844,8 +2838,10 @@
                 r.getString(R.string.apn_source_service)));
         log("binding to service to restore apns, intent=" + intent);
         try {
-            if (context.bindService(intent, connection, Context.BIND_IMPORTANT |
-                        Context.BIND_AUTO_CREATE)) {
+            if (context.bindService(intent,
+                    Context.BIND_IMPORTANT | Context.BIND_AUTO_CREATE,
+                    runnable -> new Thread(runnable).start(),
+                    connection)) {
                 synchronized (mLock) {
                     while (mIApnSourceService == null && !connectionBindingInvalid.get()) {
                         try {
@@ -2898,10 +2894,10 @@
 
         boolean isNewBuild = false;
         String newBuildId = SystemProperties.get("ro.build.id", null);
+        SharedPreferences sp = getContext().getSharedPreferences(BUILD_ID_FILE,
+                Context.MODE_PRIVATE);
         if (!TextUtils.isEmpty(newBuildId)) {
             // Check if build id has changed
-            SharedPreferences sp = getContext().getSharedPreferences(BUILD_ID_FILE,
-                    Context.MODE_PRIVATE);
             String oldBuildId = sp.getString(RO_BUILD_ID, "");
             if (!newBuildId.equals(oldBuildId)) {
                 localLog("onCreate: build id changed from " + oldBuildId + " to " + newBuildId);
@@ -2909,7 +2905,6 @@
             } else {
                 if (VDBG) log("onCreate: build id did not change: " + oldBuildId);
             }
-            sp.edit().putString(RO_BUILD_ID, newBuildId).apply();
         } else {
             if (VDBG) log("onCreate: newBuildId is empty");
         }
@@ -2924,9 +2919,15 @@
             if (DBG) addAllApnSharedPrefToLocalLog();
         }
 
-        SharedPreferences sp = getContext().getSharedPreferences(ENFORCED_FILE,
+        // Write build id to SharedPreferences after APNs have been updated above by updateApnDb()
+        if (!TextUtils.isEmpty(newBuildId)) {
+            if (isNewBuild) log("onCreate: updating build id to " + newBuildId);
+            sp.edit().putString(RO_BUILD_ID, newBuildId).apply();
+        }
+
+        SharedPreferences spEnforcedFile = getContext().getSharedPreferences(ENFORCED_FILE,
                 Context.MODE_PRIVATE);
-        mManagedApnEnforced = sp.getBoolean(ENFORCED_KEY, false);
+        mManagedApnEnforced = spEnforcedFile.getBoolean(ENFORCED_KEY, false);
 
         if (VDBG) log("onCreate:- ret true");
 
@@ -3196,10 +3197,17 @@
 
     @VisibleForTesting
     boolean writeSimSettingsToInternalStorage(byte[] data) {
-        File file = new File(getContext().getFilesDir(), BACKED_UP_SIM_SPECIFIC_SETTINGS_FILE);
-        try (FileOutputStream fos = new FileOutputStream(file)) {
+        AtomicFile atomicFile = new AtomicFile(
+                new File(getContext().getFilesDir(), BACKED_UP_SIM_SPECIFIC_SETTINGS_FILE));
+        FileOutputStream fos = null;
+        try {
+            fos = atomicFile.startWrite();
             fos.write(data);
+            atomicFile.finishWrite(fos);
         } catch (IOException e) {
+            if (fos != null) {
+                atomicFile.failWrite(fos);
+            }
             loge("Not able to create internal file with per-sim configs. Failed with error "
                     + e);
             return false;
@@ -3226,8 +3234,9 @@
             return;
         }
 
+        AtomicFile atomicFile = new AtomicFile(file);
         PersistableBundle bundle = null;
-        try (FileInputStream fis = new FileInputStream(file)) {
+        try (FileInputStream fis = atomicFile.openRead()) {
             bundle = PersistableBundle.readFromStream(fis);
         } catch (IOException e) {
             loge("Failed to convert backed up per-sim configs to bundle. Stopping restore. "
@@ -3669,6 +3678,7 @@
         checkPermissionCompat(match, projectionIn);
         switch (match) {
             case URL_TELEPHONY_USING_SUBID: {
+                // The behaves exactly same as URL_SIM_APN_LIST_ID.
                 subIdString = url.getLastPathSegment();
                 try {
                     subId = Integer.parseInt(subIdString);
@@ -3677,13 +3687,13 @@
                     return null;
                 }
                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
-                TelephonyManager telephonyManager = getContext()
-                    .getSystemService(TelephonyManager.class).createForSubscriptionId(subId);
-                constraints.add(NUMERIC + " = '" + telephonyManager.getSimOperator() + "'");
+                qb.appendWhereStandalone(IS_NOT_OWNED_BY_DPC);
+                return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs,
+                        sort, subId);
+
                 // TODO b/74213956 turn this back on once insertion includes correct sub id
                 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString);
             }
-            // intentional fall through from above case
             case URL_TELEPHONY: {
                 constraints.add(IS_NOT_OWNED_BY_DPC);
                 break;
@@ -3881,6 +3891,31 @@
     }
 
     /**
+     * This method syncs PREF_FILE_FULL_APN with the db based on the current preferred apn ids.
+     */
+    private void updatePreferredApns() {
+        SharedPreferences spApn = getContext().getSharedPreferences(PREF_FILE_APN,
+                Context.MODE_PRIVATE);
+
+        Map<String, ?> allPrefApnId = spApn.getAll();
+        for (String key : allPrefApnId.keySet()) {
+            if (key.startsWith(COLUMN_APN_ID)) {
+                int subId;
+                try {
+                    subId = Integer.parseInt(key.substring(COLUMN_APN_ID.length()));
+                } catch (NumberFormatException e) {
+                    loge("updatePreferredApns: NumberFormatException for key=" + key);
+                    continue;
+                }
+                long preferredApnId = getPreferredApnId(subId, false);
+                if (preferredApnId != INVALID_APN_ID) {
+                    setPreferredApn(preferredApnId, subId);
+                }
+            }
+        }
+    }
+
+    /**
      * To find the current sim APN. Query APN based on {MCC, MNC, MVNO} and {Carrier_ID}.
      *
      * There has three steps:
@@ -3942,10 +3977,19 @@
                 data.add(ret.getString(ret.getColumnIndex(column)));
             }
 
+            boolean isCurrentSimOperator;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                isCurrentSimOperator = tm.matchesCurrentSimOperator(
+                        ret.getString(numericIndex),
+                        getMvnoTypeIntFromString(ret.getString(mvnoIndex)),
+                        ret.getString(mvnoDataIndex));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
             boolean isMVNOAPN = !TextUtils.isEmpty(ret.getString(numericIndex))
-                    && tm.matchesCurrentSimOperator(ret.getString(numericIndex),
-                            getMvnoTypeIntFromString(ret.getString(mvnoIndex)),
-                            ret.getString(mvnoDataIndex));
+                    && isCurrentSimOperator;
             boolean isMNOAPN = !TextUtils.isEmpty(ret.getString(numericIndex))
                     && ret.getString(numericIndex).equals(mccmnc)
                     && TextUtils.isEmpty(ret.getString(mvnoIndex));
@@ -4619,6 +4663,19 @@
             }
         }
 
+        // if APNs (CARRIERS_TABLE) have been updated, some of them may be preferred APN for
+        // different subs. So update the APN field values saved in SharedPref for all subIds.
+        switch (match) {
+            case URL_TELEPHONY_USING_SUBID:
+            case URL_TELEPHONY:
+            case URL_CURRENT_USING_SUBID:
+            case URL_CURRENT:
+            case URL_ID:
+            case URL_DPC_ID:
+                updatePreferredApns();
+                break;
+        }
+
         if (count > 0) {
             boolean usingSubId = false;
             switch (uriType) {
@@ -4716,14 +4773,18 @@
 
         TelephonyManager telephonyManager =
                 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
-        for (String pkg : packages) {
-            if (telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(pkg) ==
+        final long token = Binder.clearCallingIdentity();
+        try {
+            for (String pkg : packages) {
+                if (telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(pkg) ==
                     TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-                return;
+                    return;
+                }
             }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
 
-
         throw new SecurityException("No permission to access APN settings");
     }
 
diff --git a/tests/Android.bp b/tests/Android.bp
index dafd7cd..8ecc370 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -23,7 +23,7 @@
         "android.test.base",
         "android.test.mock",
     ],
-    srcs: ["src/**/*.java"],
+    srcs: ["src/**/*.java", ":telephonyprovider-shared-srcs"],
     platform_apis: true,
     test_suites: ["device-tests"],
     certificate: "platform",
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 59fd8bd..e4e9e69 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -17,12 +17,17 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.providers.telephony.tests">
 
+    <!-- Permissions required for reading and logging compat changes -->
+    <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
+    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.providers.telephony"
+        android:targetPackage="com.android.providers.telephony.tests"
         android:label="Tests for TelephonyProvider">
     </instrumentation>
 </manifest>
diff --git a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
index 00bb15e..f6a9c7f 100644
--- a/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyBackupAgentTest.java
@@ -43,6 +43,8 @@
 import android.util.JsonWriter;
 import android.util.SparseArray;
 
+import com.android.internal.telephony.PhoneFactory;
+
 import libcore.io.IoUtils;
 
 import com.google.android.mms.pdu.CharacterSets;
@@ -620,6 +622,7 @@
      */
     public void testRestoreSms_WithException() throws Exception {
         mTelephonyBackupAgent.initUnknownSender();
+        PhoneFactory.addLocalLog("DeferredSmsMmsRestoreService", 1);
         JsonReader jsonReader = new JsonReader(new StringReader(addRandomDataToJson(mAllSmsJson)));
         FakeSmsProvider smsProvider = new FakeSmsProvider(mSmsRows, false);
         mMockContentResolver.addProvider("sms", smsProvider);
@@ -635,12 +638,16 @@
                         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);
+        TelephonyBackupAgent.SmsProviderQuery previousQuery =
+                mTelephonyBackupAgent.getAndSetSmsProviderQuery(smsProviderQuery);
+        try {
+            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);
+        } finally {
+            mTelephonyBackupAgent.getAndSetSmsProviderQuery(previousQuery);
+        }
     }
 
     /**
diff --git a/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java b/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
index fe2406f..6f3f842 100644
--- a/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
@@ -218,22 +218,6 @@
     }
 
     @Test
-    public void databaseHelperOnUpgrade_hasD2DStatusSharingField() {
-        Log.d(TAG, "databaseHelperOnUpgrade_hasD2DStatusSharingField");
-        // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
-        SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
-        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.getVersion(mContext));
-
-        // the upgraded db must have the Telephony.SimInfo.COLUMN_D2D_SHARING_STATUS field
-        Cursor cursor = db.query("siminfo", null, null, null, null, null, null);
-        String[] upgradedColumns = cursor.getColumnNames();
-        Log.d(TAG, "siminfo columns: " + Arrays.toString(upgradedColumns));
-
-        assertTrue(Arrays.asList(upgradedColumns).contains(
-                Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING));
-    }
-
-    @Test
     public void databaseHelperOnUpgrade_hasVoImsOptInStatusField() {
         Log.d(TAG, "databaseHelperOnUpgrade_hasImsRcsUceEnabledField");
         // (5 << 16) is the first upgrade trigger in onUpgrade
@@ -250,6 +234,22 @@
     }
 
     @Test
+    public void databaseHelperOnUpgrade_hasD2DStatusSharingField() {
+        Log.d(TAG, "databaseHelperOnUpgrade_hasD2DStatusSharingField");
+        // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
+        SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.getVersion(mContext));
+
+        // the upgraded db must have the Telephony.SimInfo.COLUMN_D2D_SHARING_STATUS field
+        Cursor cursor = db.query("siminfo", null, null, null, null, null, null);
+        String[] upgradedColumns = cursor.getColumnNames();
+        Log.d(TAG, "siminfo columns: " + Arrays.toString(upgradedColumns));
+
+        assertTrue(Arrays.asList(upgradedColumns).contains(
+                Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING));
+    }
+
+    @Test
     public void databaseHelperOnUpgrade_hasD2DSharingContactsField() {
         Log.d(TAG, "databaseHelperOnUpgrade_hasD2DSharingContactsField");
         // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index 37ba7ec..1a9b46c 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -45,7 +45,6 @@
 import android.telephony.TelephonyManager;
 import android.test.mock.MockContentResolver;
 import android.test.mock.MockContext;
-import android.test.mock.MockResources;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
 import android.util.Log;
@@ -54,11 +53,14 @@
 
 import junit.framework.TestCase;
 
+import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Mock;
 import static org.mockito.Mockito.when;
 
+import com.android.internal.telephony.PhoneFactory;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -1647,6 +1649,7 @@
         assertEquals(1, cursor.getCount());
         cursor.moveToFirst();
         assertEquals(otherName, cursor.getString(0));
+        PhoneFactory.addLocalLog("TelephonyProvider", 1);
     }
 
     /**