Fix Settings restart during Reset mobile nework settings flow

This CL avoids restarting Settings in the reset mobile flow when phone
process is restarted, by switching the usage of the stable content
provider connection to the unstable client.

The CL also arranges restarting phone process as the last reset
operation in the flow (later than RILD reset) to avoid any reset
operation get impacted by phone process restarting.

Since the permission to protect the TelephonyContentProvider has been
renamed, the CL also renames the requsted permision.

Bug: 347047105
Test: atest ResetNetworkOperationBuilderTest
Test: Reset mobile network feature test
Flag: EXEMPT resource update with minor refactoring
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5ac9d9c8fa0005f787b75052010dcc9935efcb4f)
Merged-In: I7bfa79bc9d7451a4a03269704b0009a3730e287f
Change-Id: I7bfa79bc9d7451a4a03269704b0009a3730e287f
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7daf136..69d000a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -140,7 +140,7 @@
     <uses-permission android:name="android.permission.REMAP_MODIFIER_KEYS" />
     <uses-permission android:name="android.permission.ACCESS_GPU_SERVICE" />
     <uses-permission android:name="android.permission.MANAGE_GAME_MODE" />
-    <uses-permission android:name="android.permission.RESTART_PHONE_PROCESS" />
+    <uses-permission android:name="android.permission.RESTART_TELEPHONY_PROCESS" />
     <uses-permission android:name="android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES" />
     <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
diff --git a/src/com/android/settings/ResetNetworkRequest.java b/src/com/android/settings/ResetNetworkRequest.java
index 7632ea0..8df67e7 100644
--- a/src/com/android/settings/ResetNetworkRequest.java
+++ b/src/com/android/settings/ResetNetworkRequest.java
@@ -271,12 +271,12 @@
             builder.resetIms(mSubscriptionIdToResetIms);
         }
         // Reset phone process and RILD may impact above components, keep them at the end
-        if ((mResetOptions & RESET_PHONE_PROCESS) != 0) {
-            builder.restartPhoneProcess();
-        }
         if ((mResetOptions & RESET_RILD) != 0) {
             builder.restartRild();
         }
+        if ((mResetOptions & RESET_PHONE_PROCESS) != 0) {
+            builder.restartPhoneProcess();
+        }
         return builder;
     }
 }
diff --git a/src/com/android/settings/network/ResetNetworkOperationBuilder.java b/src/com/android/settings/network/ResetNetworkOperationBuilder.java
index 6f36074..47c06d4 100644
--- a/src/com/android/settings/network/ResetNetworkOperationBuilder.java
+++ b/src/com/android/settings/network/ResetNetworkOperationBuilder.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothManager;
+import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -28,11 +29,14 @@
 import android.net.wifi.p2p.WifiP2pManager;
 import android.os.Looper;
 import android.os.RecoverySystem;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.ResetNetworkRequest;
