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