• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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