Reset telephony stack during Reset Mobile Network flow

This CL introduces two more steps to restart Phone process and RILD
during the Reset mobile network flow by the help of the
TelephonyContentProvider which has been used by Pixel Adaptive
Connectivity Services ("SCONE") for a while.

The additional reset options can resolve issues like resources leak
and internal state stuck, effectively recover telephony stack into
fresh state.

The reset options are performed in the background and have no impact
on UX of the reset flow.

Bug: 271921464
Test: ResetNetworkOperationBuilderTest
Test: Feature test with both flag on and off
Change-Id: If09d20d79e908dd43f3f654fb7cca7f713b7f03a
This commit is contained in:
Rambo Wang
2024-01-04 04:33:23 +00:00
parent 4f06db7bf8
commit 4c384506d5
6 changed files with 126 additions and 1 deletions

View File

@@ -140,6 +140,7 @@
<uses-permission android:name="android.permission.ACCESS_GPU_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_GAME_MODE" />
<uses-permission android:name="android.permission.RESTART_PHONE_PROCESS" />
<application
android:name=".SettingsApplication"

View File

@@ -12697,4 +12697,7 @@
<!-- Content description for setting password complete-->
<string name="accessibility_setup_password_complete">Password is now set up</string>
<!-- Authority of the content provider that support methods restartPhoneProcess and restartRild. Will be overlaid by OEM.-->
<string name="reset_telephony_stack_content_provider_authority" translatable="false"></string>
</resources>

View File

@@ -21,7 +21,6 @@ import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.provider.Settings;
@@ -128,6 +127,8 @@ public class ResetNetwork extends InstrumentedFragment {
| ResetNetworkRequest.RESET_VPN_MANAGER;
if (Flags.resetMobileNetworkSettings()) {
resetOptions |= ResetNetworkRequest.RESET_IMS_STACK;
resetOptions |= ResetNetworkRequest.RESET_PHONE_PROCESS;
resetOptions |= ResetNetworkRequest.RESET_RILD;
}
ResetNetworkRequest request = new ResetNetworkRequest(resetOptions);
if (mSubscriptions != null && mSubscriptions.size() > 0) {

View File

@@ -51,6 +51,12 @@ public class ResetNetworkRequest {
/* Reset option - reset IMS stack */
public static final int RESET_IMS_STACK = 0x20;
/* Reset option - reset phone process */
public static final int RESET_PHONE_PROCESS = 0x40;
/* Reset option - reset RILD */
public static final int RESET_RILD = 0x80;
/**
* Subscription ID indicates NOT resetting any of the components below:
* - TelephonyAndNetworkPolicy
@@ -264,6 +270,12 @@ public class ResetNetworkRequest {
if ((mResetOptions & RESET_IMS_STACK) != 0) {
builder.resetIms(mSubscriptionIdToResetIms);
}
if ((mResetOptions & RESET_PHONE_PROCESS) != 0) {
builder.restartPhoneProcess();
}
if ((mResetOptions & RESET_RILD) != 0) {
builder.restartRild();
}
return builder;
}
}

View File

@@ -33,6 +33,8 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.ResetNetworkRequest;
import com.android.settings.network.apn.ApnSettings;
@@ -50,6 +52,13 @@ public class ResetNetworkOperationBuilder {
private static final boolean DRY_RUN = false;
// TelephonyContentProvider method to restart phone process
@VisibleForTesting
static final String METHOD_RESTART_PHONE_PROCESS = "restartPhoneProcess";
// TelephonyContentProvider method to restart RILD
@VisibleForTesting
static final String METHOD_RESTART_RILD = "restartRild";
private Context mContext;
private List<Runnable> mResetSequence = new ArrayList<Runnable>();
@@ -229,16 +238,56 @@ public class ResetNetworkOperationBuilder {
// Reset IMS for all slots
for (int slotIndex = 0; slotIndex < tm.getActiveModemCount(); slotIndex++) {
tm.resetIms(slotIndex);
Log.i(TAG, "IMS was reset for slot " + slotIndex);
}
} else {
// Reset IMS for the slot specified by the sucriptionId.
final int slotIndex = SubscriptionManager.getSlotIndex(subId);
tm.resetIms(slotIndex);
Log.i(TAG, "IMS was reset for slot " + slotIndex);
}
});
return this;
}
/**
* Append a step to restart phone process by the help of TelephonyContentProvider.
* It's a no-op if TelephonyContentProvider doesn't exist.
* @return this
*/
public ResetNetworkOperationBuilder restartPhoneProcess() {
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);
}
return this;
}
/**
* Append a step to restart RILD by the help of TelephonyContentProvider.
* It's a no-op if TelephonyContentProvider doesn't exist.
* @return this
*/
public ResetNetworkOperationBuilder restartRild() {
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);
}
return this;
}
/**
* Construct a Runnable containing all operations appended.
* @return Runnable
@@ -262,4 +311,14 @@ public class ResetNetworkOperationBuilder {
};
mResetSequence.add(runnable);
}
/**
* @return the authority of the telephony content provider that support methods
* resetPhoneProcess and resetRild.
*/
@VisibleForTesting
String getResetTelephonyContentProviderAuthority() {
return mContext.getResources().getString(
R.string.reset_telephony_stack_content_provider_authority);
}
}

View File

@@ -16,13 +16,20 @@
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.Context;
import android.net.ConnectivityManager;
import android.net.NetworkPolicyManager;
@@ -59,6 +66,9 @@ public class ResetNetworkOperationBuilderTest {
private TelephonyManager mTelephonyManager;
@Mock
private NetworkPolicyManager mNetworkPolicyManager;
@Mock
private ContentProvider mContentProvider;;
private Context mContext;
private ResetNetworkOperationBuilder mBuilder;
@@ -67,6 +77,7 @@ public class ResetNetworkOperationBuilderTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
doReturn(ContentResolver.wrap(mContentProvider)).when(mContext).getContentResolver();
mBuilder = spy(new ResetNetworkOperationBuilder(mContext));
}
@@ -171,4 +182,42 @@ public class ResetNetworkOperationBuilderTest {
verify(mTelephonyManager, times(2)).resetIms(anyInt());
}
@Test
public void restartPhoneProcess_withoutTelephonyContentProvider_shouldNotCrash() {
doThrow(new IllegalArgumentException()).when(mContentProvider).call(
anyString(), anyString(), anyString(), any());
mBuilder.restartPhoneProcess();
}
@Test
public void restartRild_withoutTelephonyContentProvider_shouldNotCrash() {
doThrow(new IllegalArgumentException()).when(mContentProvider).call(
anyString(), anyString(), anyString(), any());
mBuilder.restartRild();
}
@Test
public void restartPhoneProcess_withTelephonyContentProvider_shouldCallRestartPhoneProcess() {
mBuilder.restartPhoneProcess();
verify(mContentProvider).call(
eq(mBuilder.getResetTelephonyContentProviderAuthority()),
eq(ResetNetworkOperationBuilder.METHOD_RESTART_PHONE_PROCESS),
isNull(),
isNull());
}
@Test
public void restartRild_withTelephonyContentProvider_shouldCallRestartRild() {
mBuilder.restartRild();
verify(mContentProvider).call(
eq(mBuilder.getResetTelephonyContentProviderAuthority()),
eq(ResetNetworkOperationBuilder.METHOD_RESTART_RILD),
isNull(),
isNull());
}
}