1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.network; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.bluetooth.BluetoothManager; 21 import android.content.ContentProviderClient; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.net.ConnectivityManager; 25 import android.net.NetworkPolicyManager; 26 import android.net.Uri; 27 import android.net.VpnManager; 28 import android.net.wifi.WifiManager; 29 import android.net.wifi.p2p.WifiP2pManager; 30 import android.os.Looper; 31 import android.os.RecoverySystem; 32 import android.os.RemoteException; 33 import android.os.SystemClock; 34 import android.telephony.SubscriptionManager; 35 import android.telephony.TelephonyManager; 36 import android.util.Log; 37 38 import androidx.annotation.Nullable; 39 40 import com.android.internal.annotations.VisibleForTesting; 41 import com.android.settings.R; 42 import com.android.settings.ResetNetworkRequest; 43 import com.android.settings.network.apn.PreferredApnRepository; 44 45 import java.util.ArrayList; 46 import java.util.List; 47 import java.util.concurrent.atomic.AtomicReference; 48 import java.util.function.Consumer; 49 50 /** 51 * A builder for creating a Runnable resetting network configurations. 52 */ 53 public class ResetNetworkOperationBuilder { 54 55 private static final String TAG = "ResetNetworkOpBuilder"; 56 57 private static final boolean DRY_RUN = false; 58 59 // TelephonyContentProvider method to restart phone process 60 @VisibleForTesting 61 static final String METHOD_RESTART_PHONE_PROCESS = "restartPhoneProcess"; 62 // TelephonyContentProvider method to restart RILD 63 @VisibleForTesting 64 static final String METHOD_RESTART_RILD = "restartRild"; 65 66 private Context mContext; 67 private List<Runnable> mResetSequence = new ArrayList<Runnable>(); 68 69 /** 70 * Constructor of builder. 71 * 72 * @param context Context 73 */ ResetNetworkOperationBuilder(Context context)74 public ResetNetworkOperationBuilder(Context context) { 75 mContext = context; 76 } 77 78 /** 79 * Append a step of resetting ConnectivityManager. 80 * @return this 81 */ resetConnectivityManager()82 public ResetNetworkOperationBuilder resetConnectivityManager() { 83 attachSystemServiceWork(Context.CONNECTIVITY_SERVICE, 84 (Consumer<ConnectivityManager>) cm -> { 85 cm.factoryReset(); 86 }); 87 return this; 88 } 89 90 /** 91 * Append a step of resetting VpnManager. 92 * @return this 93 */ resetVpnManager()94 public ResetNetworkOperationBuilder resetVpnManager() { 95 attachSystemServiceWork(Context.VPN_MANAGEMENT_SERVICE, 96 (Consumer<VpnManager>) vpnManager -> { 97 vpnManager.factoryReset(); 98 }); 99 return this; 100 } 101 102 /** 103 * Append a step of resetting WifiManager. 104 * @return this 105 */ resetWifiManager()106 public ResetNetworkOperationBuilder resetWifiManager() { 107 attachSystemServiceWork(Context.WIFI_SERVICE, 108 (Consumer<WifiManager>) wifiManager -> { 109 wifiManager.factoryReset(); 110 }); 111 return this; 112 } 113 114 /** 115 * Append a step of resetting WifiP2pManager. 116 * @param callbackLooper looper to support callback from WifiP2pManager 117 * @return this 118 */ resetWifiP2pManager(Looper callbackLooper)119 public ResetNetworkOperationBuilder resetWifiP2pManager(Looper callbackLooper) { 120 attachSystemServiceWork(Context.WIFI_P2P_SERVICE, 121 (Consumer<WifiP2pManager>) wifiP2pManager -> { 122 WifiP2pManager.Channel channel = wifiP2pManager.initialize( 123 mContext, callbackLooper, null /* listener */); 124 if (channel != null) { 125 wifiP2pManager.factoryReset(channel, null /* listener */); 126 } 127 }); 128 return this; 129 } 130 131 /** 132 * Append a step of resetting E-SIM. 133 * @param callerPackage package name of caller 134 * @return this 135 */ resetEsim(String callerPackage)136 public ResetNetworkOperationBuilder resetEsim(String callerPackage) { 137 resetEsim(callerPackage, null); 138 return this; 139 } 140 141 /** 142 * Append a step of resetting E-SIM. 143 * @param callerPackage package name of caller 144 * @param resultCallback a Consumer<Boolean> dealing with result of resetting eSIM 145 * @return this 146 */ resetEsim(String callerPackage, Consumer<Boolean> resultCallback)147 public ResetNetworkOperationBuilder resetEsim(String callerPackage, 148 Consumer<Boolean> resultCallback) { 149 Runnable runnable = () -> { 150 long startTime = SystemClock.elapsedRealtime(); 151 152 if (!DRY_RUN) { 153 Boolean wipped = RecoverySystem.wipeEuiccData(mContext, callerPackage); 154 if (resultCallback != null) { 155 resultCallback.accept(wipped); 156 } 157 } 158 159 long endTime = SystemClock.elapsedRealtime(); 160 Log.i(TAG, "Reset eSIM, takes " + (endTime - startTime) + " ms"); 161 }; 162 mResetSequence.add(runnable); 163 return this; 164 } 165 166 /** 167 * Append a step of resetting TelephonyManager and . 168 * @param subscriptionId of a SIM card 169 * @return this 170 */ resetTelephonyAndNetworkPolicyManager( int subscriptionId)171 public ResetNetworkOperationBuilder resetTelephonyAndNetworkPolicyManager( 172 int subscriptionId) { 173 final AtomicReference<String> subscriberId = new AtomicReference<String>(); 174 attachSystemServiceWork(Context.TELEPHONY_SERVICE, 175 (Consumer<TelephonyManager>) tm -> { 176 TelephonyManager subIdTm = tm.createForSubscriptionId(subscriptionId); 177 subscriberId.set(subIdTm.getSubscriberId()); 178 subIdTm.resetSettings(); 179 }); 180 attachSystemServiceWork(Context.NETWORK_POLICY_SERVICE, 181 (Consumer<NetworkPolicyManager>) policyManager -> { 182 policyManager.factoryReset(subscriberId.get()); 183 }); 184 return this; 185 } 186 187 /** 188 * Append a step of resetting BluetoothAdapter. 189 * @return this 190 */ resetBluetoothManager()191 public ResetNetworkOperationBuilder resetBluetoothManager() { 192 attachSystemServiceWork(Context.BLUETOOTH_SERVICE, 193 (Consumer<BluetoothManager>) btManager -> { 194 BluetoothAdapter btAdapter = btManager.getAdapter(); 195 if (btAdapter != null) { 196 btAdapter.clearBluetooth(); 197 } 198 }); 199 return this; 200 } 201 202 /** 203 * Append a step of resetting APN configurations. 204 * @param subscriptionId of a SIM card 205 * @return this 206 */ resetApn(int subscriptionId)207 public ResetNetworkOperationBuilder resetApn(int subscriptionId) { 208 Runnable runnable = () -> { 209 long startTime = SystemClock.elapsedRealtime(); 210 211 Uri uri = PreferredApnRepository.getRestorePreferredApnUri(); 212 213 if (SubscriptionManager.isUsableSubscriptionId(subscriptionId)) { 214 uri = Uri.withAppendedPath(uri, "subId/" + String.valueOf(subscriptionId)); 215 } 216 217 if (!DRY_RUN) { 218 ContentResolver resolver = mContext.getContentResolver(); 219 resolver.delete(uri, null, null); 220 } 221 222 long endTime = SystemClock.elapsedRealtime(); 223 Log.i(TAG, "Reset " + uri + ", takes " + (endTime - startTime) + " ms"); 224 }; 225 mResetSequence.add(runnable); 226 return this; 227 } 228 229 /** 230 * Append a step of resetting IMS stack. 231 * 232 * @return this 233 */ resetIms(int subId)234 public ResetNetworkOperationBuilder resetIms(int subId) { 235 attachSystemServiceWork(Context.TELEPHONY_SERVICE, 236 (Consumer<TelephonyManager>) tm -> { 237 if (subId == ResetNetworkRequest.INVALID_SUBSCRIPTION_ID) { 238 // Do nothing 239 return; 240 } 241 if (subId == ResetNetworkRequest.ALL_SUBSCRIPTION_ID) { 242 // Reset IMS for all slots 243 for (int slotIndex = 0; slotIndex < tm.getActiveModemCount(); slotIndex++) { 244 tm.resetIms(slotIndex); 245 Log.i(TAG, "IMS was reset for slot " + slotIndex); 246 } 247 } else { 248 // Reset IMS for the slot specified by the sucriptionId. 249 final int slotIndex = SubscriptionManager.getSlotIndex(subId); 250 tm.resetIms(slotIndex); 251 Log.i(TAG, "IMS was reset for slot " + slotIndex); 252 } 253 }); 254 return this; 255 } 256 257 /** 258 * Append a step to restart phone process by the help of TelephonyContentProvider. 259 * It's a no-op if TelephonyContentProvider doesn't exist. 260 * @return this 261 */ restartPhoneProcess()262 public ResetNetworkOperationBuilder restartPhoneProcess() { 263 Runnable runnable = () -> { 264 // Unstable content provider can avoid us getting killed together with phone process 265 try (ContentProviderClient client = getUnstableTelephonyContentProviderClient()) { 266 if (client != null) { 267 client.call(METHOD_RESTART_PHONE_PROCESS, /* arg= */ null, /* extra= */ null); 268 Log.i(TAG, "Phone process was restarted."); 269 } 270 } catch (RemoteException re) { 271 // It's normal to throw RE since phone process immediately dies 272 Log.i(TAG, "Phone process has been restarted: " + re); 273 } 274 }; 275 mResetSequence.add(runnable); 276 return this; 277 } 278 279 /** 280 * Append a step to restart RILD by the help of TelephonyContentProvider. 281 * It's a no-op if TelephonyContentProvider doesn't exist. 282 * @return this 283 */ restartRild()284 public ResetNetworkOperationBuilder restartRild() { 285 Runnable runnable = () -> { 286 try (ContentProviderClient client = getUnstableTelephonyContentProviderClient()) { 287 if (client != null) { 288 client.call(METHOD_RESTART_RILD, /* arg= */ null, /* extra= */ null); 289 Log.i(TAG, "RILD was restarted."); 290 } 291 } catch (RemoteException re) { 292 Log.w(TAG, "Fail to restart RILD: " + re); 293 } 294 }; 295 mResetSequence.add(runnable); 296 return this; 297 } 298 299 /** 300 * Construct a Runnable containing all operations appended. 301 * @return Runnable 302 */ build()303 public Runnable build() { 304 return () -> mResetSequence.forEach(runnable -> runnable.run()); 305 } 306 attachSystemServiceWork(String serviceName, Consumer<T> serviceAccess)307 protected <T> void attachSystemServiceWork(String serviceName, Consumer<T> serviceAccess) { 308 T service = (T) mContext.getSystemService(serviceName); 309 if (service == null) { 310 return; 311 } 312 Runnable runnable = () -> { 313 long startTime = SystemClock.elapsedRealtime(); 314 if (!DRY_RUN) { 315 serviceAccess.accept(service); 316 } 317 long endTime = SystemClock.elapsedRealtime(); 318 Log.i(TAG, "Reset " + serviceName + ", takes " + (endTime - startTime) + " ms"); 319 }; 320 mResetSequence.add(runnable); 321 } 322 323 /** 324 * @return the authority of the telephony content provider that support methods 325 * resetPhoneProcess and resetRild. 326 */ getResetTelephonyContentProviderAuthority()327 private String getResetTelephonyContentProviderAuthority() { 328 return mContext.getResources().getString( 329 R.string.reset_telephony_stack_content_provider_authority); 330 } 331 332 /** 333 * @return the unstable content provider to avoid us getting killed with phone process 334 */ 335 @Nullable 336 @VisibleForTesting getUnstableTelephonyContentProviderClient()337 public ContentProviderClient getUnstableTelephonyContentProviderClient() { 338 return mContext.getContentResolver().acquireUnstableContentProviderClient( 339 getResetTelephonyContentProviderAuthority()); 340 } 341 } 342