@@ -257,15 +261,15 @@
      */
     public ResetNetworkOperationBuilder restartPhoneProcess() {
         Runnable runnable = () -> {
-            try {
-                mContext.getContentResolver().call(
-                        getResetTelephonyContentProviderAuthority(),
-                        METHOD_RESTART_PHONE_PROCESS,
-                        /* arg= */ null,
-                        /* extras= */ null);
-                Log.i(TAG, "Phone process was restarted.");
-            } catch (IllegalArgumentException iae) {
-                Log.w(TAG, "Fail to restart phone process: " + iae);
+            // Unstable content provider can avoid us getting killed together with phone process
+            try (ContentProviderClient client = getUnstableTelephonyContentProviderClient()) {
+                if (client != null) {
+                    client.call(METHOD_RESTART_PHONE_PROCESS, /* arg= */ null, /* extra= */ null);
+                    Log.i(TAG, "Phone process was restarted.");
+                }
+            } catch (RemoteException re) {
+                // It's normal to throw RE since phone process immediately dies
+                Log.i(TAG, "Phone process has been restarted: " + re);
             }
         };
         mResetSequence.add(runnable);
@@ -279,15 +283,13 @@
      */
     public ResetNetworkOperationBuilder restartRild() {
         Runnable runnable = () -> {
-            try {
-                mContext.getContentResolver().call(
-                        getResetTelephonyContentProviderAuthority(),
-                        METHOD_RESTART_RILD,
-                        /* arg= */ null,
-                        /* extras= */ null);
-                Log.i(TAG, "RILD was restarted.");
-            } catch (IllegalArgumentException iae) {
-                Log.w(TAG, "Fail to restart RILD: " + iae);
+            try (ContentProviderClient client = getUnstableTelephonyContentProviderClient()) {
+                if (client != null) {
+                    client.call(METHOD_RESTART_RILD, /* arg= */ null, /* extra= */ null);
+                    Log.i(TAG, "RILD was restarted.");
+                }
+            } catch (RemoteException re) {
+                Log.w(TAG, "Fail to restart RILD: " + re);
             }
         };
         mResetSequence.add(runnable);
@@ -322,9 +324,18 @@
      * @return the authority of the telephony content provider that support methods
      * resetPhoneProcess and resetRild.
      */
-    @VisibleForTesting
-    String getResetTelephonyContentProviderAuthority() {
+    private String getResetTelephonyContentProviderAuthority() {
         return mContext.getResources().getString(
                 R.string.reset_telephony_stack_content_provider_authority);
     }
+
+    /**
+     * @return the unstable content provider to avoid us getting killed with phone process
+     */
+    @Nullable
+    @VisibleForTesting
+    public ContentProviderClient getUnstableTelephonyContentProviderClient() {
+        return mContext.getContentResolver().acquireUnstableContentProviderClient(
+                getResetTelephonyContentProviderAuthority());
+    }
 }
diff --git a/tests/unit/src/com/android/settings/network/ResetNetworkOperationBuilderTest.java b/tests/unit/src/com/android/settings/network/ResetNetworkOperationBuilderTest.java
index 5f54406..7f1c475 100644
--- a/tests/unit/src/com/android/settings/network/ResetNetworkOperationBuilderTest.java
+++ b/tests/unit/src/com/android/settings/network/ResetNetworkOperationBuilderTest.java
@@ -16,20 +16,16 @@
 
 package com.android.settings.network;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.content.ContentProvider;
-import android.content.ContentResolver;
+import android.content.ContentProviderClient;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkPolicyManager;
@@ -67,7 +63,7 @@
     @Mock
     private NetworkPolicyManager mNetworkPolicyManager;
     @Mock
-    private ContentProvider mContentProvider;;
+    private ContentProviderClient mContentProviderClient;
 
 
     private Context mContext;
@@ -77,9 +73,8 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(ApplicationProvider.getApplicationContext());
-        doReturn(ContentResolver.wrap(mContentProvider)).when(mContext).getContentResolver();
-
         mBuilder = spy(new ResetNetworkOperationBuilder(mContext));
+        doReturn(mContentProviderClient).when(mBuilder).getUnstableTelephonyContentProviderClient();
     }
 
     @Test
@@ -184,38 +179,38 @@
     }
 
     @Test
-    public void restartPhoneProcess_withoutTelephonyContentProvider_shouldNotCrash() {
-        doThrow(new IllegalArgumentException()).when(mContentProvider).call(
-                anyString(), anyString(), anyString(), any());
+    public void restartPhoneProcess_withoutTelephonyContentProvider_shouldNotCrash()
+            throws Exception {
+        doReturn(null).when(mBuilder).getUnstableTelephonyContentProviderClient();
 
         mBuilder.restartPhoneProcess().build().run();
     }
 
     @Test
-    public void restartRild_withoutTelephonyContentProvider_shouldNotCrash() {
-        doThrow(new IllegalArgumentException()).when(mContentProvider).call(
-                anyString(), anyString(), anyString(), any());
+    public void restartRild_withoutTelephonyContentProvider_shouldNotCrash()
+            throws Exception {
+        doReturn(null).when(mBuilder).getUnstableTelephonyContentProviderClient();
 
         mBuilder.restartRild().build().run();
     }
 
     @Test
-    public void restartPhoneProcess_withTelephonyContentProvider_shouldCallRestartPhoneProcess() {
+    public void restartPhoneProcess_withTelephonyContentProvider_shouldCallRestartPhoneProcess()
+            throws Exception {
         mBuilder.restartPhoneProcess().build().run();
 
-        verify(mContentProvider).call(
-                eq(mBuilder.getResetTelephonyContentProviderAuthority()),
+        verify(mContentProviderClient).call(
                 eq(ResetNetworkOperationBuilder.METHOD_RESTART_PHONE_PROCESS),
                 isNull(),
                 isNull());
     }
 
     @Test
-    public void restartRild_withTelephonyContentProvider_shouldCallRestartRild() {
+    public void restartRild_withTelephonyContentProvider_shouldCallRestartRild()
+            throws Exception {
         mBuilder.restartRild().build().run();
 
-        verify(mContentProvider).call(
-                eq(mBuilder.getResetTelephonyContentProviderAuthority()),
+        verify(mContentProviderClient).call(
                 eq(ResetNetworkOperationBuilder.METHOD_RESTART_RILD),
                 isNull(),
                 isNull());