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 @Nullable 69 private Consumer<Boolean> mResetEsimResultCallback = null; 70 71 /** 72 * Constructor of builder. 73 * 74 * @param context Context 75 */ ResetNetworkOperationBuilder(Context context)76 public ResetNetworkOperationBuilder(Context context) { 77 mContext = context; 78 } 79 80 /** 81 * Append a step of resetting ConnectivityManager. 82 * @return this 83 */ resetConnectivityManager()84 public ResetNetworkOperationBuilder resetConnectivityManager() { 85 attachSystemServiceWork(Context.CONNECTIVITY_SERVICE, 86 (Consumer<ConnectivityManager>) cm -> { 87 cm.factoryReset(); 88 }); 89 return this; 90 } 91 92 /** 93 * Append a step of resetting VpnManager. 94 * @return this 95 */ resetVpnManager()96 public ResetNetworkOperationBuilder resetVpnManager() { 97 attachSystemServiceWork(Context.VPN_MANAGEMENT_SERVICE, 98 (Consumer<VpnManager>) vpnManager -> { 99 vpnManager.factoryReset(); 100 }); 101 return this; 102 } 103 104 /** 105 * Append a step of resetting WifiManager. 106 * @return this 107 */ resetWifiManager()108 public ResetNetworkOperationBuilder resetWifiManager() { 109 attachSystemServiceWork(Context.WIFI_SERVICE, 110 (Consumer<WifiManager>) wifiManager -> { 111 wifiManager.factoryReset(); 112 }); 113 return this; 114 } 115 116 /** 117 * Append a step of resetting WifiP2pManager. 118 * @param callbackLooper looper to support callback from WifiP2pManager 119 * @return this 120 */ resetWifiP2pManager(Looper callbackLooper)121 public ResetNetworkOperationBuilder resetWifiP2pManager(Looper callbackLooper) { 122 attachSystemServiceWork(Context.WIFI_P2P_SERVICE, 123 (Consumer<WifiP2pManager>) wifiP2pManager -> { 124 WifiP2pManager.Channel channel = wifiP2pManager.initialize( 125 mContext, callbackLooper, null /* listener */); 126 if (channel != null) { 127 wifiP2pManager.factoryReset(channel, null /* listener */); 128 } 129 }); 130 return this; 131 } 132 133 /** 134 * Append a result callback of resetting E-SIM. 135 * @param resultCallback a callback dealing with result of resetting eSIM 136 * @return this 137 */ resetEsimResultCallback(Consumer<Boolean> resultCallback)138 public ResetNetworkOperationBuilder resetEsimResultCallback(Consumer<Boolean> resultCallback) { 139 mResetEsimResultCallback = resultCallback; 140 return this; 141 } 142 143 /** 144 * Append a step of resetting E-SIM. 145 * @param callerPackage package name of caller 146 * @return this 147 */ resetEsim(String callerPackage)148 public ResetNetworkOperationBuilder resetEsim(String callerPackage) { 149 Runnable runnable = () -> { 150 long startTime = SystemClock.elapsedRealtime(); 151 152 boolean wipped; 153 if (DRY_RUN) { 154 wipped = true; 155 } else { 156 wipped = RecoverySystem.wipeEuiccData(mContext, callerPackage); 157 } 158 if (mResetEsimResultCallback != null) { 159 mResetEsimResultCallback.accept(wipped); 160 } 161 162 long endTime = SystemClock.elapsedRealtime(); 163 Log.i(TAG, "Reset eSIM, takes " + (endTime - startTime) + " ms"); 164 }; 165 mResetSequence.add(runnable); 166 return this; 167 } 168 169 /** 170 * Append a step of resetting TelephonyManager and . 171 * @param subscriptionId of a SIM card 172 * @return this 173 */ resetTelephonyAndNetworkPolicyManager( int subscriptionId)174 public ResetNetworkOperationBuilder resetTelephonyAndNetworkPolicyManager( 175 int subscriptionId) { 176 final AtomicReference<String> subscriberId = new AtomicReference<String>(); 177 attachSystemServiceWork(Context.TELEPHONY_SERVICE, 178 (Consumer<TelephonyManager>) tm -> { 179 TelephonyManager subIdTm = tm.createForSubscriptionId(subscriptionId); 180 subscriberId.set(subIdTm.getSubscriberId()); 181 subIdTm.resetSettings(); 182 }); 183 attachSystemServiceWork(Context.NETWORK_POLICY_SERVICE, 184 (Consumer<NetworkPolicyManager>) policyManager -> { 185 policyManager.factoryReset(subscriberId.get()); 186 }); 187 return this; 188 } 189 190 /** 191 * Append a step of resetting BluetoothAdapter. 192 * @return this 193 */ resetBluetoothManager()194 public ResetNetworkOperationBuilder resetBluetoothManager() { 195 attachSystemServiceWork(Context.BLUETOOTH_SERVICE, 196 (Consumer<BluetoothManager>) btManager -> { 197 BluetoothAdapter btAdapter = btManager.getAdapter(); 198 if (btAdapter != null) { 199 btAdapter.clearBluetooth(); 200 } 201 }); 202 return this; 203 } 204 205 /** 206 * Append a step of resetting APN configurations. 207 * @param subscriptionId of a SIM card 208 * @return this 209 */ resetApn(int subscriptionId)210 public ResetNetworkOperationBuilder resetApn(int subscriptionId) { 211 Runnable runnable = () -> { 212 long startTime = SystemClock.elapsedRealtime(); 213 214 Uri uri = PreferredApnRepository.getRestorePreferredApnUri(); 215 216 if (SubscriptionManager.isUsableSubscriptionId(subscriptionId)) { 217 uri = Uri.withAppendedPath(uri, "subId/" + String.valueOf(subscriptionId)); 218 } 219 220 if (!DRY_RUN) { 221 ContentResolver resolver = mContext.getContentResolver(); 222 resolver.delete(uri, null, null); 223 } 224 225 long endTime = SystemClock.elapsedRealtime(); 226 Log.i(TAG, "Reset " + uri + ", takes " + (endTime - startTime) + " ms"); 227 }; 228 mResetSequence.add(runnable); 229 return this; 230 } 231 232 /** 233 * Append a step of resetting IMS stack. 234 * 235 * @return this 236 */ resetIms(int subId)237 public ResetNetworkOperationBuilder resetIms(int subId) { 238 attachSystemServiceWork(Context.TELEPHONY_SERVICE, 239 (Consumer<TelephonyManager>) tm -> { 240 if (subId == ResetNetworkRequest.INVALID_SUBSCRIPTION_ID) { 241 // Do nothing 242 return; 243 } 244 if (subId == ResetNetworkRequest.ALL_SUBSCRIPTION_ID) { 245 // Reset IMS for all slots 246 for (int slotIndex = 0; slotIndex < tm.getActiveModemCount(); slotIndex++) { 247 tm.resetIms(slotIndex); 248 Log.i(TAG, "IMS was reset for slot " + slotIndex); 249 } 250 } else { 251 // Reset IMS for the slot specified by the sucriptionId. 252 final int slotIndex = SubscriptionManager.getSlotIndex(subId); 253 tm.resetIms(slotIndex); 254 Log.i(TAG, "IMS was reset for slot " + slotIndex); 255 } 256 }); 257 return this; 258 } 259 260 /** 261 * Append a step to restart phone process by the help of TelephonyContentProvider. 262 * It's a no-op if TelephonyContentProvider doesn't exist. 263 * @return this 264 */ restartPhoneProcess()265 public ResetNetworkOperationBuilder restartPhoneProcess() { 266 Runnable runnable = () -> { 267 // Unstable content provider can avoid us getting killed together with phone process 268 try (ContentProviderClient client = getUnstableTelephonyContentProviderClient()) { 269 if (client != null) { 270 client.call(METHOD_RESTART_PHONE_PROCESS, /* arg= */ null, /* extra= */ null); 271 Log.i(TAG, "Phone process was restarted."); 272 } 273 } catch (RemoteException re) { 274 // It's normal to throw RE since phone process immediately dies 275 Log.i(TAG, "Phone process has been restarted: " + re); 276 } 277 }; 278 mResetSequence.add(runnable); 279 return this; 280 } 281 282 /** 283 * Append a step to restart RILD by the help of TelephonyContentProvider. 284 * It's a no-op if TelephonyContentProvider doesn't exist. 285 * @return this 286 */ restartRild()287 public ResetNetworkOperationBuilder restartRild() { 288 Runnable runnable = () -> { 289 try (ContentProviderClient client = getUnstableTelephonyContentProviderClient()) { 290 if (client != null) { 291 client.call(METHOD_RESTART_RILD, /* arg= */ null, /* extra= */ null); 292 Log.i(TAG, "RILD was restarted."); 293 } 294 } catch (RemoteException re) { 295 Log.w(TAG, "Fail to restart RILD: " + re); 296 } 297 }; 298 mResetSequence.add(runnable); 299 return this; 300 } 301 302 /** 303 * Construct a Runnable containing all operations appended. 304 * @return Runnable 305 */ build()306 public Runnable build() { 307 return () -> mResetSequence.forEach(runnable -> runnable.run()); 308 } 309 attachSystemServiceWork(String serviceName, Consumer<T> serviceAccess)310 protected <T> void attachSystemServiceWork(String serviceName, Consumer<T> serviceAccess) { 311 T service = (T) mContext.getSystemService(serviceName); 312 if (service == null) { 313 return; 314 } 315 Runnable runnable = () -> { 316 long startTime = SystemClock.elapsedRealtime(); 317 if (!DRY_RUN) { 318 serviceAccess.accept(service); 319 } 320 long endTime = SystemClock.elapsedRealtime(); 321 Log.i(TAG, "Reset " + serviceName + ", takes " + (endTime - startTime) + " ms"); 322 }; 323 mResetSequence.add(runnable); 324 } 325 326 /** 327 * @return the authority of the telephony content provider that support methods 328 * resetPhoneProcess and resetRild. 329 */ getResetTelephonyContentProviderAuthority()330 private String getResetTelephonyContentProviderAuthority() { 331 return mContext.getResources().getString( 332 R.string.reset_telephony_stack_content_provider_authority); 333 } 334 335 /** 336 * @return the unstable content provider to avoid us getting killed with phone process 337 */ 338 @Nullable 339 @VisibleForTesting getUnstableTelephonyContentProviderClient()340 public ContentProviderClient getUnstableTelephonyContentProviderClient() { 341 return mContext.getContentResolver().acquireUnstableContentProviderClient( 342 getResetTelephonyContentProviderAuthority()); 343 } 344 } 345