• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.phone;
18 
19 import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_AUDIO_CODEC;
20 import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_RADIO_ACCESS_TYPE;
21 import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_BATTERY_STATE;
22 import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_NETWORK_COVERAGE;
23 
24 import static java.util.Map.entry;
25 
26 import android.Manifest;
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.net.Uri;
32 import android.os.Binder;
33 import android.os.PersistableBundle;
34 import android.os.Process;
35 import android.os.RemoteException;
36 import android.os.ServiceSpecificException;
37 import android.provider.BlockedNumberContract;
38 import android.telephony.BarringInfo;
39 import android.telephony.CarrierConfigManager;
40 import android.telephony.SubscriptionInfo;
41 import android.telephony.SubscriptionManager;
42 import android.telephony.TelephonyManager;
43 import android.telephony.TelephonyRegistryManager;
44 import android.telephony.emergency.EmergencyNumber;
45 import android.telephony.ims.ImsException;
46 import android.telephony.ims.RcsContactUceCapability;
47 import android.telephony.ims.feature.ImsFeature;
48 import android.text.TextUtils;
49 import android.util.ArrayMap;
50 import android.util.ArraySet;
51 import android.util.Log;
52 import android.util.SparseArray;
53 
54 import com.android.ims.rcs.uce.util.FeatureTags;
55 import com.android.internal.telephony.ITelephony;
56 import com.android.internal.telephony.Phone;
57 import com.android.internal.telephony.PhoneFactory;
58 import com.android.internal.telephony.d2d.Communicator;
59 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
60 import com.android.internal.telephony.util.TelephonyUtils;
61 import com.android.modules.utils.BasicShellCommandHandler;
62 import com.android.phone.callcomposer.CallComposerPictureManager;
63 import com.android.phone.euicc.EuiccUiDispatcherActivity;
64 import com.android.phone.utils.CarrierAllowListInfo;
65 
66 import java.io.IOException;
67 import java.io.PrintWriter;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.Collections;
71 import java.util.HashMap;
72 import java.util.List;
73 import java.util.Locale;
74 import java.util.Map;
75 import java.util.Set;
76 import java.util.TreeSet;
77 import java.util.UUID;
78 import java.util.concurrent.CompletableFuture;
79 
80 /**
81  * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
82  * permission checks have been done before onCommand was called. Make sure any commands processed
83  * here also contain the appropriate permissions checks.
84  */
85 
86 public class TelephonyShellCommand extends BasicShellCommandHandler {
87 
88     private static final String LOG_TAG = "TelephonyShellCommand";
89     // Don't commit with this true.
90     private static final boolean VDBG = true;
91     private static final int DEFAULT_PHONE_ID = 0;
92 
93     private static final String CALL_COMPOSER_SUBCOMMAND = "callcomposer";
94     private static final String IMS_SUBCOMMAND = "ims";
95     private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
96     private static final String EMERGENCY_CALLBACK_MODE = "emergency-callback-mode";
97     private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
98     private static final String END_BLOCK_SUPPRESSION = "end-block-suppression";
99     private static final String RESTART_MODEM = "restart-modem";
100     private static final String UNATTENDED_REBOOT = "unattended-reboot";
101     private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
102     private static final String DATA_TEST_MODE = "data";
103     private static final String ENABLE = "enable";
104     private static final String DISABLE = "disable";
105     private static final String QUERY = "query";
106     private static final String CARRIER_RESTRICTION_STATUS_TEST = "carrier_restriction_status_test";
107     private static final String SET_CARRIER_SERVICE_PACKAGE_OVERRIDE =
108             "set-carrier-service-package-override";
109     private static final String CLEAR_CARRIER_SERVICE_PACKAGE_OVERRIDE =
110             "clear-carrier-service-package-override";
111     private final String QUOTES = "\"";
112 
113     private static final String CALL_COMPOSER_TEST_MODE = "test-mode";
114     private static final String CALL_COMPOSER_SIMULATE_CALL = "simulate-outgoing-call";
115     private static final String CALL_COMPOSER_USER_SETTING = "user-setting";
116 
117     private static final String IMS_SET_IMS_SERVICE = "set-ims-service";
118     private static final String IMS_GET_IMS_SERVICE = "get-ims-service";
119     private static final String IMS_CLEAR_SERVICE_OVERRIDE = "clear-ims-service-override";
120     // Used to disable or enable processing of conference event package data from the network.
121     // This is handy for testing scenarios where CEP data does not exist on a network which does
122     // support CEP data.
123     private static final String IMS_CEP = "conference-event-package";
124 
125     private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
126     private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
127 
128     private static final String CC_GET_VALUE = "get-value";
129     private static final String CC_SET_VALUE = "set-value";
130     private static final String CC_SET_VALUES_FROM_XML = "set-values-from-xml";
131     private static final String CC_CLEAR_VALUES = "clear-values";
132 
133     private static final String EUICC_SUBCOMMAND = "euicc";
134     private static final String EUICC_SET_UI_COMPONENT = "set-euicc-uicomponent";
135 
136     private static final String GBA_SUBCOMMAND = "gba";
137     private static final String GBA_SET_SERVICE = "set-service";
138     private static final String GBA_GET_SERVICE = "get-service";
139     private static final String GBA_SET_RELEASE_TIME = "set-release";
140     private static final String GBA_GET_RELEASE_TIME = "get-release";
141 
142     private static final String SINGLE_REGISTATION_CONFIG = "src";
143     private static final String SRC_SET_DEVICE_ENABLED = "set-device-enabled";
144     private static final String SRC_GET_DEVICE_ENABLED = "get-device-enabled";
145     private static final String SRC_SET_CARRIER_ENABLED = "set-carrier-enabled";
146     private static final String SRC_GET_CARRIER_ENABLED = "get-carrier-enabled";
147     private static final String SRC_SET_TEST_ENABLED = "set-test-enabled";
148     private static final String SRC_GET_TEST_ENABLED = "get-test-enabled";
149     private static final String SRC_SET_FEATURE_ENABLED = "set-feature-validation";
150     private static final String SRC_GET_FEATURE_ENABLED = "get-feature-validation";
151 
152     private static final String D2D_SUBCOMMAND = "d2d";
153     private static final String D2D_SEND = "send";
154     private static final String D2D_TRANSPORT = "transport";
155     private static final String D2D_SET_DEVICE_SUPPORT = "set-device-support";
156 
157     private static final String BARRING_SUBCOMMAND = "barring";
158     private static final String BARRING_SEND_INFO = "send";
159 
160     private static final String RCS_UCE_COMMAND = "uce";
161     private static final String UCE_GET_EAB_CONTACT = "get-eab-contact";
162     private static final String UCE_GET_EAB_CAPABILITY = "get-eab-capability";
163     private static final String UCE_REMOVE_EAB_CONTACT = "remove-eab-contact";
164     private static final String UCE_GET_DEVICE_ENABLED = "get-device-enabled";
165     private static final String UCE_SET_DEVICE_ENABLED = "set-device-enabled";
166     private static final String UCE_OVERRIDE_PUBLISH_CAPS = "override-published-caps";
167     private static final String UCE_GET_LAST_PIDF_XML = "get-last-publish-pidf";
168     private static final String UCE_REMOVE_REQUEST_DISALLOWED_STATUS =
169             "remove-request-disallowed-status";
170     private static final String UCE_SET_CAPABILITY_REQUEST_TIMEOUT =
171             "set-capabilities-request-timeout";
172 
173     private static final String RADIO_SUBCOMMAND = "radio";
174     private static final String RADIO_SET_MODEM_SERVICE = "set-modem-service";
175     private static final String RADIO_GET_MODEM_SERVICE = "get-modem-service";
176 
177     // Check if a package has carrier privileges on any SIM, regardless of subId/phoneId.
178     private static final String HAS_CARRIER_PRIVILEGES_COMMAND = "has-carrier-privileges";
179 
180     private static final String DISABLE_PHYSICAL_SUBSCRIPTION = "disable-physical-subscription";
181     private static final String ENABLE_PHYSICAL_SUBSCRIPTION = "enable-physical-subscription";
182 
183     private static final String THERMAL_MITIGATION_COMMAND = "thermal-mitigation";
184     private static final String ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "allow-package";
185     private static final String DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "disallow-package";
186     private static final String SET_SATELLITE_SERVICE_PACKAGE_NAME =
187             "set-satellite-service-package-name";
188     private static final String SET_SATELLITE_GATEWAY_SERVICE_PACKAGE_NAME =
189             "set-satellite-gateway-service-package-name";
190     private static final String SET_SATELLITE_LISTENING_TIMEOUT_DURATION =
191             "set-satellite-listening-timeout-duration";
192     private static final String SET_SATELLITE_POINTING_UI_CLASS_NAME =
193             "set-satellite-pointing-ui-class-name";
194     private static final String SET_DATAGRAM_CONTROLLER_TIMEOUT_DURATION =
195             "set-datagram-controller-timeout-duration";
196     private static final String SET_DATAGRAM_CONTROLLER_BOOLEAN_CONFIG =
197             "set-datagram-controller-boolean-config";
198 
199     private static final String SET_SATELLITE_CONTROLLER_TIMEOUT_DURATION =
200             "set-satellite-controller-timeout-duration";
201     private static final String SET_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE =
202             "set-emergency-call-to-satellite-handover-type";
203     private static final String SET_COUNTRY_CODES = "set-country-codes";
204     private static final String SET_SATELLITE_ACCESS_CONTROL_OVERLAY_CONFIGS =
205             "set-satellite-access-control-overlay-configs";
206     private static final String SET_OEM_ENABLED_SATELLITE_PROVISION_STATUS =
207             "set-oem-enabled-satellite-provision-status";
208     private static final String SET_SHOULD_SEND_DATAGRAM_TO_MODEM_IN_DEMO_MODE =
209             "set-should-send-datagram-to-modem-in-demo-mode";
210     private static final String SET_IS_SATELLITE_COMMUNICATION_ALLOWED_FOR_CURRENT_LOCATION_CACHE =
211             "set-is-satellite-communication-allowed-for-current-location-cache";
212 
213     private static final String DOMAIN_SELECTION_SUBCOMMAND = "domainselection";
214     private static final String DOMAIN_SELECTION_SET_SERVICE_OVERRIDE = "set-dss-override";
215     private static final String DOMAIN_SELECTION_CLEAR_SERVICE_OVERRIDE = "clear-dss-override";
216 
217     private static final String INVALID_ENTRY_ERROR = "An emergency number (only allow '0'-'9', "
218             + "'*', '#' or '+') needs to be specified after -a in the command ";
219 
220     private static final int[] ROUTING_TYPES = {EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN,
221             EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY,
222             EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL};
223 
224     private static final String GET_ALLOWED_NETWORK_TYPES_FOR_USER =
225             "get-allowed-network-types-for-users";
226     private static final String SET_ALLOWED_NETWORK_TYPES_FOR_USER =
227             "set-allowed-network-types-for-users";
228     private static final String GET_IMEI = "get-imei";
229     private static final String GET_SIM_SLOTS_MAPPING = "get-sim-slots-mapping";
230     // Take advantage of existing methods that already contain permissions checks when possible.
231     private final ITelephony mInterface;
232 
233     private SubscriptionManager mSubscriptionManager;
234     private CarrierConfigManager mCarrierConfigManager;
235     private TelephonyRegistryManager mTelephonyRegistryManager;
236     private Context mContext;
237 
238     private enum CcType {
239         BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
240                 STRING_ARRAY, PERSISTABLE_BUNDLE, UNKNOWN
241     }
242 
243     private class CcOptionParseResult {
244         public int mSubId;
245         public boolean mPersistent;
246     }
247 
248     // Maps carrier config keys to type. It is possible to infer the type for most carrier config
249     // keys by looking at the end of the string which usually tells the type.
250     // For instance: "xxxx_string", "xxxx_string_array", etc.
251     // The carrier config keys in this map does not follow this convention. It is therefore not
252     // possible to infer the type for these keys by looking at the string.
253     private static final Map<String, CcType> CC_TYPE_MAP = Map.ofEntries(
254             entry(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING,
255                     CcType.STRING),
256             entry(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING),
257             entry(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING),
258             entry(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING),
259             entry(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING),
260             entry(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING),
261             entry(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING),
262             entry(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING),
263             entry(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING),
264             entry(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING),
265             entry(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
266                     CcType.STRING),
267             entry(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
268                     CcType.STRING_ARRAY),
269             entry(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
270                     CcType.STRING_ARRAY),
271             entry(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING),
272             entry(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING),
273             entry(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING),
274             entry(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING),
275             entry(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING),
276             entry(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING),
277             entry(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING),
278             entry(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY));
279 
280     /**
281      * Map from a shorthand string to the feature tags required in registration required in order
282      * for the RCS feature to be considered "capable".
283      */
284     private static final Map<String, Set<String>> TEST_FEATURE_TAG_MAP;
285     static {
286         ArrayMap<String, Set<String>> map = new ArrayMap<>(18);
287         map.put("chat_v1", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_IM));
288         map.put("chat_v2", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_SESSION));
289         map.put("ft", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER));
290         map.put("ft_sms", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS));
291         map.put("mmtel", Collections.singleton(FeatureTags.FEATURE_TAG_MMTEL));
292         map.put("mmtel_vt", new ArraySet<>(Arrays.asList(FeatureTags.FEATURE_TAG_MMTEL,
293                 FeatureTags.FEATURE_TAG_VIDEO)));
294         map.put("geo_push", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH));
295         map.put("geo_push_sms", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS));
296         map.put("call_comp",
297                 Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING));
298         map.put("call_comp_mmtel",
299                 Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY));
300         map.put("call_post", Collections.singleton(FeatureTags.FEATURE_TAG_POST_CALL));
301         map.put("map", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_MAP));
302         map.put("sketch", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_SKETCH));
303         // Feature tags defined twice for chatbot session because we want v1 and v2 based on bot
304         // version
305         map.put("chatbot", new ArraySet<>(Arrays.asList(
306                 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION,
307                 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
308         map.put("chatbot_v2", new ArraySet<>(Arrays.asList(
309                 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION,
310                 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_V2_SUPPORTED)));
311         map.put("chatbot_sa", new ArraySet<>(Arrays.asList(
312                 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG,
313                 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
314         map.put("chatbot_sa_v2", new ArraySet<>(Arrays.asList(
315                 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG,
316                 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_V2_SUPPORTED)));
317         map.put("chatbot_role", Collections.singleton(FeatureTags.FEATURE_TAG_CHATBOT_ROLE));
318         TEST_FEATURE_TAG_MAP = Collections.unmodifiableMap(map);
319     }
320 
321 
TelephonyShellCommand(ITelephony binder, Context context)322     public TelephonyShellCommand(ITelephony binder, Context context) {
323         mInterface = binder;
324         mCarrierConfigManager =
325                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
326         mSubscriptionManager = (SubscriptionManager)
327                 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
328         mTelephonyRegistryManager = (TelephonyRegistryManager)
329                 context.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
330         mContext = context;
331     }
332 
333     @Override
onCommand(String cmd)334     public int onCommand(String cmd) {
335         if (cmd == null) {
336             return handleDefaultCommands(null);
337         }
338 
339         switch (cmd) {
340             case IMS_SUBCOMMAND: {
341                 return handleImsCommand();
342             }
343             case RCS_UCE_COMMAND:
344                 return handleRcsUceCommand();
345             case NUMBER_VERIFICATION_SUBCOMMAND:
346                 return handleNumberVerificationCommand();
347             case EMERGENCY_CALLBACK_MODE:
348                 return handleEmergencyCallbackModeCommand();
349             case EMERGENCY_NUMBER_TEST_MODE:
350                 return handleEmergencyNumberTestModeCommand();
351             case CARRIER_CONFIG_SUBCOMMAND: {
352                 return handleCcCommand();
353             }
354             case DATA_TEST_MODE:
355                 return handleDataTestModeCommand();
356             case END_BLOCK_SUPPRESSION:
357                 return handleEndBlockSuppressionCommand();
358             case EUICC_SUBCOMMAND:
359                 return handleEuiccCommand();
360             case GBA_SUBCOMMAND:
361                 return handleGbaCommand();
362             case D2D_SUBCOMMAND:
363                 return handleD2dCommand();
364             case BARRING_SUBCOMMAND:
365                 return handleBarringCommand();
366             case SINGLE_REGISTATION_CONFIG:
367                 return handleSingleRegistrationConfigCommand();
368             case RESTART_MODEM:
369                 return handleRestartModemCommand();
370             case CALL_COMPOSER_SUBCOMMAND:
371                 return handleCallComposerCommand();
372             case UNATTENDED_REBOOT:
373                 return handleUnattendedReboot();
374             case HAS_CARRIER_PRIVILEGES_COMMAND:
375                 return handleHasCarrierPrivilegesCommand();
376             case THERMAL_MITIGATION_COMMAND:
377                 return handleThermalMitigationCommand();
378             case DISABLE_PHYSICAL_SUBSCRIPTION:
379                 return handleEnablePhysicalSubscription(false);
380             case ENABLE_PHYSICAL_SUBSCRIPTION:
381                 return handleEnablePhysicalSubscription(true);
382             case GET_ALLOWED_NETWORK_TYPES_FOR_USER:
383             case SET_ALLOWED_NETWORK_TYPES_FOR_USER:
384                 return handleAllowedNetworkTypesCommand(cmd);
385             case GET_IMEI:
386                 return handleGetImei();
387             case GET_SIM_SLOTS_MAPPING:
388                 return handleGetSimSlotsMapping();
389             case RADIO_SUBCOMMAND:
390                 return handleRadioCommand();
391             case CARRIER_RESTRICTION_STATUS_TEST:
392                 return handleCarrierRestrictionStatusCommand();
393             case SET_CARRIER_SERVICE_PACKAGE_OVERRIDE:
394                 return setCarrierServicePackageOverride();
395             case CLEAR_CARRIER_SERVICE_PACKAGE_OVERRIDE:
396                 return clearCarrierServicePackageOverride();
397             case DOMAIN_SELECTION_SUBCOMMAND:
398                 return handleDomainSelectionCommand();
399             case SET_SATELLITE_SERVICE_PACKAGE_NAME:
400                 return handleSetSatelliteServicePackageNameCommand();
401             case SET_SATELLITE_GATEWAY_SERVICE_PACKAGE_NAME:
402                 return handleSetSatelliteGatewayServicePackageNameCommand();
403             case SET_SATELLITE_LISTENING_TIMEOUT_DURATION:
404                 return handleSetSatelliteListeningTimeoutDuration();
405             case SET_SATELLITE_POINTING_UI_CLASS_NAME:
406                 return handleSetSatellitePointingUiClassNameCommand();
407             case SET_DATAGRAM_CONTROLLER_TIMEOUT_DURATION:
408                 return handleSetDatagramControllerTimeoutDuration();
409             case SET_DATAGRAM_CONTROLLER_BOOLEAN_CONFIG:
410                 return handleSetDatagramControllerBooleanConfig();
411             case SET_SATELLITE_CONTROLLER_TIMEOUT_DURATION:
412                 return handleSetSatelliteControllerTimeoutDuration();
413             case SET_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE:
414                 return handleSetEmergencyCallToSatelliteHandoverType();
415             case SET_SHOULD_SEND_DATAGRAM_TO_MODEM_IN_DEMO_MODE:
416                 return handleSetShouldSendDatagramToModemInDemoMode();
417             case SET_SATELLITE_ACCESS_CONTROL_OVERLAY_CONFIGS:
418                 return handleSetSatelliteAccessControlOverlayConfigs();
419             case SET_COUNTRY_CODES:
420                 return handleSetCountryCodes();
421             case SET_OEM_ENABLED_SATELLITE_PROVISION_STATUS:
422                 return handleSetOemEnabledSatelliteProvisionStatus();
423             case SET_IS_SATELLITE_COMMUNICATION_ALLOWED_FOR_CURRENT_LOCATION_CACHE:
424                 return handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache();
425             default: {
426                 return handleDefaultCommands(cmd);
427             }
428         }
429     }
430 
431     @Override
onHelp()432     public void onHelp() {
433         PrintWriter pw = getOutPrintWriter();
434         pw.println("Telephony Commands:");
435         pw.println("  help");
436         pw.println("    Print this help text.");
437         pw.println("  ims");
438         pw.println("    IMS Commands.");
439         pw.println("  uce");
440         pw.println("    RCS User Capability Exchange Commands.");
441         pw.println("  emergency-number-test-mode");
442         pw.println("    Emergency Number Test Mode Commands.");
443         pw.println("  end-block-suppression");
444         pw.println("    End Block Suppression command.");
445         pw.println("  data");
446         pw.println("    Data Test Mode Commands.");
447         pw.println("  cc");
448         pw.println("    Carrier Config Commands.");
449         pw.println("  gba");
450         pw.println("    GBA Commands.");
451         pw.println("  src");
452         pw.println("    RCS VoLTE Single Registration Config Commands.");
453         pw.println("  restart-modem");
454         pw.println("    Restart modem command.");
455         pw.println("  unattended-reboot");
456         pw.println("    Prepare for unattended reboot.");
457         pw.println("  has-carrier-privileges [package]");
458         pw.println("    Query carrier privilege status for a package. Prints true or false.");
459         pw.println("  get-allowed-network-types-for-users");
460         pw.println("    Get the Allowed Network Types.");
461         pw.println("  set-allowed-network-types-for-users");
462         pw.println("    Set the Allowed Network Types.");
463         pw.println("  radio");
464         pw.println("    Radio Commands.");
465         onHelpIms();
466         onHelpUce();
467         onHelpEmergencyNumber();
468         onHelpEndBlockSupperssion();
469         onHelpDataTestMode();
470         onHelpCc();
471         onHelpGba();
472         onHelpSrc();
473         onHelpD2D();
474         onHelpDisableOrEnablePhysicalSubscription();
475         onHelpAllowedNetworkTypes();
476         onHelpRadio();
477         onHelpImei();
478         onHelpSatellite();
479         onHelpDomainSelection();
480     }
481 
onHelpD2D()482     private void onHelpD2D() {
483         PrintWriter pw = getOutPrintWriter();
484         pw.println("D2D Comms Commands:");
485         pw.println("  d2d send TYPE VALUE");
486         pw.println("    Sends a D2D message of specified type and value.");
487         pw.println("    Type: " + MESSAGE_CALL_RADIO_ACCESS_TYPE + " - "
488                 + Communicator.messageToString(MESSAGE_CALL_RADIO_ACCESS_TYPE));
489         pw.println("    Type: " + MESSAGE_CALL_AUDIO_CODEC + " - " + Communicator.messageToString(
490                 MESSAGE_CALL_AUDIO_CODEC));
491         pw.println("    Type: " + MESSAGE_DEVICE_BATTERY_STATE + " - "
492                         + Communicator.messageToString(
493                         MESSAGE_DEVICE_BATTERY_STATE));
494         pw.println("    Type: " + MESSAGE_DEVICE_NETWORK_COVERAGE + " - "
495                 + Communicator.messageToString(MESSAGE_DEVICE_NETWORK_COVERAGE));
496         pw.println("  d2d transport TYPE");
497         pw.println("    Forces the specified D2D transport TYPE to be active.  Use the");
498         pw.println("    short class name of the transport; i.e. DtmfTransport or RtpTransport.");
499         pw.println("  d2d set-device-support true/default");
500         pw.println("    true - forces device support to be enabled for D2D.");
501         pw.println("    default - clear any previously set force-enable of D2D, reverting to ");
502         pw.println("    the current device's configuration.");
503     }
504 
onHelpBarring()505     private void onHelpBarring() {
506         PrintWriter pw = getOutPrintWriter();
507         pw.println("Barring Commands:");
508         pw.println("  barring send -s SLOT_ID -b BARRING_TYPE -c IS_CONDITIONALLY_BARRED"
509                 + " -t CONDITIONAL_BARRING_TIME_SECS");
510         pw.println("    Notifies of a barring info change for the specified slot id.");
511         pw.println("    BARRING_TYPE: 0 for BARRING_TYPE_NONE");
512         pw.println("    BARRING_TYPE: 1 for BARRING_TYPE_UNCONDITIONAL");
513         pw.println("    BARRING_TYPE: 2 for BARRING_TYPE_CONDITIONAL");
514         pw.println("    BARRING_TYPE: -1 for BARRING_TYPE_UNKNOWN");
515     }
516 
onHelpIms()517     private void onHelpIms() {
518         PrintWriter pw = getOutPrintWriter();
519         pw.println("IMS Commands:");
520         pw.println("  ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
521         pw.println("    Sets the ImsService defined in PACKAGE_NAME to to be the bound");
522         pw.println("    ImsService. Options are:");
523         pw.println("      -s: the slot ID that the ImsService should be bound for. If no option");
524         pw.println("          is specified, it will choose the default voice SIM slot.");
525         pw.println("      -c: Override the ImsService defined in the carrier configuration.");
526         pw.println("      -d: Override the ImsService defined in the device overlay.");
527         pw.println("      -f: Set the feature that this override if for, if no option is");
528         pw.println("          specified, the new package name will be used for all features.");
529         pw.println("  ims get-ims-service [-s SLOT_ID] [-c | -d]");
530         pw.println("    Gets the package name of the currently defined ImsService.");
531         pw.println("    Options are:");
532         pw.println("      -s: The SIM slot ID for the registered ImsService. If no option");
533         pw.println("          is specified, it will choose the default voice SIM slot.");
534         pw.println("      -c: The ImsService defined as the carrier configured ImsService.");
535         pw.println("      -d: The ImsService defined as the device default ImsService.");
536         pw.println("      -f: The feature type that the query will be requested for. If none is");
537         pw.println("          specified, the returned package name will correspond to MMTEL.");
538         pw.println("  ims clear-ims-service-override [-s SLOT_ID]");
539         pw.println("    Clear all carrier ImsService overrides. This does not work for device ");
540         pw.println("    configuration overrides. Options are:");
541         pw.println("      -s: The SIM slot ID for the registered ImsService. If no option");
542         pw.println("          is specified, it will choose the default voice SIM slot.");
543         pw.println("  ims enable [-s SLOT_ID]");
544         pw.println("    enables IMS for the SIM slot specified, or for the default voice SIM slot");
545         pw.println("    if none is specified.");
546         pw.println("  ims disable [-s SLOT_ID]");
547         pw.println("    disables IMS for the SIM slot specified, or for the default voice SIM");
548         pw.println("    slot if none is specified.");
549         pw.println("  ims conference-event-package [enable/disable]");
550         pw.println("    enables or disables handling or network conference event package data.");
551     }
552 
onHelpUce()553     private void onHelpUce() {
554         PrintWriter pw = getOutPrintWriter();
555         pw.println("User Capability Exchange Commands:");
556         pw.println("  uce get-eab-contact [PHONE_NUMBER]");
557         pw.println("    Get the EAB contacts from the EAB database.");
558         pw.println("    Options are:");
559         pw.println("      PHONE_NUMBER: The phone numbers to be removed from the EAB databases");
560         pw.println("    Expected output format :");
561         pw.println("      [PHONE_NUMBER],[RAW_CONTACT_ID],[CONTACT_ID],[DATA_ID]");
562         pw.println("  uce remove-eab-contact [-s SLOT_ID] [PHONE_NUMBER]");
563         pw.println("    Remove the EAB contacts from the EAB database.");
564         pw.println("    Options are:");
565         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
566         pw.println("          is specified, it will choose the default voice SIM slot.");
567         pw.println("      PHONE_NUMBER: The phone numbers to be removed from the EAB databases");
568         pw.println("  uce get-device-enabled");
569         pw.println("    Get the config to check whether the device supports RCS UCE or not.");
570         pw.println("  uce set-device-enabled true|false");
571         pw.println("    Set the device config for RCS User Capability Exchange to the value.");
572         pw.println("    The value could be true, false.");
573         pw.println("  uce override-published-caps [-s SLOT_ID] add|remove|clear [CAPABILITIES]");
574         pw.println("    Override the existing SIP PUBLISH with different capabilities.");
575         pw.println("    Options are:");
576         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
577         pw.println("          is specified, it will choose the default voice SIM slot.");
578         pw.println("      add [CAPABILITY]: add a new capability");
579         pw.println("      remove [CAPABILITY]: remove a capability");
580         pw.println("      clear: clear all capability overrides");
581         pw.println("      CAPABILITY: \":\" separated list of capabilities.");
582         pw.println("          Valid options are: [mmtel(_vt), chat_v1, chat_v2, ft, ft_sms,");
583         pw.println("          geo_push, geo_push_sms, call_comp, call_post, map, sketch, chatbot,");
584         pw.println("          chatbot_sa, chatbot_role] as well as full length");
585         pw.println("          featureTag=\"featureValue\" feature tags that are not defined here.");
586         pw.println("  uce get-last-publish-pidf [-s SLOT_ID]");
587         pw.println("    Get the PIDF XML included in the last SIP PUBLISH, or \"none\" if no ");
588         pw.println("    PUBLISH is active");
589         pw.println("  uce remove-request-disallowed-status [-s SLOT_ID]");
590         pw.println("    Remove the UCE is disallowed to execute UCE requests status");
591         pw.println("  uce set-capabilities-request-timeout [-s SLOT_ID] [REQUEST_TIMEOUT_MS]");
592         pw.println("    Set the timeout for contact capabilities request.");
593     }
594 
onHelpNumberVerification()595     private void onHelpNumberVerification() {
596         PrintWriter pw = getOutPrintWriter();
597         pw.println("Number verification commands");
598         pw.println("  numverify override-package PACKAGE_NAME;");
599         pw.println("    Set the authorized package for number verification.");
600         pw.println("    Leave the package name blank to reset.");
601         pw.println("  numverify fake-call NUMBER;");
602         pw.println("    Fake an incoming call from NUMBER. This is for testing. Output will be");
603         pw.println("    1 if the call would have been intercepted, 0 otherwise.");
604     }
605 
onHelpThermalMitigation()606     private void onHelpThermalMitigation() {
607         PrintWriter pw = getOutPrintWriter();
608         pw.println("Thermal mitigation commands");
609         pw.println("  thermal-mitigation allow-package PACKAGE_NAME");
610         pw.println("    Set the package as one of authorized packages for thermal mitigation.");
611         pw.println("  thermal-mitigation disallow-package PACKAGE_NAME");
612         pw.println("    Remove the package from one of the authorized packages for thermal "
613                 + "mitigation.");
614     }
615 
onHelpDisableOrEnablePhysicalSubscription()616     private void onHelpDisableOrEnablePhysicalSubscription() {
617         PrintWriter pw = getOutPrintWriter();
618         pw.println("Disable or enable a physical subscription");
619         pw.println("  disable-physical-subscription SUB_ID");
620         pw.println("    Disable the physical subscription with the provided subId, if allowed.");
621         pw.println("  enable-physical-subscription SUB_ID");
622         pw.println("    Enable the physical subscription with the provided subId, if allowed.");
623     }
624 
onHelpDataTestMode()625     private void onHelpDataTestMode() {
626         PrintWriter pw = getOutPrintWriter();
627         pw.println("Mobile Data Test Mode Commands:");
628         pw.println("  data enable: enable mobile data connectivity");
629         pw.println("  data disable: disable mobile data connectivity");
630     }
631 
onHelpEmergencyNumber()632     private void onHelpEmergencyNumber() {
633         PrintWriter pw = getOutPrintWriter();
634         pw.println("Emergency Number Test Mode Commands:");
635         pw.println("  emergency-number-test-mode ");
636         pw.println("    Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
637                 + " the test mode");
638         pw.println("      -a <emergency number address>: add an emergency number address for the"
639                 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
640         pw.println("      -c: clear the emergency number list in the test mode.");
641         pw.println("      -r <emergency number address>: remove an existing emergency number"
642                 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
643         pw.println("      -p: get the full emergency number list in the test mode.");
644     }
645 
onHelpEndBlockSupperssion()646     private void onHelpEndBlockSupperssion() {
647         PrintWriter pw = getOutPrintWriter();
648         pw.println("End Block Suppression command:");
649         pw.println("  end-block-suppression: disable suppressing blocking by contact");
650         pw.println("                         with emergency services.");
651     }
652 
onHelpCc()653     private void onHelpCc() {
654         PrintWriter pw = getOutPrintWriter();
655         pw.println("Carrier Config Commands:");
656         pw.println("  cc get-value [-s SLOT_ID] [KEY]");
657         pw.println("    Print carrier config values.");
658         pw.println("    Options are:");
659         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
660         pw.println("          is specified, it will choose the default voice SIM slot.");
661         pw.println("    KEY: The key to the carrier config value to print. All values are printed");
662         pw.println("         if KEY is not specified.");
663         pw.println("  cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
664         pw.println("    Set carrier config KEY to NEW_VALUE.");
665         pw.println("    Options are:");
666         pw.println("      -s: The SIM slot ID to set carrier config value for. If no option");
667         pw.println("          is specified, it will choose the default voice SIM slot.");
668         pw.println("      -p: Value will be stored persistent");
669         pw.println("    NEW_VALUE specifies the new value for carrier config KEY. Null will be");
670         pw.println("      used if NEW_VALUE is not set. Strings should be encapsulated with");
671         pw.println("      quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
672         pw.println("      Separate items in arrays with space . Example: \"item1\" \"item2\"");
673         pw.println("  cc set-values-from-xml [-s SLOT_ID] [-p] < XML_FILE_PATH");
674         pw.println("    Set carrier config based on the contents of the XML_FILE. File must be");
675         pw.println("    provided through standard input and follow CarrierConfig XML format.");
676         pw.println("    Example: packages/apps/CarrierConfig/assets/*.xml");
677         pw.println("    Options are:");
678         pw.println("      -s: The SIM slot ID to set carrier config value for. If no option");
679         pw.println("          is specified, it will choose the default voice SIM slot.");
680         pw.println("      -p: Value will be stored persistent");
681         pw.println("  cc clear-values [-s SLOT_ID]");
682         pw.println("    Clear all carrier override values that has previously been set");
683         pw.println("    with set-value or set-values-from-xml");
684         pw.println("    Options are:");
685         pw.println("      -s: The SIM slot ID to clear carrier config values for. If no option");
686         pw.println("          is specified, it will choose the default voice SIM slot.");
687     }
688 
onHelpEuicc()689     private void onHelpEuicc() {
690         PrintWriter pw = getOutPrintWriter();
691         pw.println("Euicc Commands:");
692         pw.println("  euicc set-euicc-uicomponent COMPONENT_NAME PACKAGE_NAME");
693         pw.println("  Sets the Euicc Ui-Component which handles EuiccService Actions.");
694         pw.println("  COMPONENT_NAME: The component name which handles UI Actions.");
695         pw.println("  PACKAGE_NAME: THe package name in which ui component belongs.");
696     }
697 
onHelpGba()698     private void onHelpGba() {
699         PrintWriter pw = getOutPrintWriter();
700         pw.println("Gba Commands:");
701         pw.println("  gba set-service [-s SLOT_ID] PACKAGE_NAME");
702         pw.println("    Sets the GbaService defined in PACKAGE_NAME to to be the bound.");
703         pw.println("    Options are:");
704         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
705         pw.println("          is specified, it will choose the default voice SIM slot.");
706         pw.println("  gba get-service [-s SLOT_ID]");
707         pw.println("    Gets the package name of the currently defined GbaService.");
708         pw.println("    Options are:");
709         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
710         pw.println("          is specified, it will choose the default voice SIM slot.");
711         pw.println("  gba set-release [-s SLOT_ID] n");
712         pw.println("    Sets the time to release/unbind GbaService in n milli-second.");
713         pw.println("    Do not release/unbind if n is -1.");
714         pw.println("    Options are:");
715         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
716         pw.println("          is specified, it will choose the default voice SIM slot.");
717         pw.println("  gba get-release [-s SLOT_ID]");
718         pw.println("    Gets the time to release/unbind GbaService in n milli-sencond.");
719         pw.println("    Options are:");
720         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
721         pw.println("          is specified, it will choose the default voice SIM slot.");
722     }
723 
onHelpSrc()724     private void onHelpSrc() {
725         PrintWriter pw = getOutPrintWriter();
726         pw.println("RCS VoLTE Single Registration Config Commands:");
727         pw.println("  src set-test-enabled true|false");
728         pw.println("    Sets the test mode enabled for RCS VoLTE single registration.");
729         pw.println("    The value could be true, false, or null(undefined).");
730         pw.println("  src get-test-enabled");
731         pw.println("    Gets the test mode for RCS VoLTE single registration.");
732         pw.println("  src set-device-enabled true|false|null");
733         pw.println("    Sets the device config for RCS VoLTE single registration to the value.");
734         pw.println("    The value could be true, false, or null(undefined).");
735         pw.println("  src get-device-enabled");
736         pw.println("    Gets the device config for RCS VoLTE single registration.");
737         pw.println("  src set-carrier-enabled [-s SLOT_ID] true|false|null");
738         pw.println("    Sets the carrier config for RCS VoLTE single registration to the value.");
739         pw.println("    The value could be true, false, or null(undefined).");
740         pw.println("    Options are:");
741         pw.println("      -s: The SIM slot ID to set the config value for. If no option");
742         pw.println("          is specified, it will choose the default voice SIM slot.");
743         pw.println("  src get-carrier-enabled [-s SLOT_ID]");
744         pw.println("    Gets the carrier config for RCS VoLTE single registration.");
745         pw.println("    Options are:");
746         pw.println("      -s: The SIM slot ID to read the config value for. If no option");
747         pw.println("          is specified, it will choose the default voice SIM slot.");
748         pw.println("  src set-feature-validation [-s SLOT_ID] true|false|null");
749         pw.println("    Sets ims feature validation result.");
750         pw.println("    The value could be true, false, or null(undefined).");
751         pw.println("    Options are:");
752         pw.println("      -s: The SIM slot ID to set the config value for. If no option");
753         pw.println("          is specified, it will choose the default voice SIM slot.");
754         pw.println("  src get-feature-validation [-s SLOT_ID]");
755         pw.println("    Gets ims feature validation override value.");
756         pw.println("    Options are:");
757         pw.println("      -s: The SIM slot ID to read the config value for. If no option");
758         pw.println("          is specified, it will choose the default voice SIM slot.");
759     }
760 
onHelpAllowedNetworkTypes()761     private void onHelpAllowedNetworkTypes() {
762         PrintWriter pw = getOutPrintWriter();
763         pw.println("Allowed Network Types Commands:");
764         pw.println("  get-allowed-network-types-for-users [-s SLOT_ID]");
765         pw.println("    Print allowed network types value.");
766         pw.println("    Options are:");
767         pw.println("      -s: The SIM slot ID to read allowed network types value for. If no");
768         pw.println("          option is specified, it will choose the default voice SIM slot.");
769         pw.println("  set-allowed-network-types-for-users [-s SLOT_ID] [NETWORK_TYPES_BITMASK]");
770         pw.println("    Sets allowed network types to NETWORK_TYPES_BITMASK.");
771         pw.println("    Options are:");
772         pw.println("      -s: The SIM slot ID to set allowed network types value for. If no");
773         pw.println("          option is specified, it will choose the default voice SIM slot.");
774         pw.println("    NETWORK_TYPES_BITMASK specifies the new network types value and this type");
775         pw.println("      is bitmask in binary format. Reference the NetworkTypeBitMask");
776         pw.println("      at TelephonyManager.java");
777         pw.println("      For example:");
778         pw.println("        NR only                    : 10000000000000000000");
779         pw.println("        NR|LTE                     : 11000001000000000000");
780         pw.println("        NR|LTE|CDMA|EVDO|GSM|WCDMA : 11001111101111111111");
781         pw.println("        LTE|CDMA|EVDO|GSM|WCDMA    : 01001111101111111111");
782         pw.println("        LTE only                   : 01000001000000000000");
783     }
784 
onHelpRadio()785     private void onHelpRadio() {
786         PrintWriter pw = getOutPrintWriter();
787         pw.println("Radio Commands:");
788         pw.println("  radio set-modem-service [-s SERVICE_NAME]");
789         pw.println("    Sets the class name of modem service defined in SERVICE_NAME");
790         pw.println("    to be the bound. Options are:");
791         pw.println("      -s: the service name that the modem service should be bound for.");
792         pw.println("          If no option is specified, it will bind to the default.");
793         pw.println("  radio get-modem-service");
794         pw.println("    Gets the service name of the currently defined modem service.");
795         pw.println("    If it is binding to default, 'default' returns.");
796         pw.println("    If it doesn't bind to any modem service for some reasons,");
797         pw.println("    the result would be 'unknown'.");
798     }
799 
onHelpSatellite()800     private void onHelpSatellite() {
801         PrintWriter pw = getOutPrintWriter();
802         pw.println("Satellite Commands:");
803         pw.println("  set-satellite-service-package-name [-s SERVICE_PACKAGE_NAME]");
804         pw.println("    Sets the package name of satellite service defined in");
805         pw.println("    SERVICE_PACKAGE_NAME to be bound. Options are:");
806         pw.println("      -s: the satellite service package name that Telephony will bind to.");
807         pw.println("          If no option is specified, it will bind to the default.");
808         pw.println("  set-satellite-gateway-service-package-name [-s SERVICE_PACKAGE_NAME]");
809         pw.println("    Sets the package name of satellite gateway service defined in");
810         pw.println("    SERVICE_PACKAGE_NAME to be bound. Options are:");
811         pw.println("      -s: the satellite gateway service package name that Telephony will bind");
812         pw.println("           to. If no option is specified, it will bind to the default.");
813         pw.println("  set-satellite-listening-timeout-duration [-t TIMEOUT_MILLIS]");
814         pw.println("    Sets the timeout duration in millis that satellite will stay at listening");
815         pw.println("    mode. Options are:");
816         pw.println("      -t: the timeout duration in milliseconds.");
817         pw.println("          If no option is specified, it will use the default values.");
818         pw.println("  set-satellite-pointing-ui-class-name [-p PACKAGE_NAME -c CLASS_NAME]");
819         pw.println("    Sets the package and class name of satellite pointing UI app defined in");
820         pw.println("    PACKAGE_NAME and CLASS_NAME to be launched. Options are:");
821         pw.println("      -p: the satellite pointing UI app package name that Telephony will");
822         pw.println("           launch. If no option is specified, it will launch the default.");
823         pw.println("      -c: the satellite pointing UI app class name that Telephony will");
824         pw.println("           launch.");
825         pw.println("  set-emergency-call-to-satellite-handover-type [-t HANDOVER_TYPE ");
826         pw.println("    -d DELAY_SECONDS] Override connectivity status in monitoring emergency ");
827         pw.println("    call and sending EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.");
828         pw.println("    Options are:");
829         pw.println("      -t: the emergency call to satellite handover type.");
830         pw.println("          If no option is specified, override is disabled.");
831         pw.println("      -d: the delay in seconds in sending EVENT_DISPLAY_EMERGENCY_MESSAGE.");
832         pw.println("          If no option is specified, there is no delay in sending the event.");
833         pw.println("  set-satellite-access-control-overlay-configs [-r -a -f SATELLITE_S2_FILE ");
834         pw.println("    -d LOCATION_FRESH_DURATION_NANOS -c COUNTRY_CODES] Override the overlay");
835         pw.println("    configs of satellite access controller.");
836         pw.println("    Options are:");
837         pw.println("      -r: clear the overriding. Absent means enable overriding.");
838         pw.println("      -a: the country codes is an allowed list. Absent means disallowed.");
839         pw.println("      -f: the satellite s2 file.");
840         pw.println("      -d: the location fresh duration nanos.");
841         pw.println("      -c: the list of satellite country codes separated by comma.");
842         pw.println("  set-country-codes [-r -n CURRENT_NETWORK_COUNTRY_CODES -c");
843         pw.println("    CACHED_NETWORK_COUNTRY_CODES -l LOCATION_COUNTRY_CODE -t");
844         pw.println("    LOCATION_COUNTRY_CODE_TIMESTAMP] ");
845         pw.println("    Override the cached location country code and its update timestamp. ");
846         pw.println("    Options are:");
847         pw.println("      -r: clear the overriding. Absent means enable overriding.");
848         pw.println("      -n: the current network country code ISOs.");
849         pw.println("      -c: the cached network country code ISOs.");
850         pw.println("      -l: the location country code ISO.");
851         pw.println("      -t: the update timestamp nanos of the location country code.");
852         pw.println("  set-oem-enabled-satellite-provision-status [-p true/false]");
853         pw.println("    Sets the OEM-enabled satellite provision status. Options are:");
854         pw.println("      -p: the overriding satellite provision status. If no option is ");
855         pw.println("          specified, reset the overridden provision status.");
856     }
857 
onHelpImei()858     private void onHelpImei() {
859         PrintWriter pw = getOutPrintWriter();
860         pw.println("IMEI Commands:");
861         pw.println("  get-imei [-s SLOT_ID]");
862         pw.println("    Gets the device IMEI. Options are:");
863         pw.println("      -s: the slot ID to get the IMEI. If no option");
864         pw.println("          is specified, it will choose the default voice SIM slot.");
865     }
866 
onHelpDomainSelection()867     private void onHelpDomainSelection() {
868         PrintWriter pw = getOutPrintWriter();
869         pw.println("Domain Selection Commands:");
870         pw.println("  domainselection set-dss-override COMPONENT_NAME");
871         pw.println("    Sets the service defined in COMPONENT_NAME to be bound");
872         pw.println("  domainselection clear-dss-override");
873         pw.println("    Clears DomainSelectionService override.");
874     }
875 
handleImsCommand()876     private int handleImsCommand() {
877         String arg = getNextArg();
878         if (arg == null) {
879             onHelpIms();
880             return 0;
881         }
882 
883         switch (arg) {
884             case IMS_SET_IMS_SERVICE: {
885                 return handleImsSetServiceCommand();
886             }
887             case IMS_GET_IMS_SERVICE: {
888                 return handleImsGetServiceCommand();
889             }
890             case IMS_CLEAR_SERVICE_OVERRIDE: {
891                 return handleImsClearCarrierServiceCommand();
892             }
893             case ENABLE: {
894                 return handleEnableIms();
895             }
896             case DISABLE: {
897                 return handleDisableIms();
898             }
899             case IMS_CEP: {
900                 return handleCepChange();
901             }
902         }
903 
904         return -1;
905     }
906 
handleDataTestModeCommand()907     private int handleDataTestModeCommand() {
908         PrintWriter errPw = getErrPrintWriter();
909         String arg = getNextArgRequired();
910         if (arg == null) {
911             onHelpDataTestMode();
912             return 0;
913         }
914         switch (arg) {
915             case ENABLE: {
916                 try {
917                     mInterface.enableDataConnectivity(mContext.getOpPackageName());
918                 } catch (RemoteException ex) {
919                     Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
920                     errPw.println("Exception: " + ex.getMessage());
921                     return -1;
922                 }
923                 break;
924             }
925             case DISABLE: {
926                 try {
927                     mInterface.disableDataConnectivity(mContext.getOpPackageName());
928                 } catch (RemoteException ex) {
929                     Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
930                     errPw.println("Exception: " + ex.getMessage());
931                     return -1;
932                 }
933                 break;
934             }
935             default:
936                 onHelpDataTestMode();
937                 break;
938         }
939         return 0;
940     }
941 
handleEmergencyCallbackModeCommand()942     private int handleEmergencyCallbackModeCommand() {
943         PrintWriter errPw = getErrPrintWriter();
944         try {
945             mInterface.startEmergencyCallbackMode();
946             Log.d(LOG_TAG, "handleEmergencyCallbackModeCommand: triggered");
947         } catch (RemoteException ex) {
948             Log.w(LOG_TAG, "emergency-callback-mode error: " + ex.getMessage());
949             errPw.println("Exception: " + ex.getMessage());
950             return -1;
951         }
952         return 0;
953     }
954 
removeEmergencyNumberTestMode(String emergencyNumber)955     private void removeEmergencyNumberTestMode(String emergencyNumber) {
956         PrintWriter errPw = getErrPrintWriter();
957         for (int routingType : ROUTING_TYPES) {
958             try {
959                 mInterface.updateEmergencyNumberListTestMode(
960                         EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
961                         new EmergencyNumber(emergencyNumber, "", "",
962                                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
963                                 new ArrayList<String>(),
964                                 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
965                                 routingType));
966             } catch (RemoteException ex) {
967                 Log.w(LOG_TAG, "emergency-number-test-mode " + "error " + ex.getMessage());
968                 errPw.println("Exception: " + ex.getMessage());
969             }
970         }
971     }
972 
handleEmergencyNumberTestModeCommand()973     private int handleEmergencyNumberTestModeCommand() {
974         PrintWriter errPw = getErrPrintWriter();
975         String opt = getNextOption();
976         if (opt == null) {
977             onHelpEmergencyNumber();
978             return 0;
979         }
980         switch (opt) {
981             case "-a": {
982                 String emergencyNumberCmd = getNextArgRequired();
983                 if (emergencyNumberCmd == null){
984                     errPw.println(INVALID_ENTRY_ERROR);
985                     return -1;
986                 }
987                 String[] params = emergencyNumberCmd.split(":");
988                 String emergencyNumber;
989                 if (params[0] == null ||
990                         !EmergencyNumber.validateEmergencyNumberAddress(params[0])){
991                     errPw.println(INVALID_ENTRY_ERROR);
992                     return -1;
993                 } else {
994                     emergencyNumber = params[0];
995                 }
996                 removeEmergencyNumberTestMode(emergencyNumber);
997                 int emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN;
998                 if (params.length > 1) {
999                     switch (params[1].toLowerCase(Locale.ROOT)) {
1000                         case "emergency":
1001                             emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY;
1002                             break;
1003                         case "normal":
1004                             emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL;
1005                             break;
1006                         case "unknown":
1007                             break;
1008                         default:
1009                             errPw.println("\"" + params[1] + "\" is not a valid specification for "
1010                                     + "emergency call routing. Please enter either \"normal\", "
1011                                     + "\"unknown\", or \"emergency\" for call routing. "
1012                                     + "(-a 1234:normal)");
1013                             return -1;
1014                     }
1015                 }
1016                 try {
1017                     mInterface.updateEmergencyNumberListTestMode(
1018                             EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
1019                             new EmergencyNumber(emergencyNumber, "", "",
1020                                     EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
1021                                     new ArrayList<String>(),
1022                                     EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
1023                                     emergencyCallRouting));
1024                 } catch (RemoteException ex) {
1025                     Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumber
1026                             + ", error " + ex.getMessage());
1027                     errPw.println("Exception: " + ex.getMessage());
1028                     return -1;
1029                 }
1030                 break;
1031             }
1032             case "-c": {
1033                 try {
1034                     mInterface.updateEmergencyNumberListTestMode(
1035                             EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
1036                 } catch (RemoteException ex) {
1037                     Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
1038                     errPw.println("Exception: " + ex.getMessage());
1039                     return -1;
1040                 }
1041                 break;
1042             }
1043             case "-r": {
1044                 String emergencyNumberCmd = getNextArgRequired();
1045                 if (emergencyNumberCmd == null
1046                         || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
1047                     errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
1048                             + " to be specified after -r in the command ");
1049                     return -1;
1050                 }
1051                 removeEmergencyNumberTestMode(emergencyNumberCmd);
1052                 break;
1053             }
1054             case "-p": {
1055                 try {
1056                     getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
1057                 } catch (RemoteException ex) {
1058                     Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
1059                     errPw.println("Exception: " + ex.getMessage());
1060                     return -1;
1061                 }
1062                 break;
1063             }
1064             default:
1065                 onHelpEmergencyNumber();
1066                 break;
1067         }
1068         return 0;
1069     }
1070 
handleNumberVerificationCommand()1071     private int handleNumberVerificationCommand() {
1072         String arg = getNextArg();
1073         if (arg == null) {
1074             onHelpNumberVerification();
1075             return 0;
1076         }
1077 
1078         if (!checkShellUid()) {
1079             return -1;
1080         }
1081 
1082         switch (arg) {
1083             case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
1084                 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
1085                 return 0;
1086             }
1087             case NUMBER_VERIFICATION_FAKE_CALL: {
1088                 boolean val = NumberVerificationManager.getInstance()
1089                         .checkIncomingCall(getNextArg());
1090                 getOutPrintWriter().println(val ? "1" : "0");
1091                 return 0;
1092             }
1093         }
1094 
1095         return -1;
1096     }
1097 
subIsEsim(int subId)1098     private boolean subIsEsim(int subId) {
1099         SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1100         if (info != null) {
1101             return info.isEmbedded();
1102         }
1103         return false;
1104     }
1105 
handleEnablePhysicalSubscription(boolean enable)1106     private int handleEnablePhysicalSubscription(boolean enable) {
1107         PrintWriter errPw = getErrPrintWriter();
1108         int subId = 0;
1109         try {
1110             subId = Integer.parseInt(getNextArgRequired());
1111         } catch (NumberFormatException e) {
1112             errPw.println((enable ? "enable" : "disable")
1113                     + "-physical-subscription requires an integer as a subId.");
1114             return -1;
1115         }
1116         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
1117         // non user build.
1118         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
1119             errPw.println("cc: Permission denied.");
1120             return -1;
1121         }
1122         // Verify that the subId represents a physical sub
1123         if (subIsEsim(subId)) {
1124             errPw.println("SubId " + subId + " is not for a physical subscription");
1125             return -1;
1126         }
1127         Log.d(LOG_TAG, (enable ? "Enabling" : "Disabling")
1128                 + " physical subscription with subId=" + subId);
1129         mSubscriptionManager.setUiccApplicationsEnabled(subId, enable);
1130         return 0;
1131     }
1132 
handleThermalMitigationCommand()1133     private int handleThermalMitigationCommand() {
1134         String arg = getNextArg();
1135         String packageName = getNextArg();
1136         if (arg == null || packageName == null) {
1137             onHelpThermalMitigation();
1138             return 0;
1139         }
1140 
1141         if (!checkShellUid()) {
1142             return -1;
1143         }
1144 
1145         switch (arg) {
1146             case ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: {
1147                 PhoneInterfaceManager.addPackageToThermalMitigationAllowlist(packageName, mContext);
1148                 return 0;
1149             }
1150             case DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: {
1151                 PhoneInterfaceManager.removePackageFromThermalMitigationAllowlist(packageName,
1152                         mContext);
1153                 return 0;
1154             }
1155             default:
1156                 onHelpThermalMitigation();
1157         }
1158 
1159         return -1;
1160 
1161     }
1162 
handleD2dCommand()1163     private int handleD2dCommand() {
1164         String arg = getNextArg();
1165         if (arg == null) {
1166             onHelpD2D();
1167             return 0;
1168         }
1169 
1170         switch (arg) {
1171             case D2D_SEND: {
1172                 return handleD2dSendCommand();
1173             }
1174             case D2D_TRANSPORT: {
1175                 return handleD2dTransportCommand();
1176             }
1177             case D2D_SET_DEVICE_SUPPORT: {
1178                 return handleD2dDeviceSupportedCommand();
1179             }
1180         }
1181 
1182         return -1;
1183     }
1184 
handleD2dSendCommand()1185     private int handleD2dSendCommand() {
1186         PrintWriter errPw = getErrPrintWriter();
1187         int messageType = -1;
1188         int messageValue = -1;
1189 
1190         String arg = getNextArg();
1191         if (arg == null) {
1192             onHelpD2D();
1193             return 0;
1194         }
1195         try {
1196             messageType = Integer.parseInt(arg);
1197         } catch (NumberFormatException e) {
1198             errPw.println("message type must be a valid integer");
1199             return -1;
1200         }
1201 
1202         arg = getNextArg();
1203         if (arg == null) {
1204             onHelpD2D();
1205             return 0;
1206         }
1207         try {
1208             messageValue = Integer.parseInt(arg);
1209         } catch (NumberFormatException e) {
1210             errPw.println("message value must be a valid integer");
1211             return -1;
1212         }
1213 
1214         try {
1215             mInterface.sendDeviceToDeviceMessage(messageType, messageValue);
1216         } catch (RemoteException e) {
1217             Log.w(LOG_TAG, "d2d send error: " + e.getMessage());
1218             errPw.println("Exception: " + e.getMessage());
1219             return -1;
1220         }
1221 
1222         return 0;
1223     }
1224 
handleD2dTransportCommand()1225     private int handleD2dTransportCommand() {
1226         PrintWriter errPw = getErrPrintWriter();
1227 
1228         String arg = getNextArg();
1229         if (arg == null) {
1230             onHelpD2D();
1231             return 0;
1232         }
1233 
1234         try {
1235             mInterface.setActiveDeviceToDeviceTransport(arg);
1236         } catch (RemoteException e) {
1237             Log.w(LOG_TAG, "d2d transport error: " + e.getMessage());
1238             errPw.println("Exception: " + e.getMessage());
1239             return -1;
1240         }
1241         return 0;
1242     }
handleBarringCommand()1243     private int handleBarringCommand() {
1244         String arg = getNextArg();
1245         if (arg == null) {
1246             onHelpBarring();
1247             return 0;
1248         }
1249 
1250         switch (arg) {
1251             case BARRING_SEND_INFO: {
1252                 return handleBarringSendCommand();
1253             }
1254         }
1255         return -1;
1256     }
1257 
handleBarringSendCommand()1258     private int handleBarringSendCommand() {
1259         PrintWriter errPw = getErrPrintWriter();
1260         int slotId = getDefaultSlot();
1261         int subId = SubscriptionManager.getSubscriptionId(slotId);
1262         @BarringInfo.BarringServiceInfo.BarringType int barringType =
1263                 BarringInfo.BarringServiceInfo.BARRING_TYPE_UNCONDITIONAL;
1264         boolean isConditionallyBarred = false;
1265         int conditionalBarringTimeSeconds = 0;
1266 
1267         String opt;
1268         while ((opt = getNextOption()) != null) {
1269             switch (opt) {
1270                 case "-s": {
1271                     try {
1272                         slotId = Integer.parseInt(getNextArgRequired());
1273                         subId = SubscriptionManager.getSubscriptionId(slotId);
1274                     } catch (NumberFormatException e) {
1275                         errPw.println("barring send requires an integer as a SLOT_ID.");
1276                         return -1;
1277                     }
1278                     break;
1279                 }
1280                 case "-b": {
1281                     try {
1282                         barringType = Integer.parseInt(getNextArgRequired());
1283                         if (barringType < -1 || barringType > 2) {
1284                             throw new NumberFormatException();
1285                         }
1286 
1287                     } catch (NumberFormatException e) {
1288                         errPw.println("barring send requires an integer in range [-1,2] as "
1289                                 + "a BARRING_TYPE.");
1290                         return -1;
1291                     }
1292                     break;
1293                 }
1294                 case "-c": {
1295                     try {
1296                         isConditionallyBarred = Boolean.parseBoolean(getNextArgRequired());
1297                     } catch (Exception e) {
1298                         errPw.println("barring send requires a boolean after -c indicating"
1299                                 + " conditional barring");
1300                         return -1;
1301                     }
1302                     break;
1303                 }
1304                 case "-t": {
1305                     try {
1306                         conditionalBarringTimeSeconds = Integer.parseInt(getNextArgRequired());
1307                     } catch (NumberFormatException e) {
1308                         errPw.println("barring send requires an integer for time of barring"
1309                                 + " in seconds after -t for conditional barring");
1310                         return -1;
1311                     }
1312                     break;
1313                 }
1314             }
1315         }
1316         SparseArray<BarringInfo.BarringServiceInfo> barringServiceInfos = new SparseArray<>();
1317         BarringInfo.BarringServiceInfo bsi = new BarringInfo.BarringServiceInfo(
1318                 barringType, isConditionallyBarred, 0, conditionalBarringTimeSeconds);
1319         barringServiceInfos.append(0, bsi);
1320         BarringInfo barringInfo = new BarringInfo(null, barringServiceInfos);
1321         try {
1322             mTelephonyRegistryManager.notifyBarringInfoChanged(slotId, subId, barringInfo);
1323         } catch (Exception e) {
1324             Log.w(LOG_TAG, "barring send error: " + e.getMessage());
1325             errPw.println("Exception: " + e.getMessage());
1326             return -1;
1327         }
1328         return 0;
1329     }
1330 
handleD2dDeviceSupportedCommand()1331     private int handleD2dDeviceSupportedCommand() {
1332         PrintWriter errPw = getErrPrintWriter();
1333 
1334         String arg = getNextArg();
1335         if (arg == null) {
1336             onHelpD2D();
1337             return 0;
1338         }
1339 
1340         boolean isEnabled = "true".equals(arg.toLowerCase(Locale.ROOT));
1341         try {
1342             mInterface.setDeviceToDeviceForceEnabled(isEnabled);
1343         } catch (RemoteException e) {
1344             Log.w(LOG_TAG, "Error forcing D2D enabled: " + e.getMessage());
1345             errPw.println("Exception: " + e.getMessage());
1346             return -1;
1347         }
1348         return 0;
1349     }
1350 
1351     // ims set-ims-service
handleImsSetServiceCommand()1352     private int handleImsSetServiceCommand() {
1353         PrintWriter errPw = getErrPrintWriter();
1354         int slotId = getDefaultSlot();
1355         Boolean isCarrierService = null;
1356         List<Integer> featuresList = new ArrayList<>();
1357 
1358         String opt;
1359         while ((opt = getNextOption()) != null) {
1360             switch (opt) {
1361                 case "-s": {
1362                     try {
1363                         slotId = Integer.parseInt(getNextArgRequired());
1364                     } catch (NumberFormatException e) {
1365                         errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
1366                         return -1;
1367                     }
1368                     break;
1369                 }
1370                 case "-c": {
1371                     isCarrierService = true;
1372                     break;
1373                 }
1374                 case "-d": {
1375                     isCarrierService = false;
1376                     break;
1377                 }
1378                 case "-f": {
1379                     String featureString = getNextArgRequired();
1380                     String[] features = featureString.split(",");
1381                     for (int i = 0; i < features.length; i++) {
1382                         try {
1383                             Integer result = Integer.parseInt(features[i]);
1384                             if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
1385                                     || result >= ImsFeature.FEATURE_MAX) {
1386                                 errPw.println("ims set-ims-service -f " + result
1387                                         + " is an invalid feature.");
1388                                 return -1;
1389                             }
1390                             featuresList.add(result);
1391                         } catch (NumberFormatException e) {
1392                             errPw.println("ims set-ims-service -f tried to parse " + features[i]
1393                                             + " as an integer.");
1394                             return -1;
1395                         }
1396                     }
1397                 }
1398             }
1399         }
1400         // Mandatory param, either -c or -d
1401         if (isCarrierService == null) {
1402             errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
1403             return -1;
1404         }
1405 
1406         String packageName = getNextArg();
1407 
1408         try {
1409             if (packageName == null) {
1410                 packageName = "";
1411             }
1412             int[] featureArray = new int[featuresList.size()];
1413             for (int i = 0; i < featuresList.size(); i++) {
1414                 featureArray[i] = featuresList.get(i);
1415             }
1416             boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
1417                     featureArray, packageName);
1418             if (VDBG) {
1419                 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
1420                         + (isCarrierService ? "-c " : "-d ")
1421                         + "-f " + featuresList + " "
1422                         + packageName + ", result=" + result);
1423             }
1424             getOutPrintWriter().println(result);
1425         } catch (RemoteException e) {
1426             Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
1427                     + (isCarrierService ? "-c " : "-d ")
1428                     + "-f " + featuresList + " "
1429                     + packageName + ", error" + e.getMessage());
1430             errPw.println("Exception: " + e.getMessage());
1431             return -1;
1432         }
1433         return 0;
1434     }
1435 
1436     // ims clear-ims-service-override
handleImsClearCarrierServiceCommand()1437     private int handleImsClearCarrierServiceCommand() {
1438         PrintWriter errPw = getErrPrintWriter();
1439         int slotId = getDefaultSlot();
1440 
1441         String opt;
1442         while ((opt = getNextOption()) != null) {
1443             switch (opt) {
1444                 case "-s": {
1445                     try {
1446                         slotId = Integer.parseInt(getNextArgRequired());
1447                     } catch (NumberFormatException e) {
1448                         errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
1449                         return -1;
1450                     }
1451                     break;
1452                 }
1453             }
1454         }
1455 
1456         try {
1457             boolean result = mInterface.clearCarrierImsServiceOverride(slotId);
1458             if (VDBG) {
1459                 Log.v(LOG_TAG, "ims clear-ims-service-override -s " + slotId
1460                         + ", result=" + result);
1461             }
1462             getOutPrintWriter().println(result);
1463         } catch (RemoteException e) {
1464             Log.w(LOG_TAG, "ims clear-ims-service-override -s " + slotId
1465                     + ", error" + e.getMessage());
1466             errPw.println("Exception: " + e.getMessage());
1467             return -1;
1468         }
1469         return 0;
1470     }
1471 
1472     // ims get-ims-service
handleImsGetServiceCommand()1473     private int handleImsGetServiceCommand() {
1474         PrintWriter errPw = getErrPrintWriter();
1475         int slotId = getDefaultSlot();
1476         Boolean isCarrierService = null;
1477         Integer featureType = ImsFeature.FEATURE_MMTEL;
1478 
1479         String opt;
1480         while ((opt = getNextOption()) != null) {
1481             switch (opt) {
1482                 case "-s": {
1483                     try {
1484                         slotId = Integer.parseInt(getNextArgRequired());
1485                     } catch (NumberFormatException e) {
1486                         errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
1487                         return -1;
1488                     }
1489                     break;
1490                 }
1491                 case "-c": {
1492                     isCarrierService = true;
1493                     break;
1494                 }
1495                 case "-d": {
1496                     isCarrierService = false;
1497                     break;
1498                 }
1499                 case "-f": {
1500                     try {
1501                         featureType = Integer.parseInt(getNextArg());
1502                     } catch (NumberFormatException e) {
1503                         errPw.println("ims get-ims-service -f requires valid integer as feature.");
1504                         return -1;
1505                     }
1506                     if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
1507                             || featureType >= ImsFeature.FEATURE_MAX) {
1508                         errPw.println("ims get-ims-service -f invalid feature.");
1509                         return -1;
1510                     }
1511                 }
1512             }
1513         }
1514         // Mandatory param, either -c or -d
1515         if (isCarrierService == null) {
1516             errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
1517             return -1;
1518         }
1519 
1520         String result;
1521         try {
1522             result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
1523         } catch (RemoteException e) {
1524             return -1;
1525         }
1526         if (VDBG) {
1527             Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
1528                     + (isCarrierService ? "-c " : "-d ")
1529                     + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
1530                     + result);
1531         }
1532         getOutPrintWriter().println(result);
1533         return 0;
1534     }
1535 
handleEnableIms()1536     private int handleEnableIms() {
1537         int slotId = getDefaultSlot();
1538         String opt;
1539         while ((opt = getNextOption()) != null) {
1540             switch (opt) {
1541                 case "-s": {
1542                     try {
1543                         slotId = Integer.parseInt(getNextArgRequired());
1544                     } catch (NumberFormatException e) {
1545                         getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
1546                         return -1;
1547                     }
1548                     break;
1549                 }
1550             }
1551         }
1552         try {
1553             mInterface.enableIms(slotId);
1554         } catch (RemoteException e) {
1555             return -1;
1556         }
1557         if (VDBG) {
1558             Log.v(LOG_TAG, "ims enable -s " + slotId);
1559         }
1560         return 0;
1561     }
1562 
handleDisableIms()1563     private int handleDisableIms() {
1564         int slotId = getDefaultSlot();
1565         String opt;
1566         while ((opt = getNextOption()) != null) {
1567             switch (opt) {
1568                 case "-s": {
1569                     try {
1570                         slotId = Integer.parseInt(getNextArgRequired());
1571                     } catch (NumberFormatException e) {
1572                         getErrPrintWriter().println(
1573                                 "ims disable requires an integer as a SLOT_ID.");
1574                         return -1;
1575                     }
1576                     break;
1577                 }
1578             }
1579         }
1580         try {
1581             mInterface.disableIms(slotId);
1582         } catch (RemoteException e) {
1583             return -1;
1584         }
1585         if (VDBG) {
1586             Log.v(LOG_TAG, "ims disable -s " + slotId);
1587         }
1588         return 0;
1589     }
1590 
handleCepChange()1591     private int handleCepChange() {
1592         Log.i(LOG_TAG, "handleCepChange");
1593         String opt = getNextArg();
1594         if (opt == null) {
1595             return -1;
1596         }
1597         boolean isCepEnabled = opt.equals("enable");
1598 
1599         try {
1600             mInterface.setCepEnabled(isCepEnabled);
1601         } catch (RemoteException e) {
1602             return -1;
1603         }
1604         return 0;
1605     }
1606 
getDefaultSlot()1607     private int getDefaultSlot() {
1608         int slotId = SubscriptionManager.getDefaultVoicePhoneId();
1609         if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
1610                 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
1611             // If there is no default, default to slot 0.
1612             slotId = DEFAULT_PHONE_ID;
1613         }
1614         return slotId;
1615     }
1616 
1617     // Parse options related to Carrier Config Commands.
parseCcOptions(String tag, boolean allowOptionPersistent)1618     private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
1619         PrintWriter errPw = getErrPrintWriter();
1620         CcOptionParseResult result = new CcOptionParseResult();
1621         result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
1622         result.mPersistent = false;
1623 
1624         String opt;
1625         while ((opt = getNextOption()) != null) {
1626             switch (opt) {
1627                 case "-s": {
1628                     try {
1629                         result.mSubId = slotStringToSubId(tag, getNextArgRequired());
1630                         if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
1631                             errPw.println(tag + "No valid subscription found.");
1632                             return null;
1633                         }
1634 
1635                     } catch (IllegalArgumentException e) {
1636                         // Missing slot id
1637                         errPw.println(tag + "SLOT_ID expected after -s.");
1638                         return null;
1639                     }
1640                     break;
1641                 }
1642                 case "-p": {
1643                     if (allowOptionPersistent) {
1644                         result.mPersistent = true;
1645                     } else {
1646                         errPw.println(tag + "Unexpected option " + opt);
1647                         return null;
1648                     }
1649                     break;
1650                 }
1651                 default: {
1652                     errPw.println(tag + "Unknown option " + opt);
1653                     return null;
1654                 }
1655             }
1656         }
1657         return result;
1658     }
1659 
slotStringToSubId(String tag, String slotString)1660     private int slotStringToSubId(String tag, String slotString) {
1661         int slotId = -1;
1662         try {
1663             slotId = Integer.parseInt(slotString);
1664         } catch (NumberFormatException e) {
1665             getErrPrintWriter().println(tag + slotString + " is not a valid number for SLOT_ID.");
1666             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1667         }
1668 
1669         if (!SubscriptionManager.isValidPhoneId(slotId)) {
1670             getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
1671             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1672         }
1673 
1674         Phone phone = PhoneFactory.getPhone(slotId);
1675         if (phone == null) {
1676             getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
1677             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1678         }
1679         return phone.getSubId();
1680     }
1681 
checkShellUid()1682     private boolean checkShellUid() {
1683         // adb can run as root or as shell, depending on whether the device is rooted.
1684         return Binder.getCallingUid() == Process.SHELL_UID
1685                 || Binder.getCallingUid() == Process.ROOT_UID;
1686     }
1687 
handleCcCommand()1688     private int handleCcCommand() {
1689         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
1690         // non user build.
1691         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
1692             getErrPrintWriter().println("cc: Permission denied.");
1693             return -1;
1694         }
1695 
1696         String arg = getNextArg();
1697         if (arg == null) {
1698             onHelpCc();
1699             return 0;
1700         }
1701 
1702         switch (arg) {
1703             case CC_GET_VALUE: {
1704                 return handleCcGetValue();
1705             }
1706             case CC_SET_VALUE: {
1707                 return handleCcSetValue();
1708             }
1709             case CC_SET_VALUES_FROM_XML: {
1710                 return handleCcSetValuesFromXml();
1711             }
1712             case CC_CLEAR_VALUES: {
1713                 return handleCcClearValues();
1714             }
1715             default: {
1716                 getErrPrintWriter().println("cc: Unknown argument: " + arg);
1717             }
1718         }
1719         return -1;
1720     }
1721 
1722     // cc get-value
handleCcGetValue()1723     private int handleCcGetValue() {
1724         PrintWriter errPw = getErrPrintWriter();
1725         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
1726         String key = null;
1727 
1728         // Parse all options
1729         CcOptionParseResult options = parseCcOptions(tag, false);
1730         if (options == null) {
1731             return -1;
1732         }
1733 
1734         // Get bundle containing all carrier configuration values.
1735         PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
1736         if (bundle == null) {
1737             errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
1738             return -1;
1739         }
1740 
1741         // Get the key.
1742         key = getNextArg();
1743         if (key != null) {
1744             // A key was provided. Verify if it is a valid key
1745             if (!bundle.containsKey(key)) {
1746                 errPw.println(tag + key + " is not a valid key.");
1747                 return -1;
1748             }
1749 
1750             // Print the carrier config value for key.
1751             getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
1752         } else {
1753             // No key provided. Show all values.
1754             // Iterate over a sorted list of all carrier config keys and print them.
1755             TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
1756             for (String k : sortedSet) {
1757                 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
1758             }
1759         }
1760         return 0;
1761     }
1762 
1763     // cc set-value
handleCcSetValue()1764     private int handleCcSetValue() {
1765         PrintWriter errPw = getErrPrintWriter();
1766         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
1767 
1768         // Parse all options
1769         CcOptionParseResult options = parseCcOptions(tag, true);
1770         if (options == null) {
1771             return -1;
1772         }
1773 
1774         // Get bundle containing all current carrier configuration values.
1775         PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
1776         if (originalValues == null) {
1777             errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
1778             return -1;
1779         }
1780 
1781         // Get the key.
1782         String key = getNextArg();
1783         if (key == null || key.equals("")) {
1784             errPw.println(tag + "KEY is missing");
1785             return -1;
1786         }
1787 
1788         // Verify if the key is valid
1789         if (!originalValues.containsKey(key)) {
1790             errPw.println(tag + key + " is not a valid key.");
1791             return -1;
1792         }
1793 
1794         // Remaining arguments is a list of new values. Add them all into an ArrayList.
1795         ArrayList<String> valueList = new ArrayList<String>();
1796         while (peekNextArg() != null) {
1797             valueList.add(getNextArg());
1798         }
1799 
1800         // Find the type of the carrier config value
1801         CcType type = getType(tag, key, originalValues);
1802         if (type == CcType.UNKNOWN) {
1803             errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
1804             return -1;
1805         }
1806         if (type == CcType.PERSISTABLE_BUNDLE) {
1807             errPw.println(tag + "ERROR: Overriding of persistable bundle type is not supported. "
1808                     + "Use set-values-from-xml instead.");
1809             return -1;
1810         }
1811 
1812         // Create an override bundle containing the key and value that should be overriden.
1813         PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
1814         if (overrideBundle == null) {
1815             return -1;
1816         }
1817 
1818         // Override the value
1819         mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
1820 
1821         // Find bundle containing all new carrier configuration values after the override.
1822         PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
1823         if (newValues == null) {
1824             errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
1825             return -1;
1826         }
1827 
1828         // Print the original and new value.
1829         String originalValueString = ccValueToString(key, type, originalValues);
1830         String newValueString = ccValueToString(key, type, newValues);
1831         getOutPrintWriter().println("Previous value: \n" + originalValueString);
1832         getOutPrintWriter().println("New value: \n" + newValueString);
1833 
1834         return 0;
1835     }
1836 
1837     // cc set-values-from-xml
handleCcSetValuesFromXml()1838     private int handleCcSetValuesFromXml() {
1839         PrintWriter errPw = getErrPrintWriter();
1840         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUES_FROM_XML + ": ";
1841 
1842         // Parse all options
1843         CcOptionParseResult options = parseCcOptions(tag, true);
1844         if (options == null) {
1845             return -1;
1846         }
1847 
1848         // Get bundle containing all current carrier configuration values.
1849         PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
1850         if (originalValues == null) {
1851             errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
1852             return -1;
1853         }
1854 
1855         PersistableBundle overrideBundle = readPersistableBundleFromXml(tag);
1856         if (overrideBundle == null) {
1857             return -1;
1858         }
1859 
1860         // Verify all values are valid types
1861         for (String key : overrideBundle.keySet()) {
1862             CcType type = getType(tag, key, originalValues);
1863             if (type == CcType.UNKNOWN) {
1864                 errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
1865                 return -1;
1866             }
1867         }
1868 
1869         // Override the value
1870         mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
1871 
1872         // Find bundle containing all new carrier configuration values after the override.
1873         PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
1874         if (newValues == null) {
1875             errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
1876             return -1;
1877         }
1878 
1879         // Print the original and new values
1880         overrideBundle.keySet().forEach(key -> {
1881             CcType type = getType(tag, key, originalValues);
1882             String originalValueString = ccValueToString(key, type, originalValues);
1883             String newValueString = ccValueToString(key, type, newValues);
1884             getOutPrintWriter().println("Previous value: \n" + originalValueString);
1885             getOutPrintWriter().println("New value: \n" + newValueString);
1886         });
1887 
1888         return 0;
1889     }
1890 
readPersistableBundleFromXml(String tag)1891     private PersistableBundle readPersistableBundleFromXml(String tag) {
1892         PersistableBundle subIdBundles;
1893         try {
1894             subIdBundles = PersistableBundle.readFromStream(getRawInputStream());
1895         } catch (IOException | RuntimeException e) {
1896             PrintWriter errPw = getErrPrintWriter();
1897             errPw.println(tag + e);
1898             return null;
1899         }
1900 
1901         return subIdBundles;
1902     }
1903 
1904     // cc clear-values
handleCcClearValues()1905     private int handleCcClearValues() {
1906         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
1907 
1908         // Parse all options
1909         CcOptionParseResult options = parseCcOptions(tag, false);
1910         if (options == null) {
1911             return -1;
1912         }
1913 
1914         // Clear all values that has previously been set.
1915         mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
1916         getOutPrintWriter()
1917                 .println("All previously set carrier config override values has been cleared");
1918         return 0;
1919     }
1920 
getType(String tag, String key, PersistableBundle bundle)1921     private CcType getType(String tag, String key, PersistableBundle bundle) {
1922         // Find the type by checking the type of the current value stored in the bundle.
1923         Object value = bundle.get(key);
1924 
1925         if (CC_TYPE_MAP.containsKey(key)) {
1926             return CC_TYPE_MAP.get(key);
1927         } else if (value != null) {
1928             if (value instanceof Boolean) {
1929                 return CcType.BOOLEAN;
1930             }
1931             if (value instanceof Double) {
1932                 return CcType.DOUBLE;
1933             }
1934             if (value instanceof double[]) {
1935                 return CcType.DOUBLE_ARRAY;
1936             }
1937             if (value instanceof Integer) {
1938                 return CcType.INT;
1939             }
1940             if (value instanceof int[]) {
1941                 return CcType.INT_ARRAY;
1942             }
1943             if (value instanceof Long) {
1944                 return CcType.LONG;
1945             }
1946             if (value instanceof long[]) {
1947                 return CcType.LONG_ARRAY;
1948             }
1949             if (value instanceof String) {
1950                 return CcType.STRING;
1951             }
1952             if (value instanceof String[]) {
1953                 return CcType.STRING_ARRAY;
1954             }
1955             if (value instanceof PersistableBundle) {
1956                 return CcType.PERSISTABLE_BUNDLE;
1957             }
1958         } else {
1959             // Current value was null and can therefore not be used in order to find the type.
1960             // Check the name of the key to infer the type. This check is not needed for primitive
1961             // data types (boolean, double, int and long), since they can not be null.
1962             if (key.endsWith("double_array")) {
1963                 return CcType.DOUBLE_ARRAY;
1964             }
1965             if (key.endsWith("int_array")) {
1966                 return CcType.INT_ARRAY;
1967             }
1968             if (key.endsWith("long_array")) {
1969                 return CcType.LONG_ARRAY;
1970             }
1971             if (key.endsWith("string")) {
1972                 return CcType.STRING;
1973             }
1974             if (key.endsWith("string_array") || key.endsWith("strings")) {
1975                 return CcType.STRING_ARRAY;
1976             }
1977             if (key.endsWith("bundle")) {
1978                 return CcType.PERSISTABLE_BUNDLE;
1979             }
1980         }
1981 
1982         // Not possible to infer the type by looking at the current value or the key.
1983         PrintWriter errPw = getErrPrintWriter();
1984         errPw.println(tag + "ERROR: " + key + " has unknown type.");
1985         return CcType.UNKNOWN;
1986     }
1987 
ccValueToString(String key, CcType type, PersistableBundle bundle)1988     private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
1989         String result;
1990         StringBuilder valueString = new StringBuilder();
1991         String typeString = type.toString();
1992         Object value = bundle.get(key);
1993 
1994         if (value == null) {
1995             valueString.append("null");
1996         } else {
1997             switch (type) {
1998                 case DOUBLE_ARRAY: {
1999                     // Format the string representation of the int array as value1 value2......
2000                     double[] valueArray = (double[]) value;
2001                     for (int i = 0; i < valueArray.length; i++) {
2002                         if (i != 0) {
2003                             valueString.append(" ");
2004                         }
2005                         valueString.append(valueArray[i]);
2006                     }
2007                     break;
2008                 }
2009                 case INT_ARRAY: {
2010                     // Format the string representation of the int array as value1 value2......
2011                     int[] valueArray = (int[]) value;
2012                     for (int i = 0; i < valueArray.length; i++) {
2013                         if (i != 0) {
2014                             valueString.append(" ");
2015                         }
2016                         valueString.append(valueArray[i]);
2017                     }
2018                     break;
2019                 }
2020                 case LONG_ARRAY: {
2021                     // Format the string representation of the int array as value1 value2......
2022                     long[] valueArray = (long[]) value;
2023                     for (int i = 0; i < valueArray.length; i++) {
2024                         if (i != 0) {
2025                             valueString.append(" ");
2026                         }
2027                         valueString.append(valueArray[i]);
2028                     }
2029                     break;
2030                 }
2031                 case STRING: {
2032                     valueString.append("\"" + value.toString() + "\"");
2033                     break;
2034                 }
2035                 case STRING_ARRAY: {
2036                     // Format the string representation of the string array as "value1" "value2"....
2037                     String[] valueArray = (String[]) value;
2038                     for (int i = 0; i < valueArray.length; i++) {
2039                         if (i != 0) {
2040                             valueString.append(" ");
2041                         }
2042                         if (valueArray[i] != null) {
2043                             valueString.append("\"" + valueArray[i] + "\"");
2044                         } else {
2045                             valueString.append("null");
2046                         }
2047                     }
2048                     break;
2049                 }
2050                 default: {
2051                     valueString.append(value.toString());
2052                 }
2053             }
2054         }
2055         return String.format("%-70s %-15s %s", key, typeString, valueString);
2056     }
2057 
getOverrideBundle(String tag, CcType type, String key, ArrayList<String> valueList)2058     private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
2059             ArrayList<String> valueList) {
2060         PrintWriter errPw = getErrPrintWriter();
2061         PersistableBundle bundle = new PersistableBundle();
2062 
2063         // First verify that a valid number of values has been provided for the type.
2064         switch (type) {
2065             case BOOLEAN:
2066             case DOUBLE:
2067             case INT:
2068             case LONG: {
2069                 if (valueList.size() != 1) {
2070                     errPw.println(tag + "Expected 1 value for type " + type
2071                             + ". Found: " + valueList.size());
2072                     return null;
2073                 }
2074                 break;
2075             }
2076             case STRING: {
2077                 if (valueList.size() > 1) {
2078                     errPw.println(tag + "Expected 0 or 1 values for type " + type
2079                             + ". Found: " + valueList.size());
2080                     return null;
2081                 }
2082                 break;
2083             }
2084         }
2085 
2086         // Parse the value according to type and add it to the Bundle.
2087         switch (type) {
2088             case BOOLEAN: {
2089                 if ("true".equalsIgnoreCase(valueList.get(0))) {
2090                     bundle.putBoolean(key, true);
2091                 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
2092                     bundle.putBoolean(key, false);
2093                 } else {
2094                     errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
2095                     return null;
2096                 }
2097                 break;
2098             }
2099             case DOUBLE: {
2100                 try {
2101                     bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
2102                 } catch (NumberFormatException nfe) {
2103                     // Not a valid double
2104                     errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
2105                     return null;
2106                 }
2107                 break;
2108             }
2109             case DOUBLE_ARRAY: {
2110                 double[] valueDoubleArray = null;
2111                 if (valueList.size() > 0) {
2112                     valueDoubleArray = new double[valueList.size()];
2113                     for (int i = 0; i < valueList.size(); i++) {
2114                         try {
2115                             valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
2116                         } catch (NumberFormatException nfe) {
2117                             // Not a valid double
2118                             errPw.println(
2119                                     tag + "Unable to parse " + valueList.get(i) + " as a double.");
2120                             return null;
2121                         }
2122                     }
2123                 }
2124                 bundle.putDoubleArray(key, valueDoubleArray);
2125                 break;
2126             }
2127             case INT: {
2128                 try {
2129                     bundle.putInt(key, Integer.parseInt(valueList.get(0)));
2130                 } catch (NumberFormatException nfe) {
2131                     // Not a valid integer
2132                     errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
2133                     return null;
2134                 }
2135                 break;
2136             }
2137             case INT_ARRAY: {
2138                 int[] valueIntArray = null;
2139                 if (valueList.size() > 0) {
2140                     valueIntArray = new int[valueList.size()];
2141                     for (int i = 0; i < valueList.size(); i++) {
2142                         try {
2143                             valueIntArray[i] = Integer.parseInt(valueList.get(i));
2144                         } catch (NumberFormatException nfe) {
2145                             // Not a valid integer
2146                             errPw.println(tag
2147                                     + "Unable to parse " + valueList.get(i) + " as an integer.");
2148                             return null;
2149                         }
2150                     }
2151                 }
2152                 bundle.putIntArray(key, valueIntArray);
2153                 break;
2154             }
2155             case LONG: {
2156                 try {
2157                     bundle.putLong(key, Long.parseLong(valueList.get(0)));
2158                 } catch (NumberFormatException nfe) {
2159                     // Not a valid long
2160                     errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
2161                     return null;
2162                 }
2163                 break;
2164             }
2165             case LONG_ARRAY: {
2166                 long[] valueLongArray = null;
2167                 if (valueList.size() > 0) {
2168                     valueLongArray = new long[valueList.size()];
2169                     for (int i = 0; i < valueList.size(); i++) {
2170                         try {
2171                             valueLongArray[i] = Long.parseLong(valueList.get(i));
2172                         } catch (NumberFormatException nfe) {
2173                             // Not a valid long
2174                             errPw.println(
2175                                     tag + "Unable to parse " + valueList.get(i) + " as a long");
2176                             return null;
2177                         }
2178                     }
2179                 }
2180                 bundle.putLongArray(key, valueLongArray);
2181                 break;
2182             }
2183             case STRING: {
2184                 String value = null;
2185                 if (valueList.size() > 0) {
2186                     value = valueList.get(0);
2187                 }
2188                 bundle.putString(key, value);
2189                 break;
2190             }
2191             case STRING_ARRAY: {
2192                 String[] valueStringArray = null;
2193                 if (valueList.size() > 0) {
2194                     valueStringArray = new String[valueList.size()];
2195                     valueList.toArray(valueStringArray);
2196                 }
2197                 bundle.putStringArray(key, valueStringArray);
2198                 break;
2199             }
2200         }
2201         return bundle;
2202     }
2203 
handleEndBlockSuppressionCommand()2204     private int handleEndBlockSuppressionCommand() {
2205         if (!checkShellUid()) {
2206             return -1;
2207         }
2208 
2209         if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) {
2210             BlockedNumberContract.SystemContract.endBlockSuppression(mContext);
2211         }
2212         return 0;
2213     }
2214 
handleEuiccCommand()2215     private int handleEuiccCommand() {
2216         String arg = getNextArg();
2217         if (arg == null) {
2218             onHelpEuicc();
2219             return 0;
2220         }
2221 
2222         switch (arg) {
2223             case EUICC_SET_UI_COMPONENT: {
2224                 return handleEuiccServiceCommand();
2225             }
2226         }
2227         return -1;
2228     }
2229 
handleEuiccServiceCommand()2230     private int handleEuiccServiceCommand() {
2231         String uiComponent = getNextArg();
2232         String packageName = getNextArg();
2233         if (packageName == null || uiComponent == null) {
2234             return -1;
2235         }
2236         EuiccUiDispatcherActivity.setTestEuiccUiComponent(packageName, uiComponent);
2237         if (VDBG) {
2238             Log.v(LOG_TAG, "euicc set-euicc-uicomponent " + uiComponent +" "
2239                     + packageName);
2240         }
2241         return 0;
2242     }
2243 
handleRestartModemCommand()2244     private int handleRestartModemCommand() {
2245         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
2246         // non user build.
2247         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
2248             getErrPrintWriter().println("RestartModem: Permission denied.");
2249             return -1;
2250         }
2251 
2252         boolean result = TelephonyManager.getDefault().rebootRadio();
2253         getOutPrintWriter().println(result);
2254 
2255         return result ? 0 : -1;
2256     }
2257 
handleGetImei()2258     private int handleGetImei() {
2259         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
2260         // non user build.
2261         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
2262             getErrPrintWriter().println("Device IMEI: Permission denied.");
2263             return -1;
2264         }
2265 
2266         final long identity = Binder.clearCallingIdentity();
2267 
2268         String imei = null;
2269         String arg = getNextArg();
2270         if (arg != null) {
2271             try {
2272                 int specifiedSlotIndex = Integer.parseInt(arg);
2273                 imei = TelephonyManager.from(mContext).getImei(specifiedSlotIndex);
2274             } catch (NumberFormatException exception) {
2275                 PrintWriter errPw = getErrPrintWriter();
2276                 errPw.println("-s requires an integer as slot index.");
2277                 return -1;
2278             }
2279 
2280         } else {
2281             imei = TelephonyManager.from(mContext).getImei();
2282         }
2283         getOutPrintWriter().println("Device IMEI: " + imei);
2284 
2285         Binder.restoreCallingIdentity(identity);
2286         return 0;
2287     }
2288 
handleUnattendedReboot()2289     private int handleUnattendedReboot() {
2290         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
2291         // non user build.
2292         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
2293             getErrPrintWriter().println("UnattendedReboot: Permission denied.");
2294             return -1;
2295         }
2296 
2297         int result = TelephonyManager.getDefault().prepareForUnattendedReboot();
2298         getOutPrintWriter().println("result: " + result);
2299 
2300         return result != TelephonyManager.PREPARE_UNATTENDED_REBOOT_ERROR ? 0 : -1;
2301     }
2302 
handleGetSimSlotsMapping()2303     private int handleGetSimSlotsMapping() {
2304         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
2305         // non user build.
2306         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
2307             getErrPrintWriter().println("GetSimSlotsMapping: Permission denied.");
2308             return -1;
2309         }
2310         TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
2311         String result = telephonyManager.getSimSlotMapping().toString();
2312         getOutPrintWriter().println("simSlotsMapping: " + result);
2313 
2314         return 0;
2315     }
2316 
handleGbaCommand()2317     private int handleGbaCommand() {
2318         String arg = getNextArg();
2319         if (arg == null) {
2320             onHelpGba();
2321             return 0;
2322         }
2323 
2324         switch (arg) {
2325             case GBA_SET_SERVICE: {
2326                 return handleGbaSetServiceCommand();
2327             }
2328             case GBA_GET_SERVICE: {
2329                 return handleGbaGetServiceCommand();
2330             }
2331             case GBA_SET_RELEASE_TIME: {
2332                 return handleGbaSetReleaseCommand();
2333             }
2334             case GBA_GET_RELEASE_TIME: {
2335                 return handleGbaGetReleaseCommand();
2336             }
2337         }
2338 
2339         return -1;
2340     }
2341 
getSubId(String cmd)2342     private int getSubId(String cmd) {
2343         int slotId = getDefaultSlot();
2344         String opt = getNextOption();
2345         if (opt != null && opt.equals("-s")) {
2346             try {
2347                 slotId = Integer.parseInt(getNextArgRequired());
2348             } catch (NumberFormatException e) {
2349                 getErrPrintWriter().println(cmd + " requires an integer as a SLOT_ID.");
2350                 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
2351             }
2352         }
2353         return SubscriptionManager.getSubscriptionId(slotId);
2354     }
2355 
handleGbaSetServiceCommand()2356     private int handleGbaSetServiceCommand() {
2357         int subId = getSubId("gba set-service");
2358         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2359             return -1;
2360         }
2361 
2362         String packageName = getNextArg();
2363         try {
2364             if (packageName == null) {
2365                 packageName = "";
2366             }
2367             boolean result = mInterface.setBoundGbaServiceOverride(subId, packageName);
2368             if (VDBG) {
2369                 Log.v(LOG_TAG, "gba set-service -s " + subId + " "
2370                         + packageName + ", result=" + result);
2371             }
2372             getOutPrintWriter().println(result);
2373         } catch (RemoteException e) {
2374             Log.w(LOG_TAG, "gba set-service " + subId + " "
2375                     + packageName + ", error" + e.getMessage());
2376             getErrPrintWriter().println("Exception: " + e.getMessage());
2377             return -1;
2378         }
2379         return 0;
2380     }
2381 
handleGbaGetServiceCommand()2382     private int handleGbaGetServiceCommand() {
2383         String result;
2384 
2385         int subId = getSubId("gba get-service");
2386         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2387             return -1;
2388         }
2389 
2390         try {
2391             result = mInterface.getBoundGbaService(subId);
2392         } catch (RemoteException e) {
2393             return -1;
2394         }
2395         if (VDBG) {
2396             Log.v(LOG_TAG, "gba get-service -s " + subId + ", returned: " + result);
2397         }
2398         getOutPrintWriter().println(result);
2399         return 0;
2400     }
2401 
handleGbaSetReleaseCommand()2402     private int handleGbaSetReleaseCommand() {
2403         //the release time value could be -1
2404         int subId = getRemainingArgsCount() > 1 ? getSubId("gba set-release")
2405                 : SubscriptionManager.getDefaultSubscriptionId();
2406         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2407             return -1;
2408         }
2409 
2410         String intervalStr = getNextArg();
2411         if (intervalStr == null) {
2412             return -1;
2413         }
2414 
2415         try {
2416             int interval = Integer.parseInt(intervalStr);
2417             boolean result = mInterface.setGbaReleaseTimeOverride(subId, interval);
2418             if (VDBG) {
2419                 Log.v(LOG_TAG, "gba set-release -s " + subId + " "
2420                         + intervalStr + ", result=" + result);
2421             }
2422             getOutPrintWriter().println(result);
2423         } catch (NumberFormatException | RemoteException e) {
2424             Log.w(LOG_TAG, "gba set-release -s " + subId + " "
2425                     + intervalStr + ", error" + e.getMessage());
2426             getErrPrintWriter().println("Exception: " + e.getMessage());
2427             return -1;
2428         }
2429         return 0;
2430     }
2431 
handleGbaGetReleaseCommand()2432     private int handleGbaGetReleaseCommand() {
2433         int subId = getSubId("gba get-release");
2434         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2435             return -1;
2436         }
2437 
2438         int result = 0;
2439         try {
2440             result = mInterface.getGbaReleaseTime(subId);
2441         } catch (RemoteException e) {
2442             return -1;
2443         }
2444         if (VDBG) {
2445             Log.v(LOG_TAG, "gba get-release -s " + subId + ", returned: " + result);
2446         }
2447         getOutPrintWriter().println(result);
2448         return 0;
2449     }
2450 
handleSingleRegistrationConfigCommand()2451     private int handleSingleRegistrationConfigCommand() {
2452         String arg = getNextArg();
2453         if (arg == null) {
2454             onHelpSrc();
2455             return 0;
2456         }
2457 
2458         switch (arg) {
2459             case SRC_SET_TEST_ENABLED: {
2460                 return handleSrcSetTestEnabledCommand();
2461             }
2462             case SRC_GET_TEST_ENABLED: {
2463                 return handleSrcGetTestEnabledCommand();
2464             }
2465             case SRC_SET_DEVICE_ENABLED: {
2466                 return handleSrcSetDeviceEnabledCommand();
2467             }
2468             case SRC_GET_DEVICE_ENABLED: {
2469                 return handleSrcGetDeviceEnabledCommand();
2470             }
2471             case SRC_SET_CARRIER_ENABLED: {
2472                 return handleSrcSetCarrierEnabledCommand();
2473             }
2474             case SRC_GET_CARRIER_ENABLED: {
2475                 return handleSrcGetCarrierEnabledCommand();
2476             }
2477             case SRC_SET_FEATURE_ENABLED: {
2478                 return handleSrcSetFeatureValidationCommand();
2479             }
2480             case SRC_GET_FEATURE_ENABLED: {
2481                 return handleSrcGetFeatureValidationCommand();
2482             }
2483         }
2484 
2485         return -1;
2486     }
2487 
handleRcsUceCommand()2488     private int handleRcsUceCommand() {
2489         String arg = getNextArg();
2490         if (arg == null) {
2491             onHelpUce();
2492             return 0;
2493         }
2494 
2495         switch (arg) {
2496             case UCE_REMOVE_EAB_CONTACT:
2497                 return handleRemovingEabContactCommand();
2498             case UCE_GET_EAB_CONTACT:
2499                 return handleGettingEabContactCommand();
2500             case UCE_GET_EAB_CAPABILITY:
2501                 return handleGettingEabCapabilityCommand();
2502             case UCE_GET_DEVICE_ENABLED:
2503                 return handleUceGetDeviceEnabledCommand();
2504             case UCE_SET_DEVICE_ENABLED:
2505                 return handleUceSetDeviceEnabledCommand();
2506             case UCE_OVERRIDE_PUBLISH_CAPS:
2507                 return handleUceOverridePublishCaps();
2508             case UCE_GET_LAST_PIDF_XML:
2509                 return handleUceGetPidfXml();
2510             case UCE_REMOVE_REQUEST_DISALLOWED_STATUS:
2511                 return handleUceRemoveRequestDisallowedStatus();
2512             case UCE_SET_CAPABILITY_REQUEST_TIMEOUT:
2513                 return handleUceSetCapRequestTimeout();
2514         }
2515         return -1;
2516     }
2517 
handleRemovingEabContactCommand()2518     private int handleRemovingEabContactCommand() {
2519         int subId = getSubId("uce remove-eab-contact");
2520         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2521             return -1;
2522         }
2523 
2524         String phoneNumber = getNextArgRequired();
2525         if (TextUtils.isEmpty(phoneNumber)) {
2526             return -1;
2527         }
2528         int result = 0;
2529         try {
2530             result = mInterface.removeContactFromEab(subId, phoneNumber);
2531         } catch (RemoteException e) {
2532             Log.w(LOG_TAG, "uce remove-eab-contact -s " + subId + ", error " + e.getMessage());
2533             getErrPrintWriter().println("Exception: " + e.getMessage());
2534             return -1;
2535         }
2536 
2537         if (VDBG) {
2538             Log.v(LOG_TAG, "uce remove-eab-contact -s " + subId + ", result: " + result);
2539         }
2540         return 0;
2541     }
2542 
handleGettingEabContactCommand()2543     private int handleGettingEabContactCommand() {
2544         String phoneNumber = getNextArgRequired();
2545         if (TextUtils.isEmpty(phoneNumber)) {
2546             return -1;
2547         }
2548         String result = "";
2549         try {
2550             result = mInterface.getContactFromEab(phoneNumber);
2551         } catch (RemoteException e) {
2552             Log.w(LOG_TAG, "uce get-eab-contact, error " + e.getMessage());
2553             getErrPrintWriter().println("Exception: " + e.getMessage());
2554             return -1;
2555         }
2556 
2557         if (VDBG) {
2558             Log.v(LOG_TAG, "uce get-eab-contact, result: " + result);
2559         }
2560         getOutPrintWriter().println(result);
2561         return 0;
2562     }
2563 
handleGettingEabCapabilityCommand()2564     private int handleGettingEabCapabilityCommand() {
2565         String phoneNumber = getNextArgRequired();
2566         if (TextUtils.isEmpty(phoneNumber)) {
2567             return -1;
2568         }
2569         String result = "";
2570         try {
2571             result = mInterface.getCapabilityFromEab(phoneNumber);
2572         } catch (RemoteException e) {
2573             Log.w(LOG_TAG, "uce get-eab-capability, error " + e.getMessage());
2574             getErrPrintWriter().println("Exception: " + e.getMessage());
2575             return -1;
2576         }
2577 
2578         if (VDBG) {
2579             Log.v(LOG_TAG, "uce get-eab-capability, result: " + result);
2580         }
2581         getOutPrintWriter().println(result);
2582         return 0;
2583     }
2584 
handleUceGetDeviceEnabledCommand()2585     private int handleUceGetDeviceEnabledCommand() {
2586         boolean result = false;
2587         try {
2588             result = mInterface.getDeviceUceEnabled();
2589         } catch (RemoteException e) {
2590             Log.w(LOG_TAG, "uce get-device-enabled, error " + e.getMessage());
2591             return -1;
2592         }
2593         if (VDBG) {
2594             Log.v(LOG_TAG, "uce get-device-enabled, returned: " + result);
2595         }
2596         getOutPrintWriter().println(result);
2597         return 0;
2598     }
2599 
handleUceSetDeviceEnabledCommand()2600     private int handleUceSetDeviceEnabledCommand() {
2601         String enabledStr = getNextArg();
2602         if (TextUtils.isEmpty(enabledStr)) {
2603             return -1;
2604         }
2605 
2606         try {
2607             boolean isEnabled = Boolean.parseBoolean(enabledStr);
2608             mInterface.setDeviceUceEnabled(isEnabled);
2609             if (VDBG) {
2610                 Log.v(LOG_TAG, "uce set-device-enabled " + enabledStr + ", done");
2611             }
2612         } catch (NumberFormatException | RemoteException e) {
2613             Log.w(LOG_TAG, "uce set-device-enabled " + enabledStr + ", error " + e.getMessage());
2614             getErrPrintWriter().println("Exception: " + e.getMessage());
2615             return -1;
2616         }
2617         return 0;
2618     }
2619 
handleUceRemoveRequestDisallowedStatus()2620     private int handleUceRemoveRequestDisallowedStatus() {
2621         int subId = getSubId("uce remove-request-disallowed-status");
2622         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2623             Log.w(LOG_TAG, "uce remove-request-disallowed-status, Invalid subscription ID");
2624             return -1;
2625         }
2626         boolean result;
2627         try {
2628             result = mInterface.removeUceRequestDisallowedStatus(subId);
2629         } catch (RemoteException e) {
2630             Log.w(LOG_TAG, "uce remove-request-disallowed-status, error " + e.getMessage());
2631             return -1;
2632         }
2633         if (VDBG) {
2634             Log.v(LOG_TAG, "uce remove-request-disallowed-status, returned: " + result);
2635         }
2636         getOutPrintWriter().println(result);
2637         return 0;
2638     }
2639 
handleUceSetCapRequestTimeout()2640     private int handleUceSetCapRequestTimeout() {
2641         int subId = getSubId("uce set-capabilities-request-timeout");
2642         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2643             Log.w(LOG_TAG, "uce set-capabilities-request-timeout, Invalid subscription ID");
2644             return -1;
2645         }
2646         long timeoutAfterMs = Long.valueOf(getNextArg());
2647         boolean result;
2648         try {
2649             result = mInterface.setCapabilitiesRequestTimeout(subId, timeoutAfterMs);
2650         } catch (RemoteException e) {
2651             Log.w(LOG_TAG, "uce set-capabilities-request-timeout, error " + e.getMessage());
2652             return -1;
2653         }
2654         if (VDBG) {
2655             Log.v(LOG_TAG, "uce set-capabilities-request-timeout, returned: " + result);
2656         }
2657         getOutPrintWriter().println(result);
2658         return 0;
2659     }
2660 
handleSrcSetTestEnabledCommand()2661     private int handleSrcSetTestEnabledCommand() {
2662         String enabledStr = getNextArg();
2663         if (enabledStr == null) {
2664             return -1;
2665         }
2666 
2667         try {
2668             mInterface.setRcsSingleRegistrationTestModeEnabled(Boolean.parseBoolean(enabledStr));
2669             if (VDBG) {
2670                 Log.v(LOG_TAG, "src set-test-enabled " + enabledStr + ", done");
2671             }
2672             getOutPrintWriter().println("Done");
2673         } catch (NumberFormatException | RemoteException e) {
2674             Log.w(LOG_TAG, "src set-test-enabled " + enabledStr + ", error" + e.getMessage());
2675             getErrPrintWriter().println("Exception: " + e.getMessage());
2676             return -1;
2677         }
2678         return 0;
2679     }
2680 
handleSrcGetTestEnabledCommand()2681     private int handleSrcGetTestEnabledCommand() {
2682         boolean result = false;
2683         try {
2684             result = mInterface.getRcsSingleRegistrationTestModeEnabled();
2685         } catch (RemoteException e) {
2686             return -1;
2687         }
2688         if (VDBG) {
2689             Log.v(LOG_TAG, "src get-test-enabled, returned: " + result);
2690         }
2691         getOutPrintWriter().println(result);
2692         return 0;
2693     }
2694 
handleUceOverridePublishCaps()2695     private int handleUceOverridePublishCaps() {
2696         int subId = getSubId("uce override-published-caps");
2697         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2698             return -1;
2699         }
2700         //uce override-published-caps [-s SLOT_ID] add|remove|clear|list [CAPABILITIES]
2701         String operation = getNextArgRequired();
2702         String caps = getNextArg();
2703         if (!"add".equals(operation) && !"remove".equals(operation) && !"clear".equals(operation)
2704                 && !"list".equals(operation)) {
2705             getErrPrintWriter().println("Invalid operation: " + operation);
2706             return -1;
2707         }
2708 
2709         // add/remove requires capabilities to be specified.
2710         if ((!"clear".equals(operation) && !"list".equals(operation)) && TextUtils.isEmpty(caps)) {
2711             getErrPrintWriter().println("\"" + operation + "\" requires capabilities to be "
2712                     + "specified");
2713             return -1;
2714         }
2715 
2716         ArraySet<String> capSet = new ArraySet<>();
2717         if (!TextUtils.isEmpty(caps)) {
2718             String[] capArray = caps.split(":");
2719             for (String cap : capArray) {
2720                 // Allow unknown tags to be passed in as well.
2721                 capSet.addAll(TEST_FEATURE_TAG_MAP.getOrDefault(cap, Collections.singleton(cap)));
2722             }
2723         }
2724 
2725         RcsContactUceCapability result = null;
2726         try {
2727             switch (operation) {
2728                 case "add":
2729                     result = mInterface.addUceRegistrationOverrideShell(subId,
2730                             new ArrayList<>(capSet));
2731                     break;
2732                 case "remove":
2733                     result = mInterface.removeUceRegistrationOverrideShell(subId,
2734                             new ArrayList<>(capSet));
2735                     break;
2736                 case "clear":
2737                     result = mInterface.clearUceRegistrationOverrideShell(subId);
2738                     break;
2739                 case "list":
2740                     result = mInterface.getLatestRcsContactUceCapabilityShell(subId);
2741                     break;
2742             }
2743         } catch (RemoteException e) {
2744             Log.w(LOG_TAG, "uce override-published-caps, error " + e.getMessage());
2745             getErrPrintWriter().println("Exception: " + e.getMessage());
2746             return -1;
2747         } catch (ServiceSpecificException sse) {
2748             // Reconstruct ImsException
2749             ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode);
2750             Log.w(LOG_TAG, "uce override-published-caps, error " + imsException);
2751             getErrPrintWriter().println("Exception: " + imsException);
2752             return -1;
2753         }
2754         if (result == null) {
2755             getErrPrintWriter().println("Service not available");
2756             return -1;
2757         }
2758         getOutPrintWriter().println(result);
2759         return 0;
2760     }
2761 
handleUceGetPidfXml()2762     private int handleUceGetPidfXml() {
2763         int subId = getSubId("uce get-last-publish-pidf");
2764         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2765             return -1;
2766         }
2767 
2768         String result;
2769         try {
2770             result = mInterface.getLastUcePidfXmlShell(subId);
2771         } catch (RemoteException e) {
2772             Log.w(LOG_TAG, "uce get-last-publish-pidf, error " + e.getMessage());
2773             getErrPrintWriter().println("Exception: " + e.getMessage());
2774             return -1;
2775         } catch (ServiceSpecificException sse) {
2776             // Reconstruct ImsException
2777             ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode);
2778             Log.w(LOG_TAG, "uce get-last-publish-pidf error " + imsException);
2779             getErrPrintWriter().println("Exception: " + imsException);
2780             return -1;
2781         }
2782         if (result == null) {
2783             getErrPrintWriter().println("Service not available");
2784             return -1;
2785         }
2786         getOutPrintWriter().println(result);
2787         return 0;
2788     }
2789 
handleSrcSetDeviceEnabledCommand()2790     private int handleSrcSetDeviceEnabledCommand() {
2791         String enabledStr = getNextArg();
2792         if (enabledStr == null) {
2793             return -1;
2794         }
2795 
2796         try {
2797             mInterface.setDeviceSingleRegistrationEnabledOverride(enabledStr);
2798             if (VDBG) {
2799                 Log.v(LOG_TAG, "src set-device-enabled " + enabledStr + ", done");
2800             }
2801             getOutPrintWriter().println("Done");
2802         } catch (NumberFormatException | RemoteException e) {
2803             Log.w(LOG_TAG, "src set-device-enabled " + enabledStr + ", error" + e.getMessage());
2804             getErrPrintWriter().println("Exception: " + e.getMessage());
2805             return -1;
2806         }
2807         return 0;
2808     }
2809 
handleSrcGetDeviceEnabledCommand()2810     private int handleSrcGetDeviceEnabledCommand() {
2811         boolean result = false;
2812         try {
2813             result = mInterface.getDeviceSingleRegistrationEnabled();
2814         } catch (RemoteException e) {
2815             return -1;
2816         }
2817         if (VDBG) {
2818             Log.v(LOG_TAG, "src get-device-enabled, returned: " + result);
2819         }
2820         getOutPrintWriter().println(result);
2821         return 0;
2822     }
2823 
handleSrcSetCarrierEnabledCommand()2824     private int handleSrcSetCarrierEnabledCommand() {
2825         //the release time value could be -1
2826         int subId = getRemainingArgsCount() > 1 ? getSubId("src set-carrier-enabled")
2827                 : SubscriptionManager.getDefaultSubscriptionId();
2828         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2829             return -1;
2830         }
2831 
2832         String enabledStr = getNextArg();
2833         if (enabledStr == null) {
2834             return -1;
2835         }
2836 
2837         try {
2838             boolean result =
2839                     mInterface.setCarrierSingleRegistrationEnabledOverride(subId, enabledStr);
2840             if (VDBG) {
2841                 Log.v(LOG_TAG, "src set-carrier-enabled -s " + subId + " "
2842                         + enabledStr + ", result=" + result);
2843             }
2844             getOutPrintWriter().println(result);
2845         } catch (NumberFormatException | RemoteException e) {
2846             Log.w(LOG_TAG, "src set-carrier-enabled -s " + subId + " "
2847                     + enabledStr + ", error" + e.getMessage());
2848             getErrPrintWriter().println("Exception: " + e.getMessage());
2849             return -1;
2850         }
2851         return 0;
2852     }
2853 
handleSrcGetCarrierEnabledCommand()2854     private int handleSrcGetCarrierEnabledCommand() {
2855         int subId = getSubId("src get-carrier-enabled");
2856         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2857             return -1;
2858         }
2859 
2860         boolean result = false;
2861         try {
2862             result = mInterface.getCarrierSingleRegistrationEnabled(subId);
2863         } catch (RemoteException e) {
2864             return -1;
2865         }
2866         if (VDBG) {
2867             Log.v(LOG_TAG, "src get-carrier-enabled -s " + subId + ", returned: " + result);
2868         }
2869         getOutPrintWriter().println(result);
2870         return 0;
2871     }
2872 
handleSrcSetFeatureValidationCommand()2873     private int handleSrcSetFeatureValidationCommand() {
2874         //the release time value could be -1
2875         int subId = getRemainingArgsCount() > 1 ? getSubId("src set-feature-validation")
2876                 : SubscriptionManager.getDefaultSubscriptionId();
2877         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2878             return -1;
2879         }
2880 
2881         String enabledStr = getNextArg();
2882         if (enabledStr == null) {
2883             return -1;
2884         }
2885 
2886         try {
2887             boolean result =
2888                     mInterface.setImsFeatureValidationOverride(subId, enabledStr);
2889             if (VDBG) {
2890                 Log.v(LOG_TAG, "src set-feature-validation -s " + subId + " "
2891                         + enabledStr + ", result=" + result);
2892             }
2893             getOutPrintWriter().println(result);
2894         } catch (NumberFormatException | RemoteException e) {
2895             Log.w(LOG_TAG, "src set-feature-validation -s " + subId + " "
2896                     + enabledStr + ", error" + e.getMessage());
2897             getErrPrintWriter().println("Exception: " + e.getMessage());
2898             return -1;
2899         }
2900         return 0;
2901     }
2902 
handleSrcGetFeatureValidationCommand()2903     private int handleSrcGetFeatureValidationCommand() {
2904         int subId = getSubId("src get-feature-validation");
2905         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2906             return -1;
2907         }
2908 
2909         Boolean result = false;
2910         try {
2911             result = mInterface.getImsFeatureValidationOverride(subId);
2912         } catch (RemoteException e) {
2913             return -1;
2914         }
2915         if (VDBG) {
2916             Log.v(LOG_TAG, "src get-feature-validation -s " + subId + ", returned: " + result);
2917         }
2918         getOutPrintWriter().println(result);
2919         return 0;
2920     }
2921 
2922 
onHelpCallComposer()2923     private void onHelpCallComposer() {
2924         PrintWriter pw = getOutPrintWriter();
2925         pw.println("Call composer commands");
2926         pw.println("  callcomposer test-mode enable|disable|query");
2927         pw.println("    Enables or disables test mode for call composer. In test mode, picture");
2928         pw.println("    upload/download from carrier servers is disabled, and operations are");
2929         pw.println("    performed using emulated local files instead.");
2930         pw.println("  callcomposer simulate-outgoing-call [subId] [UUID]");
2931         pw.println("    Simulates an outgoing call being placed with the picture ID as");
2932         pw.println("    the provided UUID. This triggers storage to the call log.");
2933         pw.println("  callcomposer user-setting [subId] enable|disable|query");
2934         pw.println("    Enables or disables the user setting for call composer, as set by");
2935         pw.println("    TelephonyManager#setCallComposerStatus.");
2936     }
2937 
handleCallComposerCommand()2938     private int handleCallComposerCommand() {
2939         String arg = getNextArg();
2940         if (arg == null) {
2941             onHelpCallComposer();
2942             return 0;
2943         }
2944 
2945         mContext.enforceCallingPermission(Manifest.permission.MODIFY_PHONE_STATE,
2946                 "MODIFY_PHONE_STATE required for call composer shell cmds");
2947         switch (arg) {
2948             case CALL_COMPOSER_TEST_MODE: {
2949                 String enabledStr = getNextArg();
2950                 if (ENABLE.equals(enabledStr)) {
2951                     CallComposerPictureManager.sTestMode = true;
2952                 } else if (DISABLE.equals(enabledStr)) {
2953                     CallComposerPictureManager.sTestMode = false;
2954                 } else if (QUERY.equals(enabledStr)) {
2955                     getOutPrintWriter().println(CallComposerPictureManager.sTestMode);
2956                 } else {
2957                     onHelpCallComposer();
2958                     return 1;
2959                 }
2960                 break;
2961             }
2962             case CALL_COMPOSER_SIMULATE_CALL: {
2963                 int subscriptionId = Integer.valueOf(getNextArg());
2964                 String uuidString = getNextArg();
2965                 UUID uuid = UUID.fromString(uuidString);
2966                 CompletableFuture<Uri> storageUriFuture = new CompletableFuture<>();
2967                 Binder.withCleanCallingIdentity(() -> {
2968                     CallComposerPictureManager.getInstance(mContext, subscriptionId)
2969                             .storeUploadedPictureToCallLog(uuid, storageUriFuture::complete);
2970                 });
2971                 try {
2972                     Uri uri = storageUriFuture.get();
2973                     getOutPrintWriter().println(String.valueOf(uri));
2974                 } catch (Exception e) {
2975                     throw new RuntimeException(e);
2976                 }
2977                 break;
2978             }
2979             case CALL_COMPOSER_USER_SETTING: {
2980                 try {
2981                     int subscriptionId = Integer.valueOf(getNextArg());
2982                     String enabledStr = getNextArg();
2983                     if (ENABLE.equals(enabledStr)) {
2984                         mInterface.setCallComposerStatus(subscriptionId,
2985                                 TelephonyManager.CALL_COMPOSER_STATUS_ON);
2986                     } else if (DISABLE.equals(enabledStr)) {
2987                         mInterface.setCallComposerStatus(subscriptionId,
2988                                 TelephonyManager.CALL_COMPOSER_STATUS_OFF);
2989                     } else if (QUERY.equals(enabledStr)) {
2990                         getOutPrintWriter().println(mInterface.getCallComposerStatus(subscriptionId)
2991                                 == TelephonyManager.CALL_COMPOSER_STATUS_ON);
2992                     } else {
2993                         onHelpCallComposer();
2994                         return 1;
2995                     }
2996                 } catch (RemoteException e) {
2997                     e.printStackTrace(getOutPrintWriter());
2998                     return 1;
2999                 }
3000                 break;
3001             }
3002         }
3003         return 0;
3004     }
3005 
handleHasCarrierPrivilegesCommand()3006     private int handleHasCarrierPrivilegesCommand() {
3007         String packageName = getNextArgRequired();
3008 
3009         boolean hasCarrierPrivileges;
3010         final long token = Binder.clearCallingIdentity();
3011         try {
3012             hasCarrierPrivileges =
3013                     mInterface.checkCarrierPrivilegesForPackageAnyPhone(packageName)
3014                             == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
3015         } catch (RemoteException e) {
3016             Log.w(LOG_TAG, HAS_CARRIER_PRIVILEGES_COMMAND + " exception", e);
3017             getErrPrintWriter().println("Exception: " + e.getMessage());
3018             return -1;
3019         } finally {
3020             Binder.restoreCallingIdentity(token);
3021         }
3022 
3023         getOutPrintWriter().println(hasCarrierPrivileges);
3024         return 0;
3025     }
3026 
handleAllowedNetworkTypesCommand(String command)3027     private int handleAllowedNetworkTypesCommand(String command) {
3028         if (!checkShellUid()) {
3029             return -1;
3030         }
3031 
3032         PrintWriter errPw = getErrPrintWriter();
3033         String tag = command + ": ";
3034         String opt;
3035         int subId = -1;
3036         Log.v(LOG_TAG, command + " start");
3037 
3038         while ((opt = getNextOption()) != null) {
3039             if (opt.equals("-s")) {
3040                 try {
3041                     subId = slotStringToSubId(tag, getNextArgRequired());
3042                     if (!SubscriptionManager.isValidSubscriptionId(subId)) {
3043                         errPw.println(tag + "No valid subscription found.");
3044                         return -1;
3045                     }
3046                 } catch (IllegalArgumentException e) {
3047                     // Missing slot id
3048                     errPw.println(tag + "SLOT_ID expected after -s.");
3049                     return -1;
3050                 }
3051             } else {
3052                 errPw.println(tag + "Unknown option " + opt);
3053                 return -1;
3054             }
3055         }
3056 
3057         if (GET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) {
3058             return handleGetAllowedNetworkTypesCommand(subId);
3059         }
3060         if (SET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) {
3061             return handleSetAllowedNetworkTypesCommand(subId);
3062         }
3063         return -1;
3064     }
3065 
handleGetAllowedNetworkTypesCommand(int subId)3066     private int handleGetAllowedNetworkTypesCommand(int subId) {
3067         PrintWriter errPw = getErrPrintWriter();
3068 
3069         long result = -1;
3070         try {
3071             if (mInterface != null) {
3072                 result = mInterface.getAllowedNetworkTypesForReason(subId,
3073                         TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER);
3074             } else {
3075                 throw new IllegalStateException("telephony service is null.");
3076             }
3077         } catch (RemoteException e) {
3078             Log.e(TAG, "getAllowedNetworkTypesForReason RemoteException" + e);
3079             errPw.println(GET_ALLOWED_NETWORK_TYPES_FOR_USER + "RemoteException " + e);
3080             return -1;
3081         }
3082 
3083         getOutPrintWriter().println(TelephonyManager.convertNetworkTypeBitmaskToString(result));
3084         return 0;
3085     }
3086 
handleSetAllowedNetworkTypesCommand(int subId)3087     private int handleSetAllowedNetworkTypesCommand(int subId) {
3088         PrintWriter errPw = getErrPrintWriter();
3089 
3090         String bitmaskString = getNextArg();
3091         if (TextUtils.isEmpty(bitmaskString)) {
3092             errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No NETWORK_TYPES_BITMASK");
3093             return -1;
3094         }
3095         long allowedNetworkTypes = convertNetworkTypeBitmaskFromStringToLong(bitmaskString);
3096         if (allowedNetworkTypes < 0) {
3097             errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No valid NETWORK_TYPES_BITMASK");
3098             return -1;
3099         }
3100         boolean result = false;
3101         try {
3102             if (mInterface != null) {
3103                 result = mInterface.setAllowedNetworkTypesForReason(subId,
3104                         TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, allowedNetworkTypes);
3105             } else {
3106                 throw new IllegalStateException("telephony service is null.");
3107             }
3108         } catch (RemoteException e) {
3109             Log.e(TAG, "setAllowedNetworkTypesForReason RemoteException" + e);
3110             errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " RemoteException " + e);
3111             return -1;
3112         }
3113 
3114         String resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " failed";
3115         if (result) {
3116             resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " completed";
3117         }
3118         getOutPrintWriter().println(resultMessage);
3119         return 0;
3120     }
3121 
convertNetworkTypeBitmaskFromStringToLong(String bitmaskString)3122     private long convertNetworkTypeBitmaskFromStringToLong(String bitmaskString) {
3123         if (TextUtils.isEmpty(bitmaskString)) {
3124             return -1;
3125         }
3126         if (VDBG) {
3127             Log.v(LOG_TAG, "AllowedNetworkTypes:" + bitmaskString
3128                             + ", length: " + bitmaskString.length());
3129         }
3130         try {
3131             return Long.parseLong(bitmaskString, 2);
3132         } catch (NumberFormatException e) {
3133             Log.e(LOG_TAG, "AllowedNetworkTypes: " + e);
3134             return -1;
3135         }
3136     }
3137 
handleRadioSetModemServiceCommand()3138     private int handleRadioSetModemServiceCommand() {
3139         PrintWriter errPw = getErrPrintWriter();
3140         String serviceName = null;
3141 
3142         String opt;
3143         while ((opt = getNextOption()) != null) {
3144             switch (opt) {
3145                 case "-s": {
3146                     serviceName = getNextArgRequired();
3147                     break;
3148                 }
3149             }
3150         }
3151 
3152         try {
3153             boolean result = mInterface.setModemService(serviceName);
3154             if (VDBG) {
3155                 Log.v(LOG_TAG,
3156                         "RadioSetModemService " + serviceName + ", result = " + result);
3157             }
3158             getOutPrintWriter().println(result);
3159         } catch (RemoteException e) {
3160             Log.w(LOG_TAG,
3161                     "RadioSetModemService: " + serviceName + ", error = " + e.getMessage());
3162             errPw.println("Exception: " + e.getMessage());
3163             return -1;
3164         }
3165         return 0;
3166     }
3167 
handleRadioGetModemServiceCommand()3168     private int handleRadioGetModemServiceCommand() {
3169         PrintWriter errPw = getErrPrintWriter();
3170         String result;
3171 
3172         try {
3173             result = mInterface.getModemService();
3174             getOutPrintWriter().println(result);
3175         } catch (RemoteException e) {
3176             errPw.println("Exception: " + e.getMessage());
3177             return -1;
3178         }
3179         if (VDBG) {
3180             Log.v(LOG_TAG, "RadioGetModemService, result = " + result);
3181         }
3182         return 0;
3183     }
3184 
handleRadioCommand()3185     private int handleRadioCommand() {
3186         String arg = getNextArg();
3187         if (arg == null) {
3188             onHelpRadio();
3189             return 0;
3190         }
3191 
3192         switch (arg) {
3193             case RADIO_SET_MODEM_SERVICE:
3194                 return handleRadioSetModemServiceCommand();
3195 
3196             case RADIO_GET_MODEM_SERVICE:
3197                 return handleRadioGetModemServiceCommand();
3198         }
3199 
3200         return -1;
3201     }
3202 
handleSetSatelliteServicePackageNameCommand()3203     private int handleSetSatelliteServicePackageNameCommand() {
3204         PrintWriter errPw = getErrPrintWriter();
3205         String serviceName = null;
3206 
3207         String opt;
3208         while ((opt = getNextOption()) != null) {
3209             switch (opt) {
3210                 case "-s": {
3211                     serviceName = getNextArgRequired();
3212                     break;
3213                 }
3214             }
3215         }
3216         Log.d(LOG_TAG, "handleSetSatelliteServicePackageNameCommand: serviceName="
3217                 + serviceName);
3218 
3219         try {
3220             boolean result = mInterface.setSatelliteServicePackageName(serviceName);
3221             if (VDBG) {
3222                 Log.v(LOG_TAG, "SetSatelliteServicePackageName " + serviceName
3223                         + ", result = " + result);
3224             }
3225             getOutPrintWriter().println(result);
3226         } catch (RemoteException e) {
3227             Log.w(LOG_TAG, "SetSatelliteServicePackageName: " + serviceName
3228                     + ", error = " + e.getMessage());
3229             errPw.println("Exception: " + e.getMessage());
3230             return -1;
3231         }
3232         return 0;
3233     }
3234 
handleSetSatelliteGatewayServicePackageNameCommand()3235     private int handleSetSatelliteGatewayServicePackageNameCommand() {
3236         PrintWriter errPw = getErrPrintWriter();
3237         String serviceName = null;
3238 
3239         String opt;
3240         while ((opt = getNextOption()) != null) {
3241             switch (opt) {
3242                 case "-s": {
3243                     serviceName = getNextArgRequired();
3244                     break;
3245                 }
3246             }
3247         }
3248         Log.d(LOG_TAG, "handleSetSatelliteGatewayServicePackageNameCommand: serviceName="
3249                 + serviceName);
3250 
3251         try {
3252             boolean result = mInterface.setSatelliteGatewayServicePackageName(serviceName);
3253             if (VDBG) {
3254                 Log.v(LOG_TAG, "setSatelliteGatewayServicePackageName " + serviceName
3255                         + ", result = " + result);
3256             }
3257             getOutPrintWriter().println(result);
3258         } catch (RemoteException e) {
3259             Log.w(LOG_TAG, "setSatelliteGatewayServicePackageName: " + serviceName
3260                     + ", error = " + e.getMessage());
3261             errPw.println("Exception: " + e.getMessage());
3262             return -1;
3263         }
3264         return 0;
3265     }
3266 
handleSetSatellitePointingUiClassNameCommand()3267     private int handleSetSatellitePointingUiClassNameCommand() {
3268         PrintWriter errPw = getErrPrintWriter();
3269         String packageName = null;
3270         String className = null;
3271 
3272         String opt;
3273         while ((opt = getNextOption()) != null) {
3274             switch (opt) {
3275                 case "-p": {
3276                     packageName = getNextArgRequired();
3277                     break;
3278                 }
3279                 case "-c": {
3280                     className = getNextArgRequired();
3281                     break;
3282                 }
3283             }
3284         }
3285         Log.d(LOG_TAG, "handleSetSatellitePointingUiClassNameCommand: packageName="
3286                 + packageName + ", className=" + className);
3287 
3288         try {
3289             boolean result = mInterface.setSatellitePointingUiClassName(packageName, className);
3290             if (VDBG) {
3291                 Log.v(LOG_TAG, "setSatellitePointingUiClassName result =" + result);
3292             }
3293             getOutPrintWriter().println(result);
3294         } catch (RemoteException e) {
3295             Log.e(LOG_TAG, "setSatellitePointingUiClassName: " + packageName
3296                     + ", error = " + e.getMessage());
3297             errPw.println("Exception: " + e.getMessage());
3298             return -1;
3299         }
3300         return 0;
3301     }
3302 
handleSetEmergencyCallToSatelliteHandoverType()3303     private int handleSetEmergencyCallToSatelliteHandoverType() {
3304         PrintWriter errPw = getErrPrintWriter();
3305         int handoverType = -1;
3306         int delaySeconds = 0;
3307 
3308         String opt;
3309         while ((opt = getNextOption()) != null) {
3310             switch (opt) {
3311                 case "-t": {
3312                     try {
3313                         handoverType = Integer.parseInt(getNextArgRequired());
3314                     } catch (NumberFormatException e) {
3315                         errPw.println("SetEmergencyCallToSatelliteHandoverType: require an integer"
3316                                 + " for handoverType");
3317                         return -1;
3318                     }
3319                     break;
3320                 }
3321                 case "-d": {
3322                     try {
3323                         delaySeconds = Integer.parseInt(getNextArgRequired());
3324                     } catch (NumberFormatException e) {
3325                         errPw.println("SetEmergencyCallToSatelliteHandoverType: require an integer"
3326                                 + " for delaySeconds");
3327                         return -1;
3328                     }
3329                     break;
3330                 }
3331             }
3332         }
3333         Log.d(LOG_TAG, "handleSetEmergencyCallToSatelliteHandoverType: handoverType="
3334                 + handoverType + ", delaySeconds=" + delaySeconds);
3335 
3336         try {
3337             boolean result =
3338                     mInterface.setEmergencyCallToSatelliteHandoverType(handoverType, delaySeconds);
3339             if (VDBG) {
3340                 Log.v(LOG_TAG, "setEmergencyCallToSatelliteHandoverType result =" + result);
3341             }
3342             getOutPrintWriter().println(result);
3343         } catch (RemoteException e) {
3344             Log.e(LOG_TAG, "setEmergencyCallToSatelliteHandoverType: " + handoverType
3345                     + ", error = " + e.getMessage());
3346             errPw.println("Exception: " + e.getMessage());
3347             return -1;
3348         }
3349         return 0;
3350     }
3351 
handleSetSatelliteListeningTimeoutDuration()3352     private int handleSetSatelliteListeningTimeoutDuration() {
3353         PrintWriter errPw = getErrPrintWriter();
3354         long timeoutMillis = 0;
3355 
3356         String opt;
3357         while ((opt = getNextOption()) != null) {
3358             switch (opt) {
3359                 case "-t": {
3360                     timeoutMillis = Long.parseLong(getNextArgRequired());
3361                     break;
3362                 }
3363             }
3364         }
3365         Log.d(LOG_TAG, "handleSetSatelliteListeningTimeoutDuration: timeoutMillis="
3366                 + timeoutMillis);
3367 
3368         try {
3369             boolean result = mInterface.setSatelliteListeningTimeoutDuration(timeoutMillis);
3370             if (VDBG) {
3371                 Log.v(LOG_TAG, "setSatelliteListeningTimeoutDuration " + timeoutMillis
3372                         + ", result = " + result);
3373             }
3374             getOutPrintWriter().println(result);
3375         } catch (RemoteException e) {
3376             Log.w(LOG_TAG, "setSatelliteListeningTimeoutDuration: " + timeoutMillis
3377                     + ", error = " + e.getMessage());
3378             errPw.println("Exception: " + e.getMessage());
3379             return -1;
3380         }
3381         return 0;
3382     }
3383 
handleSetDatagramControllerTimeoutDuration()3384     private int handleSetDatagramControllerTimeoutDuration() {
3385         PrintWriter errPw = getErrPrintWriter();
3386         boolean reset = false;
3387         int timeoutType = 0;
3388         long timeoutMillis = 0;
3389 
3390         String opt;
3391         while ((opt = getNextOption()) != null) {
3392             switch (opt) {
3393                 case "-d": {
3394                     timeoutMillis = Long.parseLong(getNextArgRequired());
3395                     break;
3396                 }
3397                 case "-r": {
3398                     reset = true;
3399                     break;
3400                 }
3401                 case "-t": {
3402                     timeoutType = Integer.parseInt(getNextArgRequired());
3403                     break;
3404                 }
3405             }
3406         }
3407         Log.d(LOG_TAG, "setDatagramControllerTimeoutDuration: timeoutMillis="
3408                 + timeoutMillis + ", reset=" + reset + ", timeoutType=" + timeoutType);
3409 
3410         try {
3411             boolean result = mInterface.setDatagramControllerTimeoutDuration(
3412                     reset, timeoutType, timeoutMillis);
3413             if (VDBG) {
3414                 Log.v(LOG_TAG, "setDatagramControllerTimeoutDuration " + timeoutMillis
3415                         + ", result = " + result);
3416             }
3417             getOutPrintWriter().println(result);
3418         } catch (RemoteException e) {
3419             Log.w(LOG_TAG, "setDatagramControllerTimeoutDuration: " + timeoutMillis
3420                     + ", error = " + e.getMessage());
3421             errPw.println("Exception: " + e.getMessage());
3422             return -1;
3423         }
3424         return 0;
3425     }
3426 
handleSetDatagramControllerBooleanConfig()3427     private int handleSetDatagramControllerBooleanConfig() {
3428         PrintWriter errPw = getErrPrintWriter();
3429         boolean reset = false;
3430         int booleanType = 0;
3431         boolean enable = false;
3432 
3433         String opt;
3434         while ((opt = getNextOption()) != null) {
3435             switch (opt) {
3436                 case "-d": {
3437                     enable = Boolean.parseBoolean(getNextArgRequired());
3438                     break;
3439                 }
3440                 case "-r": {
3441                     reset = true;
3442                     break;
3443                 }
3444                 case "-t": {
3445                     booleanType = Integer.parseInt(getNextArgRequired());
3446                     break;
3447                 }
3448             }
3449         }
3450         Log.d(LOG_TAG, "setDatagramControllerBooleanConfig: enable="
3451                 + enable + ", reset=" + reset + ", booleanType=" + booleanType);
3452 
3453         try {
3454             boolean result = mInterface.setDatagramControllerBooleanConfig(
3455                     reset, booleanType, enable);
3456             if (VDBG) {
3457                 Log.v(LOG_TAG, "setDatagramControllerBooleanConfig result = " + result);
3458             }
3459             getOutPrintWriter().println(result);
3460         } catch (RemoteException e) {
3461             Log.w(LOG_TAG, "setDatagramControllerBooleanConfig: error = " + e.getMessage());
3462             errPw.println("Exception: " + e.getMessage());
3463             return -1;
3464         }
3465         return 0;
3466     }
3467 
handleSetSatelliteControllerTimeoutDuration()3468     private int handleSetSatelliteControllerTimeoutDuration() {
3469         PrintWriter errPw = getErrPrintWriter();
3470         boolean reset = false;
3471         int timeoutType = 0;
3472         long timeoutMillis = 0;
3473 
3474         String opt;
3475         while ((opt = getNextOption()) != null) {
3476             switch (opt) {
3477                 case "-d": {
3478                     timeoutMillis = Long.parseLong(getNextArgRequired());
3479                     break;
3480                 }
3481                 case "-r": {
3482                     reset = true;
3483                     break;
3484                 }
3485                 case "-t": {
3486                     timeoutType = Integer.parseInt(getNextArgRequired());
3487                     break;
3488                 }
3489             }
3490         }
3491         Log.d(LOG_TAG, "setSatelliteControllerTimeoutDuration: timeoutMillis="
3492                 + timeoutMillis + ", reset=" + reset + ", timeoutType=" + timeoutType);
3493 
3494         try {
3495             boolean result = mInterface.setSatelliteControllerTimeoutDuration(
3496                     reset, timeoutType, timeoutMillis);
3497             if (VDBG) {
3498                 Log.v(LOG_TAG, "setSatelliteControllerTimeoutDuration " + timeoutMillis
3499                         + ", result = " + result);
3500             }
3501             getOutPrintWriter().println(result);
3502         } catch (RemoteException e) {
3503             Log.w(LOG_TAG, "setSatelliteControllerTimeoutDuration: " + timeoutMillis
3504                     + ", error = " + e.getMessage());
3505             errPw.println("Exception: " + e.getMessage());
3506             return -1;
3507         }
3508         return 0;
3509     }
3510 
handleSetShouldSendDatagramToModemInDemoMode()3511     private int handleSetShouldSendDatagramToModemInDemoMode() {
3512         PrintWriter errPw = getErrPrintWriter();
3513         String opt;
3514         boolean shouldSendToDemoMode;
3515 
3516         if ((opt = getNextArg()) == null) {
3517             errPw.println(
3518                     "adb shell cmd phone set-should-send-datagram-to-modem-in-demo-mode :"
3519                             + " Invalid Argument");
3520             return -1;
3521         } else {
3522             switch (opt) {
3523                 case "true": {
3524                     shouldSendToDemoMode = true;
3525                     break;
3526                 }
3527                 case "false": {
3528                     shouldSendToDemoMode = false;
3529                     break;
3530                 }
3531                 default:
3532                     errPw.println(
3533                             "adb shell cmd phone set-should-send-datagram-to-modem-in-demo-mode :"
3534                                     + " Invalid Argument");
3535                     return -1;
3536             }
3537         }
3538 
3539         Log.d(LOG_TAG,
3540                 "handleSetShouldSendDatagramToModemInDemoMode(" + shouldSendToDemoMode + ")");
3541 
3542         try {
3543             boolean result = mInterface.setShouldSendDatagramToModemInDemoMode(
3544                     shouldSendToDemoMode);
3545             if (VDBG) {
3546                 Log.v(LOG_TAG, "handleSetShouldSendDatagramToModemInDemoMode returns: "
3547                         + result);
3548             }
3549             getOutPrintWriter().println(false);
3550         } catch (RemoteException e) {
3551             Log.w(LOG_TAG, "setShouldSendDatagramToModemInDemoMode(" + shouldSendToDemoMode
3552                     + "), error = " + e.getMessage());
3553             errPw.println("Exception: " + e.getMessage());
3554             return -1;
3555         }
3556         return 0;
3557     }
3558 
handleSetSatelliteAccessControlOverlayConfigs()3559     private int handleSetSatelliteAccessControlOverlayConfigs() {
3560         PrintWriter errPw = getErrPrintWriter();
3561         boolean reset = false;
3562         boolean isAllowed = false;
3563         String s2CellFile = null;
3564         long locationFreshDurationNanos = 0;
3565         List<String> satelliteCountryCodes = null;
3566 
3567         String opt;
3568         while ((opt = getNextOption()) != null) {
3569             switch (opt) {
3570                 case "-r": {
3571                     reset = true;
3572                     break;
3573                 }
3574                 case "-a": {
3575                     isAllowed = true;
3576                     break;
3577                 }
3578                 case "-f": {
3579                     s2CellFile = getNextArgRequired();
3580                     break;
3581                 }
3582                 case "-d": {
3583                     locationFreshDurationNanos = Long.parseLong(getNextArgRequired());
3584                     break;
3585                 }
3586                 case "-c": {
3587                     String countryCodeStr = getNextArgRequired();
3588                     satelliteCountryCodes = Arrays.asList(countryCodeStr.split(","));
3589                     break;
3590                 }
3591             }
3592         }
3593         Log.d(LOG_TAG, "handleSetSatelliteAccessControlOverlayConfigs: reset=" + reset
3594                 + ", isAllowed=" + isAllowed + ", s2CellFile=" + s2CellFile
3595                 + ", locationFreshDurationNanos=" + locationFreshDurationNanos
3596                 + ", satelliteCountryCodes=" + satelliteCountryCodes);
3597 
3598         try {
3599             boolean result = mInterface.setSatelliteAccessControlOverlayConfigs(reset, isAllowed,
3600                     s2CellFile, locationFreshDurationNanos, satelliteCountryCodes);
3601             if (VDBG) {
3602                 Log.v(LOG_TAG, "setSatelliteAccessControlOverlayConfigs result =" + result);
3603             }
3604             getOutPrintWriter().println(result);
3605         } catch (RemoteException e) {
3606             Log.e(LOG_TAG, "setSatelliteAccessControlOverlayConfigs: ex=" + e.getMessage());
3607             errPw.println("Exception: " + e.getMessage());
3608             return -1;
3609         }
3610         return 0;
3611     }
3612 
handleSetCountryCodes()3613     private int handleSetCountryCodes() {
3614         PrintWriter errPw = getErrPrintWriter();
3615         List<String> currentNetworkCountryCodes = new ArrayList<>();
3616         String locationCountryCode = null;
3617         long locationCountryCodeTimestampNanos = 0;
3618         Map<String, Long> cachedNetworkCountryCodes = new HashMap<>();
3619         boolean reset = false;
3620 
3621         String opt;
3622         while ((opt = getNextOption()) != null) {
3623             switch (opt) {
3624                 case "-r": {
3625                     reset = true;
3626                     break;
3627                 }
3628                 case "-n": {
3629                     String countryCodeStr = getNextArgRequired();
3630                     currentNetworkCountryCodes = Arrays.asList(countryCodeStr.split(","));
3631                     break;
3632                 }
3633                 case "-c": {
3634                     String cachedNetworkCountryCodeStr = getNextArgRequired();
3635                     cachedNetworkCountryCodes = parseStringLongMap(cachedNetworkCountryCodeStr);
3636                     break;
3637                 }
3638                 case "-l": {
3639                     locationCountryCode = getNextArgRequired();
3640                     break;
3641                 }
3642                 case "-t": {
3643                     locationCountryCodeTimestampNanos = Long.parseLong(getNextArgRequired());
3644                     break;
3645                 }
3646             }
3647         }
3648         Log.d(LOG_TAG, "setCountryCodes: locationCountryCode="
3649                 + locationCountryCode + ", locationCountryCodeTimestampNanos="
3650                 + locationCountryCodeTimestampNanos + ", currentNetworkCountryCodes="
3651                 + currentNetworkCountryCodes);
3652 
3653         try {
3654             boolean result = mInterface.setCountryCodes(reset, currentNetworkCountryCodes,
3655                     cachedNetworkCountryCodes, locationCountryCode,
3656                     locationCountryCodeTimestampNanos);
3657             if (VDBG) {
3658                 Log.v(LOG_TAG, "setCountryCodes result =" + result);
3659             }
3660             getOutPrintWriter().println(result);
3661         } catch (RemoteException e) {
3662             Log.e(LOG_TAG, "setCountryCodes: ex=" + e.getMessage());
3663             errPw.println("Exception: " + e.getMessage());
3664             return -1;
3665         }
3666         return 0;
3667     }
3668 
handleSetOemEnabledSatelliteProvisionStatus()3669     private int handleSetOemEnabledSatelliteProvisionStatus() {
3670         PrintWriter errPw = getErrPrintWriter();
3671         boolean isProvisioned = false;
3672         boolean reset = true;
3673 
3674         String opt;
3675         while ((opt = getNextOption()) != null) {
3676             switch (opt) {
3677                 case "-p": {
3678                     try {
3679                         isProvisioned = Boolean.parseBoolean(getNextArgRequired());
3680                         reset = false;
3681                     } catch (Exception e) {
3682                         errPw.println("setOemEnabledSatelliteProvisionStatus requires a boolean "
3683                                 + "after -p indicating provision status");
3684                         return -1;
3685                     }
3686                 }
3687             }
3688         }
3689         Log.d(LOG_TAG, "setOemEnabledSatelliteProvisionStatus: reset=" + reset
3690                 + ", isProvisioned=" + isProvisioned);
3691 
3692         try {
3693             boolean result = mInterface.setOemEnabledSatelliteProvisionStatus(reset, isProvisioned);
3694             if (VDBG) {
3695                 Log.v(LOG_TAG, "setOemEnabledSatelliteProvisionStatus result = " + result);
3696             }
3697             getOutPrintWriter().println(result);
3698         } catch (RemoteException e) {
3699             Log.w(LOG_TAG, "setOemEnabledSatelliteProvisionStatus: error = " + e.getMessage());
3700             errPw.println("Exception: " + e.getMessage());
3701             return -1;
3702         }
3703         return 0;
3704     }
3705 
handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache()3706     private int handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache() {
3707         PrintWriter errPw = getErrPrintWriter();
3708         String opt;
3709         String state;
3710 
3711         if ((opt = getNextArg()) == null) {
3712             errPw.println(
3713                     "adb shell cmd phone set-is-satellite-communication-allowed-for-current"
3714                             + "-location-cache :"
3715                             + " Invalid Argument");
3716             return -1;
3717         } else {
3718             switch (opt) {
3719                 case "-a": {
3720                     state = "cache_allowed";
3721                     break;
3722                 }
3723                 case "-n": {
3724                     state = "cache_clear_and_not_allowed";
3725                     break;
3726                 }
3727                 case "-c": {
3728                     state = "clear_cache_only";
3729                     break;
3730                 }
3731                 default:
3732                     errPw.println(
3733                             "adb shell cmd phone set-is-satellite-communication-allowed-for-current"
3734                                     + "-location-cache :"
3735                                     + " Invalid Argument");
3736                     return -1;
3737             }
3738         }
3739 
3740         Log.d(LOG_TAG, "handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache("
3741                 + state + ")");
3742 
3743         try {
3744             boolean result = mInterface.setIsSatelliteCommunicationAllowedForCurrentLocationCache(
3745                     state);
3746             if (VDBG) {
3747                 Log.v(LOG_TAG, "setIsSatelliteCommunicationAllowedForCurrentLocationCache "
3748                         + "returns: "
3749                         + result);
3750             }
3751             getOutPrintWriter().println(result);
3752         } catch (RemoteException e) {
3753             Log.w(LOG_TAG, "setIsSatelliteCommunicationAllowedForCurrentLocationCache("
3754                     + state + "), error = " + e.getMessage());
3755             errPw.println("Exception: " + e.getMessage());
3756             return -1;
3757         }
3758         return 0;
3759     }
3760 
3761     /**
3762      * Sample inputStr = "US,UK,CA;2,1,3"
3763      * Sample output: {[US,2], [UK,1], [CA,3]}
3764      */
parseStringLongMap(@ullable String inputStr)3765     @NonNull private Map<String, Long> parseStringLongMap(@Nullable String inputStr) {
3766         Map<String, Long> result = new HashMap<>();
3767         if (!TextUtils.isEmpty(inputStr)) {
3768             String[] stringLongArr = inputStr.split(";");
3769             if (stringLongArr.length != 2) {
3770                 Log.e(LOG_TAG, "parseStringLongMap: invalid inputStr=" + inputStr);
3771                 return result;
3772             }
3773 
3774             String[] stringArr = stringLongArr[0].split(",");
3775             String[] longArr = stringLongArr[1].split(",");
3776             if (stringArr.length != longArr.length) {
3777                 Log.e(LOG_TAG, "parseStringLongMap: invalid inputStr=" + inputStr);
3778                 return result;
3779             }
3780 
3781             for (int i = 0; i < stringArr.length; i++) {
3782                 try {
3783                     result.put(stringArr[i], Long.parseLong(longArr[i]));
3784                 } catch (Exception ex) {
3785                     Log.e(LOG_TAG, "parseStringLongMap: invalid inputStr=" + inputStr
3786                             + ", ex=" + ex);
3787                     return result;
3788                 }
3789             }
3790         }
3791         return result;
3792     }
3793 
handleCarrierRestrictionStatusCommand()3794     private int handleCarrierRestrictionStatusCommand() {
3795         try {
3796             String MOCK_MODEM_SERVICE_NAME = "android.telephony.mockmodem.MockModemService";
3797             if (!(checkShellUid() && MOCK_MODEM_SERVICE_NAME.equalsIgnoreCase(
3798                     mInterface.getModemService()))) {
3799                 Log.v(LOG_TAG,
3800                         "handleCarrierRestrictionStatusCommand, MockModem service check fails or "
3801                                 + " checkShellUid fails");
3802                 return -1;
3803             }
3804         } catch (RemoteException ex) {
3805             ex.printStackTrace();
3806         }
3807         String callerInfo = getNextOption();
3808         CarrierAllowListInfo allowListInfo = CarrierAllowListInfo.loadInstance(mContext);
3809         if (TextUtils.isEmpty(callerInfo)) {
3810             // reset the Json content after testing
3811             allowListInfo.updateJsonForTest(null);
3812             return 0;
3813         }
3814         if (callerInfo.startsWith("--")) {
3815             callerInfo = callerInfo.replace("--", "");
3816         }
3817         String params[] = callerInfo.split(",");
3818         StringBuffer jsonStrBuffer = new StringBuffer();
3819         String tokens;
3820         for (int index = 0; index < params.length; index++) {
3821             tokens = convertToJsonString(index, params[index]);
3822             if (TextUtils.isEmpty(tokens)) {
3823                 // received wrong format from CTS
3824                 if (VDBG) {
3825                     Log.v(LOG_TAG,
3826                             "handleCarrierRestrictionStatusCommand, Shell command parsing error");
3827                 }
3828                 return -1;
3829             }
3830             jsonStrBuffer.append(tokens);
3831         }
3832         int result = allowListInfo.updateJsonForTest(jsonStrBuffer.toString());
3833         return result;
3834     }
3835 
3836     // set-carrier-service-package-override
setCarrierServicePackageOverride()3837     private int setCarrierServicePackageOverride() {
3838         PrintWriter errPw = getErrPrintWriter();
3839         int subId = SubscriptionManager.getDefaultSubscriptionId();
3840 
3841         String opt;
3842         while ((opt = getNextOption()) != null) {
3843             switch (opt) {
3844                 case "-s":
3845                     try {
3846                         subId = Integer.parseInt(getNextArgRequired());
3847                     } catch (NumberFormatException e) {
3848                         errPw.println(
3849                                 "set-carrier-service-package-override requires an integer as a"
3850                                         + " subscription ID.");
3851                         return -1;
3852                     }
3853                     break;
3854             }
3855         }
3856 
3857         String packageName = getNextArg();
3858         if (packageName == null) {
3859             errPw.println("set-carrier-service-package-override requires a override package name.");
3860             return -1;
3861         }
3862 
3863         try {
3864             mInterface.setCarrierServicePackageOverride(
3865                     subId, packageName, mContext.getOpPackageName());
3866 
3867             if (VDBG) {
3868                 Log.v(
3869                         LOG_TAG,
3870                         "set-carrier-service-package-override -s " + subId + " " + packageName);
3871             }
3872         } catch (RemoteException | IllegalArgumentException | IllegalStateException e) {
3873             Log.w(
3874                     LOG_TAG,
3875                     "set-carrier-service-package-override -s "
3876                             + subId
3877                             + " "
3878                             + packageName
3879                             + ", error"
3880                             + e.getMessage());
3881             errPw.println("Exception: " + e.getMessage());
3882             return -1;
3883         }
3884         return 0;
3885     }
3886 
3887     // clear-carrier-service-package-override
clearCarrierServicePackageOverride()3888     private int clearCarrierServicePackageOverride() {
3889         PrintWriter errPw = getErrPrintWriter();
3890         int subId = SubscriptionManager.getDefaultSubscriptionId();
3891 
3892         String opt;
3893         while ((opt = getNextOption()) != null) {
3894             switch (opt) {
3895                 case "-s":
3896                     try {
3897                         subId = Integer.parseInt(getNextArgRequired());
3898                     } catch (NumberFormatException e) {
3899                         errPw.println(
3900                                 "clear-carrier-service-package-override requires an integer as a"
3901                                         + " subscription ID.");
3902                         return -1;
3903                     }
3904                     break;
3905             }
3906         }
3907 
3908         try {
3909             mInterface.setCarrierServicePackageOverride(subId, null, mContext.getOpPackageName());
3910 
3911             if (VDBG) {
3912                 Log.v(LOG_TAG, "clear-carrier-service-package-override -s " + subId);
3913             }
3914         } catch (RemoteException | IllegalArgumentException | IllegalStateException e) {
3915             Log.w(
3916                     LOG_TAG,
3917                     "clear-carrier-service-package-override -s "
3918                             + subId
3919                             + ", error"
3920                             + e.getMessage());
3921             errPw.println("Exception: " + e.getMessage());
3922             return -1;
3923         }
3924         return 0;
3925     }
3926 
handleDomainSelectionCommand()3927     private int handleDomainSelectionCommand() {
3928         String arg = getNextArg();
3929         if (arg == null) {
3930             onHelpDomainSelection();
3931             return 0;
3932         }
3933 
3934         switch (arg) {
3935             case DOMAIN_SELECTION_SET_SERVICE_OVERRIDE: {
3936                 return handleDomainSelectionSetServiceOverrideCommand();
3937             }
3938             case DOMAIN_SELECTION_CLEAR_SERVICE_OVERRIDE: {
3939                 return handleDomainSelectionClearServiceOverrideCommand();
3940             }
3941         }
3942 
3943         return -1;
3944     }
3945 
3946     // domainselection set-dss-override
handleDomainSelectionSetServiceOverrideCommand()3947     private int handleDomainSelectionSetServiceOverrideCommand() {
3948         PrintWriter errPw = getErrPrintWriter();
3949 
3950         String componentName = getNextArg();
3951 
3952         try {
3953             boolean result = mInterface.setDomainSelectionServiceOverride(
3954                     ComponentName.unflattenFromString(componentName));
3955             if (VDBG) {
3956                 Log.v(LOG_TAG, "domainselection set-dss-override "
3957                         + componentName + ", result=" + result);
3958             }
3959             getOutPrintWriter().println(result);
3960         } catch (Exception e) {
3961             Log.w(LOG_TAG, "domainselection set-dss-override "
3962                     + componentName + ", error=" + e.getMessage());
3963             errPw.println("Exception: " + e.getMessage());
3964             return -1;
3965         }
3966         return 0;
3967     }
3968 
3969     // domainselection clear-dss-override
handleDomainSelectionClearServiceOverrideCommand()3970     private int handleDomainSelectionClearServiceOverrideCommand() {
3971         PrintWriter errPw = getErrPrintWriter();
3972 
3973         try {
3974             boolean result = mInterface.clearDomainSelectionServiceOverride();
3975             if (VDBG) {
3976                 Log.v(LOG_TAG, "domainselection clear-dss-override result=" + result);
3977             }
3978             getOutPrintWriter().println(result);
3979         } catch (RemoteException e) {
3980             Log.w(LOG_TAG, "domainselection clear-dss-override error=" + e.getMessage());
3981             errPw.println("Exception: " + e.getMessage());
3982             return -1;
3983         }
3984         return 0;
3985     }
3986 
3987     /**
3988      * Building the string that can be used to build the JsonObject which supports to stub the data
3989      * in CarrierAllowListInfo for CTS testing. sample format is like
3990      * {"com.android.example":{"carrierIds":[10000],"callerSHA256Ids":["XXXXXXXXXXXXXX"]}}
3991      */
convertToJsonString(int index, String param)3992     private String convertToJsonString(int index, String param) {
3993 
3994         String token[] = param.split(":");
3995         String jSonString;
3996         switch (index) {
3997             case 0:
3998                 jSonString = "{" + QUOTES + token[1] + QUOTES + ":";
3999                 break;
4000             case 1:
4001                 jSonString =
4002                         "{" + QUOTES + token[0] + QUOTES + ":" + "[" + token[1] + "],";
4003                 break;
4004             case 2:
4005                 jSonString =
4006                         QUOTES + token[0] + QUOTES + ":" + "[" + QUOTES + token[1] + QUOTES + "]}}";
4007                 break;
4008             default:
4009                 jSonString = null;
4010         }
4011         return jSonString;
4012     }
4013 }
4014