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 android.Manifest;
25 import android.content.Context;
26 import android.net.Uri;
27 import android.os.Binder;
28 import android.os.PersistableBundle;
29 import android.os.Process;
30 import android.os.RemoteException;
31 import android.os.ServiceSpecificException;
32 import android.provider.BlockedNumberContract;
33 import android.telephony.BarringInfo;
34 import android.telephony.CarrierConfigManager;
35 import android.telephony.SubscriptionInfo;
36 import android.telephony.SubscriptionManager;
37 import android.telephony.TelephonyManager;
38 import android.telephony.TelephonyRegistryManager;
39 import android.telephony.emergency.EmergencyNumber;
40 import android.telephony.ims.ImsException;
41 import android.telephony.ims.RcsContactUceCapability;
42 import android.telephony.ims.feature.ImsFeature;
43 import android.text.TextUtils;
44 import android.util.ArrayMap;
45 import android.util.ArraySet;
46 import android.util.Log;
47 import android.util.SparseArray;
48 
49 import com.android.ims.rcs.uce.util.FeatureTags;
50 import com.android.internal.telephony.ITelephony;
51 import com.android.internal.telephony.Phone;
52 import com.android.internal.telephony.PhoneFactory;
53 import com.android.internal.telephony.d2d.Communicator;
54 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
55 import com.android.internal.telephony.util.TelephonyUtils;
56 import com.android.modules.utils.BasicShellCommandHandler;
57 import com.android.phone.callcomposer.CallComposerPictureManager;
58 
59 import java.io.PrintWriter;
60 import java.util.ArrayList;
61 import java.util.Arrays;
62 import java.util.Collections;
63 import java.util.HashMap;
64 import java.util.List;
65 import java.util.Map;
66 import java.util.Set;
67 import java.util.TreeSet;
68 import java.util.UUID;
69 import java.util.concurrent.CompletableFuture;
70 
71 /**
72  * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
73  * permission checks have been done before onCommand was called. Make sure any commands processed
74  * here also contain the appropriate permissions checks.
75  */
76 
77 public class TelephonyShellCommand extends BasicShellCommandHandler {
78 
79     private static final String LOG_TAG = "TelephonyShellCommand";
80     // Don't commit with this true.
81     private static final boolean VDBG = true;
82     private static final int DEFAULT_PHONE_ID = 0;
83 
84     private static final String CALL_COMPOSER_SUBCOMMAND = "callcomposer";
85     private static final String IMS_SUBCOMMAND = "ims";
86     private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
87     private static final String EMERGENCY_CALLBACK_MODE = "emergency-callback-mode";
88     private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
89     private static final String END_BLOCK_SUPPRESSION = "end-block-suppression";
90     private static final String RESTART_MODEM = "restart-modem";
91     private static final String UNATTENDED_REBOOT = "unattended-reboot";
92     private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
93     private static final String DATA_TEST_MODE = "data";
94     private static final String ENABLE = "enable";
95     private static final String DISABLE = "disable";
96     private static final String QUERY = "query";
97 
98     private static final String CALL_COMPOSER_TEST_MODE = "test-mode";
99     private static final String CALL_COMPOSER_SIMULATE_CALL = "simulate-outgoing-call";
100     private static final String CALL_COMPOSER_USER_SETTING = "user-setting";
101 
102     private static final String IMS_SET_IMS_SERVICE = "set-ims-service";
103     private static final String IMS_GET_IMS_SERVICE = "get-ims-service";
104     private static final String IMS_CLEAR_SERVICE_OVERRIDE = "clear-ims-service-override";
105     // Used to disable or enable processing of conference event package data from the network.
106     // This is handy for testing scenarios where CEP data does not exist on a network which does
107     // support CEP data.
108     private static final String IMS_CEP = "conference-event-package";
109 
110     private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
111     private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
112 
113     private static final String CC_GET_VALUE = "get-value";
114     private static final String CC_SET_VALUE = "set-value";
115     private static final String CC_CLEAR_VALUES = "clear-values";
116 
117     private static final String GBA_SUBCOMMAND = "gba";
118     private static final String GBA_SET_SERVICE = "set-service";
119     private static final String GBA_GET_SERVICE = "get-service";
120     private static final String GBA_SET_RELEASE_TIME = "set-release";
121     private static final String GBA_GET_RELEASE_TIME = "get-release";
122 
123     private static final String SINGLE_REGISTATION_CONFIG = "src";
124     private static final String SRC_SET_DEVICE_ENABLED = "set-device-enabled";
125     private static final String SRC_GET_DEVICE_ENABLED = "get-device-enabled";
126     private static final String SRC_SET_CARRIER_ENABLED = "set-carrier-enabled";
127     private static final String SRC_GET_CARRIER_ENABLED = "get-carrier-enabled";
128     private static final String SRC_SET_TEST_ENABLED = "set-test-enabled";
129     private static final String SRC_GET_TEST_ENABLED = "get-test-enabled";
130     private static final String SRC_SET_FEATURE_ENABLED = "set-feature-validation";
131     private static final String SRC_GET_FEATURE_ENABLED = "get-feature-validation";
132 
133     private static final String D2D_SUBCOMMAND = "d2d";
134     private static final String D2D_SEND = "send";
135     private static final String D2D_TRANSPORT = "transport";
136     private static final String D2D_SET_DEVICE_SUPPORT = "set-device-support";
137 
138     private static final String BARRING_SUBCOMMAND = "barring";
139     private static final String BARRING_SEND_INFO = "send";
140 
141     private static final String RCS_UCE_COMMAND = "uce";
142     private static final String UCE_GET_EAB_CONTACT = "get-eab-contact";
143     private static final String UCE_GET_EAB_CAPABILITY = "get-eab-capability";
144     private static final String UCE_REMOVE_EAB_CONTACT = "remove-eab-contact";
145     private static final String UCE_GET_DEVICE_ENABLED = "get-device-enabled";
146     private static final String UCE_SET_DEVICE_ENABLED = "set-device-enabled";
147     private static final String UCE_OVERRIDE_PUBLISH_CAPS = "override-published-caps";
148     private static final String UCE_GET_LAST_PIDF_XML = "get-last-publish-pidf";
149     private static final String UCE_REMOVE_REQUEST_DISALLOWED_STATUS =
150             "remove-request-disallowed-status";
151     private static final String UCE_SET_CAPABILITY_REQUEST_TIMEOUT =
152             "set-capabilities-request-timeout";
153 
154     // Check if a package has carrier privileges on any SIM, regardless of subId/phoneId.
155     private static final String HAS_CARRIER_PRIVILEGES_COMMAND = "has-carrier-privileges";
156 
157     private static final String DISABLE_PHYSICAL_SUBSCRIPTION = "disable-physical-subscription";
158     private static final String ENABLE_PHYSICAL_SUBSCRIPTION = "enable-physical-subscription";
159 
160     private static final String THERMAL_MITIGATION_COMMAND = "thermal-mitigation";
161     private static final String ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "allow-package";
162     private static final String DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "disallow-package";
163 
164     private static final String GET_ALLOWED_NETWORK_TYPES_FOR_USER =
165             "get-allowed-network-types-for-users";
166     private static final String SET_ALLOWED_NETWORK_TYPES_FOR_USER =
167             "set-allowed-network-types-for-users";
168     // Take advantage of existing methods that already contain permissions checks when possible.
169     private final ITelephony mInterface;
170 
171     private SubscriptionManager mSubscriptionManager;
172     private CarrierConfigManager mCarrierConfigManager;
173     private TelephonyRegistryManager mTelephonyRegistryManager;
174     private Context mContext;
175 
176     private enum CcType {
177         BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
178                 STRING_ARRAY, UNKNOWN
179     }
180 
181     private class CcOptionParseResult {
182         public int mSubId;
183         public boolean mPersistent;
184     }
185 
186     // Maps carrier config keys to type. It is possible to infer the type for most carrier config
187     // keys by looking at the end of the string which usually tells the type.
188     // For instance: "xxxx_string", "xxxx_string_array", etc.
189     // The carrier config keys in this map does not follow this convention. It is therefore not
190     // possible to infer the type for these keys by looking at the string.
191     private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
192             put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
193             put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
194             put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
195             put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
196             put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
197             put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
198             put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
199             put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
200             put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
201             put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
202             put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
203                     CcType.STRING);
204             put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
205                     CcType.STRING_ARRAY);
206             put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
207                     CcType.STRING_ARRAY);
208             put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
209             put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
210             put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
211             put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
212             put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
213             put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
214             put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
215             put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
216         }
217     };
218 
219     /**
220      * Map from a shorthand string to the feature tags required in registration required in order
221      * for the RCS feature to be considered "capable".
222      */
223     private static final Map<String, Set<String>> TEST_FEATURE_TAG_MAP;
224     static {
225         ArrayMap<String, Set<String>> map = new ArrayMap<>(18);
226         map.put("chat_v1", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_IM));
227         map.put("chat_v2", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_SESSION));
228         map.put("ft", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER));
229         map.put("ft_sms", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS));
230         map.put("mmtel", Collections.singleton(FeatureTags.FEATURE_TAG_MMTEL));
231         map.put("mmtel_vt", new ArraySet<>(Arrays.asList(FeatureTags.FEATURE_TAG_MMTEL,
232                 FeatureTags.FEATURE_TAG_VIDEO)));
233         map.put("geo_push", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH));
234         map.put("geo_push_sms", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS));
235         map.put("call_comp",
236                 Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING));
237         map.put("call_comp_mmtel",
238                 Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY));
239         map.put("call_post", Collections.singleton(FeatureTags.FEATURE_TAG_POST_CALL));
240         map.put("map", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_MAP));
241         map.put("sketch", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_SKETCH));
242         // Feature tags defined twice for chatbot session because we want v1 and v2 based on bot
243         // version
244         map.put("chatbot", new ArraySet<>(Arrays.asList(
245                 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION,
246                 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
247         map.put("chatbot_v2", new ArraySet<>(Arrays.asList(
248                 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION,
249                 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
250         map.put("chatbot_sa", new ArraySet<>(Arrays.asList(
251                 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG,
252                 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
253         map.put("chatbot_sa_v2", new ArraySet<>(Arrays.asList(
254                 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG,
255                 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
256         map.put("chatbot_role", Collections.singleton(FeatureTags.FEATURE_TAG_CHATBOT_ROLE));
257         TEST_FEATURE_TAG_MAP = Collections.unmodifiableMap(map);
258     }
259 
260 
TelephonyShellCommand(ITelephony binder, Context context)261     public TelephonyShellCommand(ITelephony binder, Context context) {
262         mInterface = binder;
263         mCarrierConfigManager =
264                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
265         mSubscriptionManager = (SubscriptionManager)
266                 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
267         mTelephonyRegistryManager = (TelephonyRegistryManager)
268                 context.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
269         mContext = context;
270     }
271 
272     @Override
onCommand(String cmd)273     public int onCommand(String cmd) {
274         if (cmd == null) {
275             return handleDefaultCommands(null);
276         }
277 
278         switch (cmd) {
279             case IMS_SUBCOMMAND: {
280                 return handleImsCommand();
281             }
282             case RCS_UCE_COMMAND:
283                 return handleRcsUceCommand();
284             case NUMBER_VERIFICATION_SUBCOMMAND:
285                 return handleNumberVerificationCommand();
286             case EMERGENCY_CALLBACK_MODE:
287                 return handleEmergencyCallbackModeCommand();
288             case EMERGENCY_NUMBER_TEST_MODE:
289                 return handleEmergencyNumberTestModeCommand();
290             case CARRIER_CONFIG_SUBCOMMAND: {
291                 return handleCcCommand();
292             }
293             case DATA_TEST_MODE:
294                 return handleDataTestModeCommand();
295             case END_BLOCK_SUPPRESSION:
296                 return handleEndBlockSuppressionCommand();
297             case GBA_SUBCOMMAND:
298                 return handleGbaCommand();
299             case D2D_SUBCOMMAND:
300                 return handleD2dCommand();
301             case BARRING_SUBCOMMAND:
302                 return handleBarringCommand();
303             case SINGLE_REGISTATION_CONFIG:
304                 return handleSingleRegistrationConfigCommand();
305             case RESTART_MODEM:
306                 return handleRestartModemCommand();
307             case CALL_COMPOSER_SUBCOMMAND:
308                 return handleCallComposerCommand();
309             case UNATTENDED_REBOOT:
310                 return handleUnattendedReboot();
311             case HAS_CARRIER_PRIVILEGES_COMMAND:
312                 return handleHasCarrierPrivilegesCommand();
313             case THERMAL_MITIGATION_COMMAND:
314                 return handleThermalMitigationCommand();
315             case DISABLE_PHYSICAL_SUBSCRIPTION:
316                 return handleEnablePhysicalSubscription(false);
317             case ENABLE_PHYSICAL_SUBSCRIPTION:
318                 return handleEnablePhysicalSubscription(true);
319             case GET_ALLOWED_NETWORK_TYPES_FOR_USER:
320             case SET_ALLOWED_NETWORK_TYPES_FOR_USER:
321                 return handleAllowedNetworkTypesCommand(cmd);
322             default: {
323                 return handleDefaultCommands(cmd);
324             }
325         }
326     }
327 
328     @Override
onHelp()329     public void onHelp() {
330         PrintWriter pw = getOutPrintWriter();
331         pw.println("Telephony Commands:");
332         pw.println("  help");
333         pw.println("    Print this help text.");
334         pw.println("  ims");
335         pw.println("    IMS Commands.");
336         pw.println("  uce");
337         pw.println("    RCS User Capability Exchange Commands.");
338         pw.println("  emergency-number-test-mode");
339         pw.println("    Emergency Number Test Mode Commands.");
340         pw.println("  end-block-suppression");
341         pw.println("    End Block Suppression command.");
342         pw.println("  data");
343         pw.println("    Data Test Mode Commands.");
344         pw.println("  cc");
345         pw.println("    Carrier Config Commands.");
346         pw.println("  gba");
347         pw.println("    GBA Commands.");
348         pw.println("  src");
349         pw.println("    RCS VoLTE Single Registration Config Commands.");
350         pw.println("  restart-modem");
351         pw.println("    Restart modem command.");
352         pw.println("  unattended-reboot");
353         pw.println("    Prepare for unattended reboot.");
354         pw.println("  has-carrier-privileges [package]");
355         pw.println("    Query carrier privilege status for a package. Prints true or false.");
356         pw.println("  get-allowed-network-types-for-users");
357         pw.println("    Get the Allowed Network Types.");
358         pw.println("  set-allowed-network-types-for-users");
359         pw.println("    Set the Allowed Network Types.");
360         onHelpIms();
361         onHelpUce();
362         onHelpEmergencyNumber();
363         onHelpEndBlockSupperssion();
364         onHelpDataTestMode();
365         onHelpCc();
366         onHelpGba();
367         onHelpSrc();
368         onHelpD2D();
369         onHelpDisableOrEnablePhysicalSubscription();
370         onHelpAllowedNetworkTypes();
371     }
372 
onHelpD2D()373     private void onHelpD2D() {
374         PrintWriter pw = getOutPrintWriter();
375         pw.println("D2D Comms Commands:");
376         pw.println("  d2d send TYPE VALUE");
377         pw.println("    Sends a D2D message of specified type and value.");
378         pw.println("    Type: " + MESSAGE_CALL_RADIO_ACCESS_TYPE + " - "
379                 + Communicator.messageToString(MESSAGE_CALL_RADIO_ACCESS_TYPE));
380         pw.println("    Type: " + MESSAGE_CALL_AUDIO_CODEC + " - " + Communicator.messageToString(
381                 MESSAGE_CALL_AUDIO_CODEC));
382         pw.println("    Type: " + MESSAGE_DEVICE_BATTERY_STATE + " - "
383                         + Communicator.messageToString(
384                         MESSAGE_DEVICE_BATTERY_STATE));
385         pw.println("    Type: " + MESSAGE_DEVICE_NETWORK_COVERAGE + " - "
386                 + Communicator.messageToString(MESSAGE_DEVICE_NETWORK_COVERAGE));
387         pw.println("  d2d transport TYPE");
388         pw.println("    Forces the specified D2D transport TYPE to be active.  Use the");
389         pw.println("    short class name of the transport; i.e. DtmfTransport or RtpTransport.");
390         pw.println("  d2d set-device-support true/default");
391         pw.println("    true - forces device support to be enabled for D2D.");
392         pw.println("    default - clear any previously set force-enable of D2D, reverting to ");
393         pw.println("    the current device's configuration.");
394     }
395 
onHelpBarring()396     private void onHelpBarring() {
397         PrintWriter pw = getOutPrintWriter();
398         pw.println("Barring Commands:");
399         pw.println("  barring send -s SLOT_ID -b BARRING_TYPE -c IS_CONDITIONALLY_BARRED"
400                 + " -t CONDITIONAL_BARRING_TIME_SECS");
401         pw.println("    Notifies of a barring info change for the specified slot id.");
402         pw.println("    BARRING_TYPE: 0 for BARRING_TYPE_NONE");
403         pw.println("    BARRING_TYPE: 1 for BARRING_TYPE_UNCONDITIONAL");
404         pw.println("    BARRING_TYPE: 2 for BARRING_TYPE_CONDITIONAL");
405         pw.println("    BARRING_TYPE: -1 for BARRING_TYPE_UNKNOWN");
406     }
407 
onHelpIms()408     private void onHelpIms() {
409         PrintWriter pw = getOutPrintWriter();
410         pw.println("IMS Commands:");
411         pw.println("  ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
412         pw.println("    Sets the ImsService defined in PACKAGE_NAME to to be the bound");
413         pw.println("    ImsService. Options are:");
414         pw.println("      -s: the slot ID that the ImsService should be bound for. If no option");
415         pw.println("          is specified, it will choose the default voice SIM slot.");
416         pw.println("      -c: Override the ImsService defined in the carrier configuration.");
417         pw.println("      -d: Override the ImsService defined in the device overlay.");
418         pw.println("      -f: Set the feature that this override if for, if no option is");
419         pw.println("          specified, the new package name will be used for all features.");
420         pw.println("  ims get-ims-service [-s SLOT_ID] [-c | -d]");
421         pw.println("    Gets the package name of the currently defined ImsService.");
422         pw.println("    Options are:");
423         pw.println("      -s: The SIM slot ID for the registered ImsService. If no option");
424         pw.println("          is specified, it will choose the default voice SIM slot.");
425         pw.println("      -c: The ImsService defined as the carrier configured ImsService.");
426         pw.println("      -d: The ImsService defined as the device default ImsService.");
427         pw.println("      -f: The feature type that the query will be requested for. If none is");
428         pw.println("          specified, the returned package name will correspond to MMTEL.");
429         pw.println("  ims clear-ims-service-override [-s SLOT_ID]");
430         pw.println("    Clear all carrier ImsService overrides. This does not work for device ");
431         pw.println("    configuration overrides. Options are:");
432         pw.println("      -s: The SIM slot ID for the registered ImsService. If no option");
433         pw.println("          is specified, it will choose the default voice SIM slot.");
434         pw.println("  ims enable [-s SLOT_ID]");
435         pw.println("    enables IMS for the SIM slot specified, or for the default voice SIM slot");
436         pw.println("    if none is specified.");
437         pw.println("  ims disable [-s SLOT_ID]");
438         pw.println("    disables IMS for the SIM slot specified, or for the default voice SIM");
439         pw.println("    slot if none is specified.");
440         pw.println("  ims conference-event-package [enable/disable]");
441         pw.println("    enables or disables handling or network conference event package data.");
442     }
443 
onHelpUce()444     private void onHelpUce() {
445         PrintWriter pw = getOutPrintWriter();
446         pw.println("User Capability Exchange Commands:");
447         pw.println("  uce get-eab-contact [PHONE_NUMBER]");
448         pw.println("    Get the EAB contacts from the EAB database.");
449         pw.println("    Options are:");
450         pw.println("      PHONE_NUMBER: The phone numbers to be removed from the EAB databases");
451         pw.println("    Expected output format :");
452         pw.println("      [PHONE_NUMBER],[RAW_CONTACT_ID],[CONTACT_ID],[DATA_ID]");
453         pw.println("  uce remove-eab-contact [-s SLOT_ID] [PHONE_NUMBER]");
454         pw.println("    Remove the EAB contacts from the EAB database.");
455         pw.println("    Options are:");
456         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
457         pw.println("          is specified, it will choose the default voice SIM slot.");
458         pw.println("      PHONE_NUMBER: The phone numbers to be removed from the EAB databases");
459         pw.println("  uce get-device-enabled");
460         pw.println("    Get the config to check whether the device supports RCS UCE or not.");
461         pw.println("  uce set-device-enabled true|false");
462         pw.println("    Set the device config for RCS User Capability Exchange to the value.");
463         pw.println("    The value could be true, false.");
464         pw.println("  uce override-published-caps [-s SLOT_ID] add|remove|clear [CAPABILITIES]");
465         pw.println("    Override the existing SIP PUBLISH with different capabilities.");
466         pw.println("    Options are:");
467         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
468         pw.println("          is specified, it will choose the default voice SIM slot.");
469         pw.println("      add [CAPABILITY]: add a new capability");
470         pw.println("      remove [CAPABILITY]: remove a capability");
471         pw.println("      clear: clear all capability overrides");
472         pw.println("      CAPABILITY: \":\" separated list of capabilities.");
473         pw.println("          Valid options are: [mmtel(_vt), chat_v1, chat_v2, ft, ft_sms,");
474         pw.println("          geo_push, geo_push_sms, call_comp, call_post, map, sketch, chatbot,");
475         pw.println("          chatbot_sa, chatbot_role] as well as full length");
476         pw.println("          featureTag=\"featureValue\" feature tags that are not defined here.");
477         pw.println("  uce get-last-publish-pidf [-s SLOT_ID]");
478         pw.println("    Get the PIDF XML included in the last SIP PUBLISH, or \"none\" if no ");
479         pw.println("    PUBLISH is active");
480         pw.println("  uce remove-request-disallowed-status [-s SLOT_ID]");
481         pw.println("    Remove the UCE is disallowed to execute UCE requests status");
482         pw.println("  uce set-capabilities-request-timeout [-s SLOT_ID] [REQUEST_TIMEOUT_MS]");
483         pw.println("    Set the timeout for contact capabilities request.");
484     }
485 
onHelpNumberVerification()486     private void onHelpNumberVerification() {
487         PrintWriter pw = getOutPrintWriter();
488         pw.println("Number verification commands");
489         pw.println("  numverify override-package PACKAGE_NAME;");
490         pw.println("    Set the authorized package for number verification.");
491         pw.println("    Leave the package name blank to reset.");
492         pw.println("  numverify fake-call NUMBER;");
493         pw.println("    Fake an incoming call from NUMBER. This is for testing. Output will be");
494         pw.println("    1 if the call would have been intercepted, 0 otherwise.");
495     }
496 
onHelpThermalMitigation()497     private void onHelpThermalMitigation() {
498         PrintWriter pw = getOutPrintWriter();
499         pw.println("Thermal mitigation commands");
500         pw.println("  thermal-mitigation allow-package PACKAGE_NAME");
501         pw.println("    Set the package as one of authorized packages for thermal mitigation.");
502         pw.println("  thermal-mitigation disallow-package PACKAGE_NAME");
503         pw.println("    Remove the package from one of the authorized packages for thermal "
504                 + "mitigation.");
505     }
506 
onHelpDisableOrEnablePhysicalSubscription()507     private void onHelpDisableOrEnablePhysicalSubscription() {
508         PrintWriter pw = getOutPrintWriter();
509         pw.println("Disable or enable a physical subscription");
510         pw.println("  disable-physical-subscription SUB_ID");
511         pw.println("    Disable the physical subscription with the provided subId, if allowed.");
512         pw.println("  enable-physical-subscription SUB_ID");
513         pw.println("    Enable the physical subscription with the provided subId, if allowed.");
514     }
515 
onHelpDataTestMode()516     private void onHelpDataTestMode() {
517         PrintWriter pw = getOutPrintWriter();
518         pw.println("Mobile Data Test Mode Commands:");
519         pw.println("  data enable: enable mobile data connectivity");
520         pw.println("  data disable: disable mobile data connectivity");
521     }
522 
onHelpEmergencyNumber()523     private void onHelpEmergencyNumber() {
524         PrintWriter pw = getOutPrintWriter();
525         pw.println("Emergency Number Test Mode Commands:");
526         pw.println("  emergency-number-test-mode ");
527         pw.println("    Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
528                 + " the test mode");
529         pw.println("      -a <emergency number address>: add an emergency number address for the"
530                 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
531         pw.println("      -c: clear the emergency number list in the test mode.");
532         pw.println("      -r <emergency number address>: remove an existing emergency number"
533                 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
534         pw.println("      -p: get the full emergency number list in the test mode.");
535     }
536 
onHelpEndBlockSupperssion()537     private void onHelpEndBlockSupperssion() {
538         PrintWriter pw = getOutPrintWriter();
539         pw.println("End Block Suppression command:");
540         pw.println("  end-block-suppression: disable suppressing blocking by contact");
541         pw.println("                         with emergency services.");
542     }
543 
onHelpCc()544     private void onHelpCc() {
545         PrintWriter pw = getOutPrintWriter();
546         pw.println("Carrier Config Commands:");
547         pw.println("  cc get-value [-s SLOT_ID] [KEY]");
548         pw.println("    Print carrier config values.");
549         pw.println("    Options are:");
550         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
551         pw.println("          is specified, it will choose the default voice SIM slot.");
552         pw.println("    KEY: The key to the carrier config value to print. All values are printed");
553         pw.println("         if KEY is not specified.");
554         pw.println("  cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
555         pw.println("    Set carrier config KEY to NEW_VALUE.");
556         pw.println("    Options are:");
557         pw.println("      -s: The SIM slot ID to set carrier config value for. If no option");
558         pw.println("          is specified, it will choose the default voice SIM slot.");
559         pw.println("      -p: Value will be stored persistent");
560         pw.println("    NEW_VALUE specifies the new value for carrier config KEY. Null will be");
561         pw.println("      used if NEW_VALUE is not set. Strings should be encapsulated with");
562         pw.println("      quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
563         pw.println("      Separate items in arrays with space . Example: \"item1\" \"item2\"");
564         pw.println("  cc clear-values [-s SLOT_ID]");
565         pw.println("    Clear all carrier override values that has previously been set");
566         pw.println("    with set-value");
567         pw.println("    Options are:");
568         pw.println("      -s: The SIM slot ID to clear carrier config values for. If no option");
569         pw.println("          is specified, it will choose the default voice SIM slot.");
570     }
571 
onHelpGba()572     private void onHelpGba() {
573         PrintWriter pw = getOutPrintWriter();
574         pw.println("Gba Commands:");
575         pw.println("  gba set-service [-s SLOT_ID] PACKAGE_NAME");
576         pw.println("    Sets the GbaService defined in PACKAGE_NAME to to be the bound.");
577         pw.println("    Options are:");
578         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
579         pw.println("          is specified, it will choose the default voice SIM slot.");
580         pw.println("  gba get-service [-s SLOT_ID]");
581         pw.println("    Gets the package name of the currently defined GbaService.");
582         pw.println("    Options are:");
583         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
584         pw.println("          is specified, it will choose the default voice SIM slot.");
585         pw.println("  gba set-release [-s SLOT_ID] n");
586         pw.println("    Sets the time to release/unbind GbaService in n milli-second.");
587         pw.println("    Do not release/unbind if n is -1.");
588         pw.println("    Options are:");
589         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
590         pw.println("          is specified, it will choose the default voice SIM slot.");
591         pw.println("  gba get-release [-s SLOT_ID]");
592         pw.println("    Gets the time to release/unbind GbaService in n milli-sencond.");
593         pw.println("    Options are:");
594         pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
595         pw.println("          is specified, it will choose the default voice SIM slot.");
596     }
597 
onHelpSrc()598     private void onHelpSrc() {
599         PrintWriter pw = getOutPrintWriter();
600         pw.println("RCS VoLTE Single Registration Config Commands:");
601         pw.println("  src set-test-enabled true|false");
602         pw.println("    Sets the test mode enabled for RCS VoLTE single registration.");
603         pw.println("    The value could be true, false, or null(undefined).");
604         pw.println("  src get-test-enabled");
605         pw.println("    Gets the test mode for RCS VoLTE single registration.");
606         pw.println("  src set-device-enabled true|false|null");
607         pw.println("    Sets the device config for RCS VoLTE single registration to the value.");
608         pw.println("    The value could be true, false, or null(undefined).");
609         pw.println("  src get-device-enabled");
610         pw.println("    Gets the device config for RCS VoLTE single registration.");
611         pw.println("  src set-carrier-enabled [-s SLOT_ID] true|false|null");
612         pw.println("    Sets the carrier config for RCS VoLTE single registration to the value.");
613         pw.println("    The value could be true, false, or null(undefined).");
614         pw.println("    Options are:");
615         pw.println("      -s: The SIM slot ID to set the config value for. If no option");
616         pw.println("          is specified, it will choose the default voice SIM slot.");
617         pw.println("  src get-carrier-enabled [-s SLOT_ID]");
618         pw.println("    Gets the carrier config for RCS VoLTE single registration.");
619         pw.println("    Options are:");
620         pw.println("      -s: The SIM slot ID to read the config value for. If no option");
621         pw.println("          is specified, it will choose the default voice SIM slot.");
622         pw.println("  src set-feature-validation [-s SLOT_ID] true|false|null");
623         pw.println("    Sets ims feature validation result.");
624         pw.println("    The value could be true, false, or null(undefined).");
625         pw.println("    Options are:");
626         pw.println("      -s: The SIM slot ID to set the config value for. If no option");
627         pw.println("          is specified, it will choose the default voice SIM slot.");
628         pw.println("  src get-feature-validation [-s SLOT_ID]");
629         pw.println("    Gets ims feature validation override value.");
630         pw.println("    Options are:");
631         pw.println("      -s: The SIM slot ID to read the config value for. If no option");
632         pw.println("          is specified, it will choose the default voice SIM slot.");
633     }
634 
onHelpAllowedNetworkTypes()635     private void onHelpAllowedNetworkTypes() {
636         PrintWriter pw = getOutPrintWriter();
637         pw.println("Allowed Network Types Commands:");
638         pw.println("  get-allowed-network-types-for-users [-s SLOT_ID]");
639         pw.println("    Print allowed network types value.");
640         pw.println("    Options are:");
641         pw.println("      -s: The SIM slot ID to read allowed network types value for. If no");
642         pw.println("          option is specified, it will choose the default voice SIM slot.");
643         pw.println("  set-allowed-network-types-for-users [-s SLOT_ID] [NETWORK_TYPES_BITMASK]");
644         pw.println("    Sets allowed network types to NETWORK_TYPES_BITMASK.");
645         pw.println("    Options are:");
646         pw.println("      -s: The SIM slot ID to set allowed network types value for. If no");
647         pw.println("          option is specified, it will choose the default voice SIM slot.");
648         pw.println("    NETWORK_TYPES_BITMASK specifies the new network types value and this type");
649         pw.println("      is bitmask in binary format. Reference the NetworkTypeBitMask");
650         pw.println("      at TelephonyManager.java");
651         pw.println("      For example:");
652         pw.println("        NR only                    : 10000000000000000000");
653         pw.println("        NR|LTE                     : 11000001000000000000");
654         pw.println("        NR|LTE|CDMA|EVDO|GSM|WCDMA : 11001111101111111111");
655         pw.println("        LTE|CDMA|EVDO|GSM|WCDMA    : 01001111101111111111");
656         pw.println("        LTE only                   : 01000001000000000000");
657     }
658 
handleImsCommand()659     private int handleImsCommand() {
660         String arg = getNextArg();
661         if (arg == null) {
662             onHelpIms();
663             return 0;
664         }
665 
666         switch (arg) {
667             case IMS_SET_IMS_SERVICE: {
668                 return handleImsSetServiceCommand();
669             }
670             case IMS_GET_IMS_SERVICE: {
671                 return handleImsGetServiceCommand();
672             }
673             case IMS_CLEAR_SERVICE_OVERRIDE: {
674                 return handleImsClearCarrierServiceCommand();
675             }
676             case ENABLE: {
677                 return handleEnableIms();
678             }
679             case DISABLE: {
680                 return handleDisableIms();
681             }
682             case IMS_CEP: {
683                 return handleCepChange();
684             }
685         }
686 
687         return -1;
688     }
689 
handleDataTestModeCommand()690     private int handleDataTestModeCommand() {
691         PrintWriter errPw = getErrPrintWriter();
692         String arg = getNextArgRequired();
693         if (arg == null) {
694             onHelpDataTestMode();
695             return 0;
696         }
697         switch (arg) {
698             case ENABLE: {
699                 try {
700                     mInterface.enableDataConnectivity();
701                 } catch (RemoteException ex) {
702                     Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
703                     errPw.println("Exception: " + ex.getMessage());
704                     return -1;
705                 }
706                 break;
707             }
708             case DISABLE: {
709                 try {
710                     mInterface.disableDataConnectivity();
711                 } catch (RemoteException ex) {
712                     Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
713                     errPw.println("Exception: " + ex.getMessage());
714                     return -1;
715                 }
716                 break;
717             }
718             default:
719                 onHelpDataTestMode();
720                 break;
721         }
722         return 0;
723     }
724 
handleEmergencyCallbackModeCommand()725     private int handleEmergencyCallbackModeCommand() {
726         PrintWriter errPw = getErrPrintWriter();
727         try {
728             mInterface.startEmergencyCallbackMode();
729             Log.d(LOG_TAG, "handleEmergencyCallbackModeCommand: triggered");
730         } catch (RemoteException ex) {
731             Log.w(LOG_TAG, "emergency-callback-mode error: " + ex.getMessage());
732             errPw.println("Exception: " + ex.getMessage());
733             return -1;
734         }
735         return 0;
736     }
737 
handleEmergencyNumberTestModeCommand()738     private int handleEmergencyNumberTestModeCommand() {
739         PrintWriter errPw = getErrPrintWriter();
740         String opt = getNextOption();
741         if (opt == null) {
742             onHelpEmergencyNumber();
743             return 0;
744         }
745 
746         switch (opt) {
747             case "-a": {
748                 String emergencyNumberCmd = getNextArgRequired();
749                 if (emergencyNumberCmd == null
750                         || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
751                     errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
752                             + " to be specified after -a in the command ");
753                     return -1;
754                 }
755                 try {
756                     mInterface.updateEmergencyNumberListTestMode(
757                             EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
758                             new EmergencyNumber(emergencyNumberCmd, "", "",
759                                     EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
760                                     new ArrayList<String>(),
761                                     EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
762                                     EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
763                 } catch (RemoteException ex) {
764                     Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
765                             + ", error " + ex.getMessage());
766                     errPw.println("Exception: " + ex.getMessage());
767                     return -1;
768                 }
769                 break;
770             }
771             case "-c": {
772                 try {
773                     mInterface.updateEmergencyNumberListTestMode(
774                             EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
775                 } catch (RemoteException ex) {
776                     Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
777                     errPw.println("Exception: " + ex.getMessage());
778                     return -1;
779                 }
780                 break;
781             }
782             case "-r": {
783                 String emergencyNumberCmd = getNextArgRequired();
784                 if (emergencyNumberCmd == null
785                         || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
786                     errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
787                             + " to be specified after -r in the command ");
788                     return -1;
789                 }
790                 try {
791                     mInterface.updateEmergencyNumberListTestMode(
792                             EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
793                             new EmergencyNumber(emergencyNumberCmd, "", "",
794                                     EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
795                                     new ArrayList<String>(),
796                                     EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
797                                     EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
798                 } catch (RemoteException ex) {
799                     Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
800                             + ", error " + ex.getMessage());
801                     errPw.println("Exception: " + ex.getMessage());
802                     return -1;
803                 }
804                 break;
805             }
806             case "-p": {
807                 try {
808                     getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
809                 } catch (RemoteException ex) {
810                     Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
811                     errPw.println("Exception: " + ex.getMessage());
812                     return -1;
813                 }
814                 break;
815             }
816             default:
817                 onHelpEmergencyNumber();
818                 break;
819         }
820         return 0;
821     }
822 
handleNumberVerificationCommand()823     private int handleNumberVerificationCommand() {
824         String arg = getNextArg();
825         if (arg == null) {
826             onHelpNumberVerification();
827             return 0;
828         }
829 
830         if (!checkShellUid()) {
831             return -1;
832         }
833 
834         switch (arg) {
835             case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
836                 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
837                 return 0;
838             }
839             case NUMBER_VERIFICATION_FAKE_CALL: {
840                 boolean val = NumberVerificationManager.getInstance()
841                         .checkIncomingCall(getNextArg());
842                 getOutPrintWriter().println(val ? "1" : "0");
843                 return 0;
844             }
845         }
846 
847         return -1;
848     }
849 
subIsEsim(int subId)850     private boolean subIsEsim(int subId) {
851         SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
852         if (info != null) {
853             return info.isEmbedded();
854         }
855         return false;
856     }
857 
handleEnablePhysicalSubscription(boolean enable)858     private int handleEnablePhysicalSubscription(boolean enable) {
859         PrintWriter errPw = getErrPrintWriter();
860         int subId = 0;
861         try {
862             subId = Integer.parseInt(getNextArgRequired());
863         } catch (NumberFormatException e) {
864             errPw.println((enable ? "enable" : "disable")
865                     + "-physical-subscription requires an integer as a subId.");
866             return -1;
867         }
868         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
869         // non user build.
870         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
871             errPw.println("cc: Permission denied.");
872             return -1;
873         }
874         // Verify that the subId represents a physical sub
875         if (subIsEsim(subId)) {
876             errPw.println("SubId " + subId + " is not for a physical subscription");
877             return -1;
878         }
879         Log.d(LOG_TAG, (enable ? "Enabling" : "Disabling")
880                 + " physical subscription with subId=" + subId);
881         mSubscriptionManager.setUiccApplicationsEnabled(subId, enable);
882         return 0;
883     }
884 
handleThermalMitigationCommand()885     private int handleThermalMitigationCommand() {
886         String arg = getNextArg();
887         String packageName = getNextArg();
888         if (arg == null || packageName == null) {
889             onHelpThermalMitigation();
890             return 0;
891         }
892 
893         if (!checkShellUid()) {
894             return -1;
895         }
896 
897         switch (arg) {
898             case ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: {
899                 PhoneInterfaceManager.addPackageToThermalMitigationAllowlist(packageName, mContext);
900                 return 0;
901             }
902             case DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: {
903                 PhoneInterfaceManager.removePackageFromThermalMitigationAllowlist(packageName,
904                         mContext);
905                 return 0;
906             }
907             default:
908                 onHelpThermalMitigation();
909         }
910 
911         return -1;
912 
913     }
914 
handleD2dCommand()915     private int handleD2dCommand() {
916         String arg = getNextArg();
917         if (arg == null) {
918             onHelpD2D();
919             return 0;
920         }
921 
922         switch (arg) {
923             case D2D_SEND: {
924                 return handleD2dSendCommand();
925             }
926             case D2D_TRANSPORT: {
927                 return handleD2dTransportCommand();
928             }
929             case D2D_SET_DEVICE_SUPPORT: {
930                 return handleD2dDeviceSupportedCommand();
931             }
932         }
933 
934         return -1;
935     }
936 
handleD2dSendCommand()937     private int handleD2dSendCommand() {
938         PrintWriter errPw = getErrPrintWriter();
939         int messageType = -1;
940         int messageValue = -1;
941 
942         String arg = getNextArg();
943         if (arg == null) {
944             onHelpD2D();
945             return 0;
946         }
947         try {
948             messageType = Integer.parseInt(arg);
949         } catch (NumberFormatException e) {
950             errPw.println("message type must be a valid integer");
951             return -1;
952         }
953 
954         arg = getNextArg();
955         if (arg == null) {
956             onHelpD2D();
957             return 0;
958         }
959         try {
960             messageValue = Integer.parseInt(arg);
961         } catch (NumberFormatException e) {
962             errPw.println("message value must be a valid integer");
963             return -1;
964         }
965 
966         try {
967             mInterface.sendDeviceToDeviceMessage(messageType, messageValue);
968         } catch (RemoteException e) {
969             Log.w(LOG_TAG, "d2d send error: " + e.getMessage());
970             errPw.println("Exception: " + e.getMessage());
971             return -1;
972         }
973 
974         return 0;
975     }
976 
handleD2dTransportCommand()977     private int handleD2dTransportCommand() {
978         PrintWriter errPw = getErrPrintWriter();
979 
980         String arg = getNextArg();
981         if (arg == null) {
982             onHelpD2D();
983             return 0;
984         }
985 
986         try {
987             mInterface.setActiveDeviceToDeviceTransport(arg);
988         } catch (RemoteException e) {
989             Log.w(LOG_TAG, "d2d transport error: " + e.getMessage());
990             errPw.println("Exception: " + e.getMessage());
991             return -1;
992         }
993         return 0;
994     }
handleBarringCommand()995     private int handleBarringCommand() {
996         String arg = getNextArg();
997         if (arg == null) {
998             onHelpBarring();
999             return 0;
1000         }
1001 
1002         switch (arg) {
1003             case BARRING_SEND_INFO: {
1004                 return handleBarringSendCommand();
1005             }
1006         }
1007         return -1;
1008     }
1009 
handleBarringSendCommand()1010     private int handleBarringSendCommand() {
1011         PrintWriter errPw = getErrPrintWriter();
1012         int slotId = getDefaultSlot();
1013         int subId = SubscriptionManager.getSubId(slotId)[0];
1014         @BarringInfo.BarringServiceInfo.BarringType int barringType =
1015                 BarringInfo.BarringServiceInfo.BARRING_TYPE_UNCONDITIONAL;
1016         boolean isConditionallyBarred = false;
1017         int conditionalBarringTimeSeconds = 0;
1018 
1019         String opt;
1020         while ((opt = getNextOption()) != null) {
1021             switch (opt) {
1022                 case "-s": {
1023                     try {
1024                         slotId = Integer.parseInt(getNextArgRequired());
1025                         subId = SubscriptionManager.getSubId(slotId)[0];
1026                     } catch (NumberFormatException e) {
1027                         errPw.println("barring send requires an integer as a SLOT_ID.");
1028                         return -1;
1029                     }
1030                     break;
1031                 }
1032                 case "-b": {
1033                     try {
1034                         barringType = Integer.parseInt(getNextArgRequired());
1035                         if (barringType < -1 || barringType > 2) {
1036                             throw new NumberFormatException();
1037                         }
1038 
1039                     } catch (NumberFormatException e) {
1040                         errPw.println("barring send requires an integer in range [-1,2] as "
1041                                 + "a BARRING_TYPE.");
1042                         return -1;
1043                     }
1044                     break;
1045                 }
1046                 case "-c": {
1047                     try {
1048                         isConditionallyBarred = Boolean.parseBoolean(getNextArgRequired());
1049                     } catch (Exception e) {
1050                         errPw.println("barring send requires a boolean after -c indicating"
1051                                 + " conditional barring");
1052                         return -1;
1053                     }
1054                     break;
1055                 }
1056                 case "-t": {
1057                     try {
1058                         conditionalBarringTimeSeconds = Integer.parseInt(getNextArgRequired());
1059                     } catch (NumberFormatException e) {
1060                         errPw.println("barring send requires an integer for time of barring"
1061                                 + " in seconds after -t for conditional barring");
1062                         return -1;
1063                     }
1064                     break;
1065                 }
1066             }
1067         }
1068         SparseArray<BarringInfo.BarringServiceInfo> barringServiceInfos = new SparseArray<>();
1069         BarringInfo.BarringServiceInfo bsi = new BarringInfo.BarringServiceInfo(
1070                 barringType, isConditionallyBarred, 0, conditionalBarringTimeSeconds);
1071         barringServiceInfos.append(0, bsi);
1072         BarringInfo barringInfo = new BarringInfo(null, barringServiceInfos);
1073         try {
1074             mTelephonyRegistryManager.notifyBarringInfoChanged(slotId, subId, barringInfo);
1075         } catch (Exception e) {
1076             Log.w(LOG_TAG, "barring send error: " + e.getMessage());
1077             errPw.println("Exception: " + e.getMessage());
1078             return -1;
1079         }
1080         return 0;
1081     }
1082 
handleD2dDeviceSupportedCommand()1083     private int handleD2dDeviceSupportedCommand() {
1084         PrintWriter errPw = getErrPrintWriter();
1085 
1086         String arg = getNextArg();
1087         if (arg == null) {
1088             onHelpD2D();
1089             return 0;
1090         }
1091 
1092         boolean isEnabled = "true".equals(arg.toLowerCase());
1093         try {
1094             mInterface.setDeviceToDeviceForceEnabled(isEnabled);
1095         } catch (RemoteException e) {
1096             Log.w(LOG_TAG, "Error forcing D2D enabled: " + e.getMessage());
1097             errPw.println("Exception: " + e.getMessage());
1098             return -1;
1099         }
1100         return 0;
1101     }
1102 
1103     // ims set-ims-service
handleImsSetServiceCommand()1104     private int handleImsSetServiceCommand() {
1105         PrintWriter errPw = getErrPrintWriter();
1106         int slotId = getDefaultSlot();
1107         Boolean isCarrierService = null;
1108         List<Integer> featuresList = new ArrayList<>();
1109 
1110         String opt;
1111         while ((opt = getNextOption()) != null) {
1112             switch (opt) {
1113                 case "-s": {
1114                     try {
1115                         slotId = Integer.parseInt(getNextArgRequired());
1116                     } catch (NumberFormatException e) {
1117                         errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
1118                         return -1;
1119                     }
1120                     break;
1121                 }
1122                 case "-c": {
1123                     isCarrierService = true;
1124                     break;
1125                 }
1126                 case "-d": {
1127                     isCarrierService = false;
1128                     break;
1129                 }
1130                 case "-f": {
1131                     String featureString = getNextArgRequired();
1132                     String[] features = featureString.split(",");
1133                     for (int i = 0; i < features.length; i++) {
1134                         try {
1135                             Integer result = Integer.parseInt(features[i]);
1136                             if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
1137                                     || result >= ImsFeature.FEATURE_MAX) {
1138                                 errPw.println("ims set-ims-service -f " + result
1139                                         + " is an invalid feature.");
1140                                 return -1;
1141                             }
1142                             featuresList.add(result);
1143                         } catch (NumberFormatException e) {
1144                             errPw.println("ims set-ims-service -f tried to parse " + features[i]
1145                                             + " as an integer.");
1146                             return -1;
1147                         }
1148                     }
1149                 }
1150             }
1151         }
1152         // Mandatory param, either -c or -d
1153         if (isCarrierService == null) {
1154             errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
1155             return -1;
1156         }
1157 
1158         String packageName = getNextArg();
1159 
1160         try {
1161             if (packageName == null) {
1162                 packageName = "";
1163             }
1164             int[] featureArray = new int[featuresList.size()];
1165             for (int i = 0; i < featuresList.size(); i++) {
1166                 featureArray[i] = featuresList.get(i);
1167             }
1168             boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
1169                     featureArray, packageName);
1170             if (VDBG) {
1171                 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
1172                         + (isCarrierService ? "-c " : "-d ")
1173                         + "-f " + featuresList + " "
1174                         + packageName + ", result=" + result);
1175             }
1176             getOutPrintWriter().println(result);
1177         } catch (RemoteException e) {
1178             Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
1179                     + (isCarrierService ? "-c " : "-d ")
1180                     + "-f " + featuresList + " "
1181                     + packageName + ", error" + e.getMessage());
1182             errPw.println("Exception: " + e.getMessage());
1183             return -1;
1184         }
1185         return 0;
1186     }
1187 
1188     // ims clear-ims-service-override
handleImsClearCarrierServiceCommand()1189     private int handleImsClearCarrierServiceCommand() {
1190         PrintWriter errPw = getErrPrintWriter();
1191         int slotId = getDefaultSlot();
1192 
1193         String opt;
1194         while ((opt = getNextOption()) != null) {
1195             switch (opt) {
1196                 case "-s": {
1197                     try {
1198                         slotId = Integer.parseInt(getNextArgRequired());
1199                     } catch (NumberFormatException e) {
1200                         errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
1201                         return -1;
1202                     }
1203                     break;
1204                 }
1205             }
1206         }
1207 
1208         try {
1209             boolean result = mInterface.clearCarrierImsServiceOverride(slotId);
1210             if (VDBG) {
1211                 Log.v(LOG_TAG, "ims clear-ims-service-override -s " + slotId
1212                         + ", result=" + result);
1213             }
1214             getOutPrintWriter().println(result);
1215         } catch (RemoteException e) {
1216             Log.w(LOG_TAG, "ims clear-ims-service-override -s " + slotId
1217                     + ", error" + e.getMessage());
1218             errPw.println("Exception: " + e.getMessage());
1219             return -1;
1220         }
1221         return 0;
1222     }
1223 
1224     // ims get-ims-service
handleImsGetServiceCommand()1225     private int handleImsGetServiceCommand() {
1226         PrintWriter errPw = getErrPrintWriter();
1227         int slotId = getDefaultSlot();
1228         Boolean isCarrierService = null;
1229         Integer featureType = ImsFeature.FEATURE_MMTEL;
1230 
1231         String opt;
1232         while ((opt = getNextOption()) != null) {
1233             switch (opt) {
1234                 case "-s": {
1235                     try {
1236                         slotId = Integer.parseInt(getNextArgRequired());
1237                     } catch (NumberFormatException e) {
1238                         errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
1239                         return -1;
1240                     }
1241                     break;
1242                 }
1243                 case "-c": {
1244                     isCarrierService = true;
1245                     break;
1246                 }
1247                 case "-d": {
1248                     isCarrierService = false;
1249                     break;
1250                 }
1251                 case "-f": {
1252                     try {
1253                         featureType = Integer.parseInt(getNextArg());
1254                     } catch (NumberFormatException e) {
1255                         errPw.println("ims get-ims-service -f requires valid integer as feature.");
1256                         return -1;
1257                     }
1258                     if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
1259                             || featureType >= ImsFeature.FEATURE_MAX) {
1260                         errPw.println("ims get-ims-service -f invalid feature.");
1261                         return -1;
1262                     }
1263                 }
1264             }
1265         }
1266         // Mandatory param, either -c or -d
1267         if (isCarrierService == null) {
1268             errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
1269             return -1;
1270         }
1271 
1272         String result;
1273         try {
1274             result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
1275         } catch (RemoteException e) {
1276             return -1;
1277         }
1278         if (VDBG) {
1279             Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
1280                     + (isCarrierService ? "-c " : "-d ")
1281                     + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
1282                     + result);
1283         }
1284         getOutPrintWriter().println(result);
1285         return 0;
1286     }
1287 
handleEnableIms()1288     private int handleEnableIms() {
1289         int slotId = getDefaultSlot();
1290         String opt;
1291         while ((opt = getNextOption()) != null) {
1292             switch (opt) {
1293                 case "-s": {
1294                     try {
1295                         slotId = Integer.parseInt(getNextArgRequired());
1296                     } catch (NumberFormatException e) {
1297                         getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
1298                         return -1;
1299                     }
1300                     break;
1301                 }
1302             }
1303         }
1304         try {
1305             mInterface.enableIms(slotId);
1306         } catch (RemoteException e) {
1307             return -1;
1308         }
1309         if (VDBG) {
1310             Log.v(LOG_TAG, "ims enable -s " + slotId);
1311         }
1312         return 0;
1313     }
1314 
handleDisableIms()1315     private int handleDisableIms() {
1316         int slotId = getDefaultSlot();
1317         String opt;
1318         while ((opt = getNextOption()) != null) {
1319             switch (opt) {
1320                 case "-s": {
1321                     try {
1322                         slotId = Integer.parseInt(getNextArgRequired());
1323                     } catch (NumberFormatException e) {
1324                         getErrPrintWriter().println(
1325                                 "ims disable requires an integer as a SLOT_ID.");
1326                         return -1;
1327                     }
1328                     break;
1329                 }
1330             }
1331         }
1332         try {
1333             mInterface.disableIms(slotId);
1334         } catch (RemoteException e) {
1335             return -1;
1336         }
1337         if (VDBG) {
1338             Log.v(LOG_TAG, "ims disable -s " + slotId);
1339         }
1340         return 0;
1341     }
1342 
handleCepChange()1343     private int handleCepChange() {
1344         Log.i(LOG_TAG, "handleCepChange");
1345         String opt = getNextArg();
1346         if (opt == null) {
1347             return -1;
1348         }
1349         boolean isCepEnabled = opt.equals("enable");
1350 
1351         try {
1352             mInterface.setCepEnabled(isCepEnabled);
1353         } catch (RemoteException e) {
1354             return -1;
1355         }
1356         return 0;
1357     }
1358 
getDefaultSlot()1359     private int getDefaultSlot() {
1360         int slotId = SubscriptionManager.getDefaultVoicePhoneId();
1361         if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
1362                 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
1363             // If there is no default, default to slot 0.
1364             slotId = DEFAULT_PHONE_ID;
1365         }
1366         return slotId;
1367     }
1368 
1369     // Parse options related to Carrier Config Commands.
parseCcOptions(String tag, boolean allowOptionPersistent)1370     private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
1371         PrintWriter errPw = getErrPrintWriter();
1372         CcOptionParseResult result = new CcOptionParseResult();
1373         result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
1374         result.mPersistent = false;
1375 
1376         String opt;
1377         while ((opt = getNextOption()) != null) {
1378             switch (opt) {
1379                 case "-s": {
1380                     try {
1381                         result.mSubId = slotStringToSubId(tag, getNextArgRequired());
1382                         if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
1383                             errPw.println(tag + "No valid subscription found.");
1384                             return null;
1385                         }
1386 
1387                     } catch (IllegalArgumentException e) {
1388                         // Missing slot id
1389                         errPw.println(tag + "SLOT_ID expected after -s.");
1390                         return null;
1391                     }
1392                     break;
1393                 }
1394                 case "-p": {
1395                     if (allowOptionPersistent) {
1396                         result.mPersistent = true;
1397                     } else {
1398                         errPw.println(tag + "Unexpected option " + opt);
1399                         return null;
1400                     }
1401                     break;
1402                 }
1403                 default: {
1404                     errPw.println(tag + "Unknown option " + opt);
1405                     return null;
1406                 }
1407             }
1408         }
1409         return result;
1410     }
1411 
slotStringToSubId(String tag, String slotString)1412     private int slotStringToSubId(String tag, String slotString) {
1413         int slotId = -1;
1414         try {
1415             slotId = Integer.parseInt(slotString);
1416         } catch (NumberFormatException e) {
1417             getErrPrintWriter().println(tag + slotString + " is not a valid number for SLOT_ID.");
1418             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1419         }
1420 
1421         if (!SubscriptionManager.isValidPhoneId(slotId)) {
1422             getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
1423             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1424         }
1425 
1426         Phone phone = PhoneFactory.getPhone(slotId);
1427         if (phone == null) {
1428             getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
1429             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1430         }
1431         return phone.getSubId();
1432     }
1433 
checkShellUid()1434     private boolean checkShellUid() {
1435         // adb can run as root or as shell, depending on whether the device is rooted.
1436         return Binder.getCallingUid() == Process.SHELL_UID
1437                 || Binder.getCallingUid() == Process.ROOT_UID;
1438     }
1439 
handleCcCommand()1440     private int handleCcCommand() {
1441         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
1442         // non user build.
1443         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
1444             getErrPrintWriter().println("cc: Permission denied.");
1445             return -1;
1446         }
1447 
1448         String arg = getNextArg();
1449         if (arg == null) {
1450             onHelpCc();
1451             return 0;
1452         }
1453 
1454         switch (arg) {
1455             case CC_GET_VALUE: {
1456                 return handleCcGetValue();
1457             }
1458             case CC_SET_VALUE: {
1459                 return handleCcSetValue();
1460             }
1461             case CC_CLEAR_VALUES: {
1462                 return handleCcClearValues();
1463             }
1464             default: {
1465                 getErrPrintWriter().println("cc: Unknown argument: " + arg);
1466             }
1467         }
1468         return -1;
1469     }
1470 
1471     // cc get-value
handleCcGetValue()1472     private int handleCcGetValue() {
1473         PrintWriter errPw = getErrPrintWriter();
1474         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
1475         String key = null;
1476 
1477         // Parse all options
1478         CcOptionParseResult options =  parseCcOptions(tag, false);
1479         if (options == null) {
1480             return -1;
1481         }
1482 
1483         // Get bundle containing all carrier configuration values.
1484         PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
1485         if (bundle == null) {
1486             errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
1487             return -1;
1488         }
1489 
1490         // Get the key.
1491         key = getNextArg();
1492         if (key != null) {
1493             // A key was provided. Verify if it is a valid key
1494             if (!bundle.containsKey(key)) {
1495                 errPw.println(tag + key + " is not a valid key.");
1496                 return -1;
1497             }
1498 
1499             // Print the carrier config value for key.
1500             getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
1501         } else {
1502             // No key provided. Show all values.
1503             // Iterate over a sorted list of all carrier config keys and print them.
1504             TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
1505             for (String k : sortedSet) {
1506                 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
1507             }
1508         }
1509         return 0;
1510     }
1511 
1512     // cc set-value
handleCcSetValue()1513     private int handleCcSetValue() {
1514         PrintWriter errPw = getErrPrintWriter();
1515         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
1516 
1517         // Parse all options
1518         CcOptionParseResult options =  parseCcOptions(tag, true);
1519         if (options == null) {
1520             return -1;
1521         }
1522 
1523         // Get bundle containing all current carrier configuration values.
1524         PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
1525         if (originalValues == null) {
1526             errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
1527             return -1;
1528         }
1529 
1530         // Get the key.
1531         String key = getNextArg();
1532         if (key == null || key.equals("")) {
1533             errPw.println(tag + "KEY is missing");
1534             return -1;
1535         }
1536 
1537         // Verify if the key is valid
1538         if (!originalValues.containsKey(key)) {
1539             errPw.println(tag + key + " is not a valid key.");
1540             return -1;
1541         }
1542 
1543         // Remaining arguments is a list of new values. Add them all into an ArrayList.
1544         ArrayList<String> valueList = new ArrayList<String>();
1545         while (peekNextArg() != null) {
1546             valueList.add(getNextArg());
1547         }
1548 
1549         // Find the type of the carrier config value
1550         CcType type = getType(tag, key, originalValues);
1551         if (type == CcType.UNKNOWN) {
1552             errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
1553             return -1;
1554         }
1555 
1556         // Create an override bundle containing the key and value that should be overriden.
1557         PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
1558         if (overrideBundle == null) {
1559             return -1;
1560         }
1561 
1562         // Override the value
1563         mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
1564 
1565         // Find bundle containing all new carrier configuration values after the override.
1566         PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
1567         if (newValues == null) {
1568             errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
1569             return -1;
1570         }
1571 
1572         // Print the original and new value.
1573         String originalValueString = ccValueToString(key, type, originalValues);
1574         String newValueString = ccValueToString(key, type, newValues);
1575         getOutPrintWriter().println("Previous value: \n" + originalValueString);
1576         getOutPrintWriter().println("New value: \n" + newValueString);
1577 
1578         return 0;
1579     }
1580 
1581     // cc clear-values
handleCcClearValues()1582     private int handleCcClearValues() {
1583         PrintWriter errPw = getErrPrintWriter();
1584         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
1585 
1586         // Parse all options
1587         CcOptionParseResult options =  parseCcOptions(tag, false);
1588         if (options == null) {
1589             return -1;
1590         }
1591 
1592         // Clear all values that has previously been set.
1593         mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
1594         getOutPrintWriter()
1595                 .println("All previously set carrier config override values has been cleared");
1596         return 0;
1597     }
1598 
getType(String tag, String key, PersistableBundle bundle)1599     private CcType getType(String tag, String key, PersistableBundle bundle) {
1600         // Find the type by checking the type of the current value stored in the bundle.
1601         Object value = bundle.get(key);
1602 
1603         if (CC_TYPE_MAP.containsKey(key)) {
1604             return CC_TYPE_MAP.get(key);
1605         } else if (value != null) {
1606             if (value instanceof Boolean) {
1607                 return CcType.BOOLEAN;
1608             } else if (value instanceof Double) {
1609                 return CcType.DOUBLE;
1610             } else if (value instanceof double[]) {
1611                 return CcType.DOUBLE_ARRAY;
1612             } else if (value instanceof Integer) {
1613                 return CcType.INT;
1614             } else if (value instanceof int[]) {
1615                 return CcType.INT_ARRAY;
1616             } else if (value instanceof Long) {
1617                 return CcType.LONG;
1618             } else if (value instanceof long[]) {
1619                 return CcType.LONG_ARRAY;
1620             } else if (value instanceof String) {
1621                 return CcType.STRING;
1622             } else if (value instanceof String[]) {
1623                 return CcType.STRING_ARRAY;
1624             }
1625         } else {
1626             // Current value was null and can therefore not be used in order to find the type.
1627             // Check the name of the key to infer the type. This check is not needed for primitive
1628             // data types (boolean, double, int and long), since they can not be null.
1629             if (key.endsWith("double_array")) {
1630                 return CcType.DOUBLE_ARRAY;
1631             }
1632             if (key.endsWith("int_array")) {
1633                 return CcType.INT_ARRAY;
1634             }
1635             if (key.endsWith("long_array")) {
1636                 return CcType.LONG_ARRAY;
1637             }
1638             if (key.endsWith("string")) {
1639                 return CcType.STRING;
1640             }
1641             if (key.endsWith("string_array") || key.endsWith("strings")) {
1642                 return CcType.STRING_ARRAY;
1643             }
1644         }
1645 
1646         // Not possible to infer the type by looking at the current value or the key.
1647         PrintWriter errPw = getErrPrintWriter();
1648         errPw.println(tag + "ERROR: " + key + " has unknown type.");
1649         return CcType.UNKNOWN;
1650     }
1651 
ccValueToString(String key, CcType type, PersistableBundle bundle)1652     private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
1653         String result;
1654         StringBuilder valueString = new StringBuilder();
1655         String typeString = type.toString();
1656         Object value = bundle.get(key);
1657 
1658         if (value == null) {
1659             valueString.append("null");
1660         } else {
1661             switch (type) {
1662                 case DOUBLE_ARRAY: {
1663                     // Format the string representation of the int array as value1 value2......
1664                     double[] valueArray = (double[]) value;
1665                     for (int i = 0; i < valueArray.length; i++) {
1666                         if (i != 0) {
1667                             valueString.append(" ");
1668                         }
1669                         valueString.append(valueArray[i]);
1670                     }
1671                     break;
1672                 }
1673                 case INT_ARRAY: {
1674                     // Format the string representation of the int array as value1 value2......
1675                     int[] valueArray = (int[]) value;
1676                     for (int i = 0; i < valueArray.length; i++) {
1677                         if (i != 0) {
1678                             valueString.append(" ");
1679                         }
1680                         valueString.append(valueArray[i]);
1681                     }
1682                     break;
1683                 }
1684                 case LONG_ARRAY: {
1685                     // Format the string representation of the int array as value1 value2......
1686                     long[] valueArray = (long[]) value;
1687                     for (int i = 0; i < valueArray.length; i++) {
1688                         if (i != 0) {
1689                             valueString.append(" ");
1690                         }
1691                         valueString.append(valueArray[i]);
1692                     }
1693                     break;
1694                 }
1695                 case STRING: {
1696                     valueString.append("\"" + value.toString() + "\"");
1697                     break;
1698                 }
1699                 case STRING_ARRAY: {
1700                     // Format the string representation of the string array as "value1" "value2"....
1701                     String[] valueArray = (String[]) value;
1702                     for (int i = 0; i < valueArray.length; i++) {
1703                         if (i != 0) {
1704                             valueString.append(" ");
1705                         }
1706                         if (valueArray[i] != null) {
1707                             valueString.append("\"" + valueArray[i] + "\"");
1708                         } else {
1709                             valueString.append("null");
1710                         }
1711                     }
1712                     break;
1713                 }
1714                 default: {
1715                     valueString.append(value.toString());
1716                 }
1717             }
1718         }
1719         return String.format("%-70s %-15s %s", key, typeString, valueString);
1720     }
1721 
getOverrideBundle(String tag, CcType type, String key, ArrayList<String> valueList)1722     private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
1723             ArrayList<String> valueList) {
1724         PrintWriter errPw = getErrPrintWriter();
1725         PersistableBundle bundle = new PersistableBundle();
1726 
1727         // First verify that a valid number of values has been provided for the type.
1728         switch (type) {
1729             case BOOLEAN:
1730             case DOUBLE:
1731             case INT:
1732             case LONG: {
1733                 if (valueList.size() != 1) {
1734                     errPw.println(tag + "Expected 1 value for type " + type
1735                             + ". Found: " + valueList.size());
1736                     return null;
1737                 }
1738                 break;
1739             }
1740             case STRING: {
1741                 if (valueList.size() > 1) {
1742                     errPw.println(tag + "Expected 0 or 1 values for type " + type
1743                             + ". Found: " + valueList.size());
1744                     return null;
1745                 }
1746                 break;
1747             }
1748         }
1749 
1750         // Parse the value according to type and add it to the Bundle.
1751         switch (type) {
1752             case BOOLEAN: {
1753                 if ("true".equalsIgnoreCase(valueList.get(0))) {
1754                     bundle.putBoolean(key, true);
1755                 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
1756                     bundle.putBoolean(key, false);
1757                 } else {
1758                     errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1759                     return null;
1760                 }
1761                 break;
1762             }
1763             case DOUBLE: {
1764                 try {
1765                     bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
1766                 } catch (NumberFormatException nfe) {
1767                     // Not a valid double
1768                     errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1769                     return null;
1770                 }
1771                 break;
1772             }
1773             case DOUBLE_ARRAY: {
1774                 double[] valueDoubleArray = null;
1775                 if (valueList.size() > 0) {
1776                     valueDoubleArray = new double[valueList.size()];
1777                     for (int i = 0; i < valueList.size(); i++) {
1778                         try {
1779                             valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
1780                         } catch (NumberFormatException nfe) {
1781                             // Not a valid double
1782                             errPw.println(
1783                                     tag + "Unable to parse " + valueList.get(i) + " as a double.");
1784                             return null;
1785                         }
1786                     }
1787                 }
1788                 bundle.putDoubleArray(key, valueDoubleArray);
1789                 break;
1790             }
1791             case INT: {
1792                 try {
1793                     bundle.putInt(key, Integer.parseInt(valueList.get(0)));
1794                 } catch (NumberFormatException nfe) {
1795                     // Not a valid integer
1796                     errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
1797                     return null;
1798                 }
1799                 break;
1800             }
1801             case INT_ARRAY: {
1802                 int[] valueIntArray = null;
1803                 if (valueList.size() > 0) {
1804                     valueIntArray = new int[valueList.size()];
1805                     for (int i = 0; i < valueList.size(); i++) {
1806                         try {
1807                             valueIntArray[i] = Integer.parseInt(valueList.get(i));
1808                         } catch (NumberFormatException nfe) {
1809                             // Not a valid integer
1810                             errPw.println(tag
1811                                     + "Unable to parse " + valueList.get(i) + " as an integer.");
1812                             return null;
1813                         }
1814                     }
1815                 }
1816                 bundle.putIntArray(key, valueIntArray);
1817                 break;
1818             }
1819             case LONG: {
1820                 try {
1821                     bundle.putLong(key, Long.parseLong(valueList.get(0)));
1822                 } catch (NumberFormatException nfe) {
1823                     // Not a valid long
1824                     errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1825                     return null;
1826                 }
1827                 break;
1828             }
1829             case LONG_ARRAY: {
1830                 long[] valueLongArray = null;
1831                 if (valueList.size() > 0) {
1832                     valueLongArray = new long[valueList.size()];
1833                     for (int i = 0; i < valueList.size(); i++) {
1834                         try {
1835                             valueLongArray[i] = Long.parseLong(valueList.get(i));
1836                         } catch (NumberFormatException nfe) {
1837                             // Not a valid long
1838                             errPw.println(
1839                                     tag + "Unable to parse " + valueList.get(i) + " as a long");
1840                             return null;
1841                         }
1842                     }
1843                 }
1844                 bundle.putLongArray(key, valueLongArray);
1845                 break;
1846             }
1847             case STRING: {
1848                 String value = null;
1849                 if (valueList.size() > 0) {
1850                     value = valueList.get(0);
1851                 }
1852                 bundle.putString(key, value);
1853                 break;
1854             }
1855             case STRING_ARRAY: {
1856                 String[] valueStringArray = null;
1857                 if (valueList.size() > 0) {
1858                     valueStringArray = new String[valueList.size()];
1859                     valueList.toArray(valueStringArray);
1860                 }
1861                 bundle.putStringArray(key, valueStringArray);
1862                 break;
1863             }
1864         }
1865         return bundle;
1866     }
1867 
handleEndBlockSuppressionCommand()1868     private int handleEndBlockSuppressionCommand() {
1869         if (!checkShellUid()) {
1870             return -1;
1871         }
1872 
1873         if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) {
1874             BlockedNumberContract.SystemContract.endBlockSuppression(mContext);
1875         }
1876         return 0;
1877     }
1878 
handleRestartModemCommand()1879     private int handleRestartModemCommand() {
1880         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
1881         // non user build.
1882         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
1883             getErrPrintWriter().println("RestartModem: Permission denied.");
1884             return -1;
1885         }
1886 
1887         boolean result = TelephonyManager.getDefault().rebootRadio();
1888         getOutPrintWriter().println(result);
1889 
1890         return result ? 0 : -1;
1891     }
1892 
handleUnattendedReboot()1893     private int handleUnattendedReboot() {
1894         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
1895         // non user build.
1896         if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
1897             getErrPrintWriter().println("UnattendedReboot: Permission denied.");
1898             return -1;
1899         }
1900 
1901         int result = TelephonyManager.getDefault().prepareForUnattendedReboot();
1902         getOutPrintWriter().println("result: " + result);
1903 
1904         return result != TelephonyManager.PREPARE_UNATTENDED_REBOOT_ERROR ? 0 : -1;
1905     }
1906 
handleGbaCommand()1907     private int handleGbaCommand() {
1908         String arg = getNextArg();
1909         if (arg == null) {
1910             onHelpGba();
1911             return 0;
1912         }
1913 
1914         switch (arg) {
1915             case GBA_SET_SERVICE: {
1916                 return handleGbaSetServiceCommand();
1917             }
1918             case GBA_GET_SERVICE: {
1919                 return handleGbaGetServiceCommand();
1920             }
1921             case GBA_SET_RELEASE_TIME: {
1922                 return handleGbaSetReleaseCommand();
1923             }
1924             case GBA_GET_RELEASE_TIME: {
1925                 return handleGbaGetReleaseCommand();
1926             }
1927         }
1928 
1929         return -1;
1930     }
1931 
getSubId(String cmd)1932     private int getSubId(String cmd) {
1933         int slotId = getDefaultSlot();
1934         String opt = getNextOption();
1935         if (opt != null && opt.equals("-s")) {
1936             try {
1937                 slotId = Integer.parseInt(getNextArgRequired());
1938             } catch (NumberFormatException e) {
1939                 getErrPrintWriter().println(cmd + " requires an integer as a SLOT_ID.");
1940                 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1941             }
1942         }
1943         int[] subIds = SubscriptionManager.getSubId(slotId);
1944         return subIds[0];
1945     }
1946 
handleGbaSetServiceCommand()1947     private int handleGbaSetServiceCommand() {
1948         int subId = getSubId("gba set-service");
1949         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1950             return -1;
1951         }
1952 
1953         String packageName = getNextArg();
1954         try {
1955             if (packageName == null) {
1956                 packageName = "";
1957             }
1958             boolean result = mInterface.setBoundGbaServiceOverride(subId, packageName);
1959             if (VDBG) {
1960                 Log.v(LOG_TAG, "gba set-service -s " + subId + " "
1961                         + packageName + ", result=" + result);
1962             }
1963             getOutPrintWriter().println(result);
1964         } catch (RemoteException e) {
1965             Log.w(LOG_TAG, "gba set-service " + subId + " "
1966                     + packageName + ", error" + e.getMessage());
1967             getErrPrintWriter().println("Exception: " + e.getMessage());
1968             return -1;
1969         }
1970         return 0;
1971     }
1972 
handleGbaGetServiceCommand()1973     private int handleGbaGetServiceCommand() {
1974         String result;
1975 
1976         int subId = getSubId("gba get-service");
1977         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1978             return -1;
1979         }
1980 
1981         try {
1982             result = mInterface.getBoundGbaService(subId);
1983         } catch (RemoteException e) {
1984             return -1;
1985         }
1986         if (VDBG) {
1987             Log.v(LOG_TAG, "gba get-service -s " + subId + ", returned: " + result);
1988         }
1989         getOutPrintWriter().println(result);
1990         return 0;
1991     }
1992 
handleGbaSetReleaseCommand()1993     private int handleGbaSetReleaseCommand() {
1994         //the release time value could be -1
1995         int subId = getRemainingArgsCount() > 1 ? getSubId("gba set-release")
1996                 : SubscriptionManager.getDefaultSubscriptionId();
1997         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1998             return -1;
1999         }
2000 
2001         String intervalStr = getNextArg();
2002         if (intervalStr == null) {
2003             return -1;
2004         }
2005 
2006         try {
2007             int interval = Integer.parseInt(intervalStr);
2008             boolean result = mInterface.setGbaReleaseTimeOverride(subId, interval);
2009             if (VDBG) {
2010                 Log.v(LOG_TAG, "gba set-release -s " + subId + " "
2011                         + intervalStr + ", result=" + result);
2012             }
2013             getOutPrintWriter().println(result);
2014         } catch (NumberFormatException | RemoteException e) {
2015             Log.w(LOG_TAG, "gba set-release -s " + subId + " "
2016                     + intervalStr + ", error" + e.getMessage());
2017             getErrPrintWriter().println("Exception: " + e.getMessage());
2018             return -1;
2019         }
2020         return 0;
2021     }
2022 
handleGbaGetReleaseCommand()2023     private int handleGbaGetReleaseCommand() {
2024         int subId = getSubId("gba get-release");
2025         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2026             return -1;
2027         }
2028 
2029         int result = 0;
2030         try {
2031             result = mInterface.getGbaReleaseTime(subId);
2032         } catch (RemoteException e) {
2033             return -1;
2034         }
2035         if (VDBG) {
2036             Log.v(LOG_TAG, "gba get-release -s " + subId + ", returned: " + result);
2037         }
2038         getOutPrintWriter().println(result);
2039         return 0;
2040     }
2041 
handleSingleRegistrationConfigCommand()2042     private int handleSingleRegistrationConfigCommand() {
2043         String arg = getNextArg();
2044         if (arg == null) {
2045             onHelpSrc();
2046             return 0;
2047         }
2048 
2049         switch (arg) {
2050             case SRC_SET_TEST_ENABLED: {
2051                 return handleSrcSetTestEnabledCommand();
2052             }
2053             case SRC_GET_TEST_ENABLED: {
2054                 return handleSrcGetTestEnabledCommand();
2055             }
2056             case SRC_SET_DEVICE_ENABLED: {
2057                 return handleSrcSetDeviceEnabledCommand();
2058             }
2059             case SRC_GET_DEVICE_ENABLED: {
2060                 return handleSrcGetDeviceEnabledCommand();
2061             }
2062             case SRC_SET_CARRIER_ENABLED: {
2063                 return handleSrcSetCarrierEnabledCommand();
2064             }
2065             case SRC_GET_CARRIER_ENABLED: {
2066                 return handleSrcGetCarrierEnabledCommand();
2067             }
2068             case SRC_SET_FEATURE_ENABLED: {
2069                 return handleSrcSetFeatureValidationCommand();
2070             }
2071             case SRC_GET_FEATURE_ENABLED: {
2072                 return handleSrcGetFeatureValidationCommand();
2073             }
2074         }
2075 
2076         return -1;
2077     }
2078 
handleRcsUceCommand()2079     private int handleRcsUceCommand() {
2080         String arg = getNextArg();
2081         if (arg == null) {
2082             onHelpUce();
2083             return 0;
2084         }
2085 
2086         switch (arg) {
2087             case UCE_REMOVE_EAB_CONTACT:
2088                 return handleRemovingEabContactCommand();
2089             case UCE_GET_EAB_CONTACT:
2090                 return handleGettingEabContactCommand();
2091             case UCE_GET_EAB_CAPABILITY:
2092                 return handleGettingEabCapabilityCommand();
2093             case UCE_GET_DEVICE_ENABLED:
2094                 return handleUceGetDeviceEnabledCommand();
2095             case UCE_SET_DEVICE_ENABLED:
2096                 return handleUceSetDeviceEnabledCommand();
2097             case UCE_OVERRIDE_PUBLISH_CAPS:
2098                 return handleUceOverridePublishCaps();
2099             case UCE_GET_LAST_PIDF_XML:
2100                 return handleUceGetPidfXml();
2101             case UCE_REMOVE_REQUEST_DISALLOWED_STATUS:
2102                 return handleUceRemoveRequestDisallowedStatus();
2103             case UCE_SET_CAPABILITY_REQUEST_TIMEOUT:
2104                 return handleUceSetCapRequestTimeout();
2105         }
2106         return -1;
2107     }
2108 
handleRemovingEabContactCommand()2109     private int handleRemovingEabContactCommand() {
2110         int subId = getSubId("uce remove-eab-contact");
2111         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2112             return -1;
2113         }
2114 
2115         String phoneNumber = getNextArgRequired();
2116         if (TextUtils.isEmpty(phoneNumber)) {
2117             return -1;
2118         }
2119         int result = 0;
2120         try {
2121             result = mInterface.removeContactFromEab(subId, phoneNumber);
2122         } catch (RemoteException e) {
2123             Log.w(LOG_TAG, "uce remove-eab-contact -s " + subId + ", error " + e.getMessage());
2124             getErrPrintWriter().println("Exception: " + e.getMessage());
2125             return -1;
2126         }
2127 
2128         if (VDBG) {
2129             Log.v(LOG_TAG, "uce remove-eab-contact -s " + subId + ", result: " + result);
2130         }
2131         return 0;
2132     }
2133 
handleGettingEabContactCommand()2134     private int handleGettingEabContactCommand() {
2135         String phoneNumber = getNextArgRequired();
2136         if (TextUtils.isEmpty(phoneNumber)) {
2137             return -1;
2138         }
2139         String result = "";
2140         try {
2141             result = mInterface.getContactFromEab(phoneNumber);
2142         } catch (RemoteException e) {
2143             Log.w(LOG_TAG, "uce get-eab-contact, error " + e.getMessage());
2144             getErrPrintWriter().println("Exception: " + e.getMessage());
2145             return -1;
2146         }
2147 
2148         if (VDBG) {
2149             Log.v(LOG_TAG, "uce get-eab-contact, result: " + result);
2150         }
2151         getOutPrintWriter().println(result);
2152         return 0;
2153     }
2154 
handleGettingEabCapabilityCommand()2155     private int handleGettingEabCapabilityCommand() {
2156         String phoneNumber = getNextArgRequired();
2157         if (TextUtils.isEmpty(phoneNumber)) {
2158             return -1;
2159         }
2160         String result = "";
2161         try {
2162             result = mInterface.getCapabilityFromEab(phoneNumber);
2163         } catch (RemoteException e) {
2164             Log.w(LOG_TAG, "uce get-eab-capability, error " + e.getMessage());
2165             getErrPrintWriter().println("Exception: " + e.getMessage());
2166             return -1;
2167         }
2168 
2169         if (VDBG) {
2170             Log.v(LOG_TAG, "uce get-eab-capability, result: " + result);
2171         }
2172         getOutPrintWriter().println(result);
2173         return 0;
2174     }
2175 
handleUceGetDeviceEnabledCommand()2176     private int handleUceGetDeviceEnabledCommand() {
2177         boolean result = false;
2178         try {
2179             result = mInterface.getDeviceUceEnabled();
2180         } catch (RemoteException e) {
2181             Log.w(LOG_TAG, "uce get-device-enabled, error " + e.getMessage());
2182             return -1;
2183         }
2184         if (VDBG) {
2185             Log.v(LOG_TAG, "uce get-device-enabled, returned: " + result);
2186         }
2187         getOutPrintWriter().println(result);
2188         return 0;
2189     }
2190 
handleUceSetDeviceEnabledCommand()2191     private int handleUceSetDeviceEnabledCommand() {
2192         String enabledStr = getNextArg();
2193         if (TextUtils.isEmpty(enabledStr)) {
2194             return -1;
2195         }
2196 
2197         try {
2198             boolean isEnabled = Boolean.parseBoolean(enabledStr);
2199             mInterface.setDeviceUceEnabled(isEnabled);
2200             if (VDBG) {
2201                 Log.v(LOG_TAG, "uce set-device-enabled " + enabledStr + ", done");
2202             }
2203         } catch (NumberFormatException | RemoteException e) {
2204             Log.w(LOG_TAG, "uce set-device-enabled " + enabledStr + ", error " + e.getMessage());
2205             getErrPrintWriter().println("Exception: " + e.getMessage());
2206             return -1;
2207         }
2208         return 0;
2209     }
2210 
handleUceRemoveRequestDisallowedStatus()2211     private int handleUceRemoveRequestDisallowedStatus() {
2212         int subId = getSubId("uce remove-request-disallowed-status");
2213         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2214             Log.w(LOG_TAG, "uce remove-request-disallowed-status, Invalid subscription ID");
2215             return -1;
2216         }
2217         boolean result;
2218         try {
2219             result = mInterface.removeUceRequestDisallowedStatus(subId);
2220         } catch (RemoteException e) {
2221             Log.w(LOG_TAG, "uce remove-request-disallowed-status, error " + e.getMessage());
2222             return -1;
2223         }
2224         if (VDBG) {
2225             Log.v(LOG_TAG, "uce remove-request-disallowed-status, returned: " + result);
2226         }
2227         getOutPrintWriter().println(result);
2228         return 0;
2229     }
2230 
handleUceSetCapRequestTimeout()2231     private int handleUceSetCapRequestTimeout() {
2232         int subId = getSubId("uce set-capabilities-request-timeout");
2233         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2234             Log.w(LOG_TAG, "uce set-capabilities-request-timeout, Invalid subscription ID");
2235             return -1;
2236         }
2237         long timeoutAfterMs = Long.valueOf(getNextArg());
2238         boolean result;
2239         try {
2240             result = mInterface.setCapabilitiesRequestTimeout(subId, timeoutAfterMs);
2241         } catch (RemoteException e) {
2242             Log.w(LOG_TAG, "uce set-capabilities-request-timeout, error " + e.getMessage());
2243             return -1;
2244         }
2245         if (VDBG) {
2246             Log.v(LOG_TAG, "uce set-capabilities-request-timeout, returned: " + result);
2247         }
2248         getOutPrintWriter().println(result);
2249         return 0;
2250     }
2251 
handleSrcSetTestEnabledCommand()2252     private int handleSrcSetTestEnabledCommand() {
2253         String enabledStr = getNextArg();
2254         if (enabledStr == null) {
2255             return -1;
2256         }
2257 
2258         try {
2259             mInterface.setRcsSingleRegistrationTestModeEnabled(Boolean.parseBoolean(enabledStr));
2260             if (VDBG) {
2261                 Log.v(LOG_TAG, "src set-test-enabled " + enabledStr + ", done");
2262             }
2263             getOutPrintWriter().println("Done");
2264         } catch (NumberFormatException | RemoteException e) {
2265             Log.w(LOG_TAG, "src set-test-enabled " + enabledStr + ", error" + e.getMessage());
2266             getErrPrintWriter().println("Exception: " + e.getMessage());
2267             return -1;
2268         }
2269         return 0;
2270     }
2271 
handleSrcGetTestEnabledCommand()2272     private int handleSrcGetTestEnabledCommand() {
2273         boolean result = false;
2274         try {
2275             result = mInterface.getRcsSingleRegistrationTestModeEnabled();
2276         } catch (RemoteException e) {
2277             return -1;
2278         }
2279         if (VDBG) {
2280             Log.v(LOG_TAG, "src get-test-enabled, returned: " + result);
2281         }
2282         getOutPrintWriter().println(result);
2283         return 0;
2284     }
2285 
handleUceOverridePublishCaps()2286     private int handleUceOverridePublishCaps() {
2287         int subId = getSubId("uce override-published-caps");
2288         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2289             return -1;
2290         }
2291         //uce override-published-caps [-s SLOT_ID] add|remove|clear|list [CAPABILITIES]
2292         String operation = getNextArgRequired();
2293         String caps = getNextArg();
2294         if (!"add".equals(operation) && !"remove".equals(operation) && !"clear".equals(operation)
2295                 && !"list".equals(operation)) {
2296             getErrPrintWriter().println("Invalid operation: " + operation);
2297             return -1;
2298         }
2299 
2300         // add/remove requires capabilities to be specified.
2301         if ((!"clear".equals(operation) && !"list".equals(operation)) && TextUtils.isEmpty(caps)) {
2302             getErrPrintWriter().println("\"" + operation + "\" requires capabilities to be "
2303                     + "specified");
2304             return -1;
2305         }
2306 
2307         ArraySet<String> capSet = new ArraySet<>();
2308         if (!TextUtils.isEmpty(caps)) {
2309             String[] capArray = caps.split(":");
2310             for (String cap : capArray) {
2311                 // Allow unknown tags to be passed in as well.
2312                 capSet.addAll(TEST_FEATURE_TAG_MAP.getOrDefault(cap, Collections.singleton(cap)));
2313             }
2314         }
2315 
2316         RcsContactUceCapability result = null;
2317         try {
2318             switch (operation) {
2319                 case "add":
2320                     result = mInterface.addUceRegistrationOverrideShell(subId,
2321                             new ArrayList<>(capSet));
2322                     break;
2323                 case "remove":
2324                     result = mInterface.removeUceRegistrationOverrideShell(subId,
2325                             new ArrayList<>(capSet));
2326                     break;
2327                 case "clear":
2328                     result = mInterface.clearUceRegistrationOverrideShell(subId);
2329                     break;
2330                 case "list":
2331                     result = mInterface.getLatestRcsContactUceCapabilityShell(subId);
2332                     break;
2333             }
2334         } catch (RemoteException e) {
2335             Log.w(LOG_TAG, "uce override-published-caps, error " + e.getMessage());
2336             getErrPrintWriter().println("Exception: " + e.getMessage());
2337             return -1;
2338         } catch (ServiceSpecificException sse) {
2339             // Reconstruct ImsException
2340             ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode);
2341             Log.w(LOG_TAG, "uce override-published-caps, error " + imsException);
2342             getErrPrintWriter().println("Exception: " + imsException);
2343             return -1;
2344         }
2345         if (result == null) {
2346             getErrPrintWriter().println("Service not available");
2347             return -1;
2348         }
2349         getOutPrintWriter().println(result);
2350         return 0;
2351     }
2352 
handleUceGetPidfXml()2353     private int handleUceGetPidfXml() {
2354         int subId = getSubId("uce get-last-publish-pidf");
2355         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2356             return -1;
2357         }
2358 
2359         String result;
2360         try {
2361             result = mInterface.getLastUcePidfXmlShell(subId);
2362         } catch (RemoteException e) {
2363             Log.w(LOG_TAG, "uce get-last-publish-pidf, error " + e.getMessage());
2364             getErrPrintWriter().println("Exception: " + e.getMessage());
2365             return -1;
2366         } catch (ServiceSpecificException sse) {
2367             // Reconstruct ImsException
2368             ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode);
2369             Log.w(LOG_TAG, "uce get-last-publish-pidf error " + imsException);
2370             getErrPrintWriter().println("Exception: " + imsException);
2371             return -1;
2372         }
2373         if (result == null) {
2374             getErrPrintWriter().println("Service not available");
2375             return -1;
2376         }
2377         getOutPrintWriter().println(result);
2378         return 0;
2379     }
2380 
handleSrcSetDeviceEnabledCommand()2381     private int handleSrcSetDeviceEnabledCommand() {
2382         String enabledStr = getNextArg();
2383         if (enabledStr == null) {
2384             return -1;
2385         }
2386 
2387         try {
2388             mInterface.setDeviceSingleRegistrationEnabledOverride(enabledStr);
2389             if (VDBG) {
2390                 Log.v(LOG_TAG, "src set-device-enabled " + enabledStr + ", done");
2391             }
2392             getOutPrintWriter().println("Done");
2393         } catch (NumberFormatException | RemoteException e) {
2394             Log.w(LOG_TAG, "src set-device-enabled " + enabledStr + ", error" + e.getMessage());
2395             getErrPrintWriter().println("Exception: " + e.getMessage());
2396             return -1;
2397         }
2398         return 0;
2399     }
2400 
handleSrcGetDeviceEnabledCommand()2401     private int handleSrcGetDeviceEnabledCommand() {
2402         boolean result = false;
2403         try {
2404             result = mInterface.getDeviceSingleRegistrationEnabled();
2405         } catch (RemoteException e) {
2406             return -1;
2407         }
2408         if (VDBG) {
2409             Log.v(LOG_TAG, "src get-device-enabled, returned: " + result);
2410         }
2411         getOutPrintWriter().println(result);
2412         return 0;
2413     }
2414 
handleSrcSetCarrierEnabledCommand()2415     private int handleSrcSetCarrierEnabledCommand() {
2416         //the release time value could be -1
2417         int subId = getRemainingArgsCount() > 1 ? getSubId("src set-carrier-enabled")
2418                 : SubscriptionManager.getDefaultSubscriptionId();
2419         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2420             return -1;
2421         }
2422 
2423         String enabledStr = getNextArg();
2424         if (enabledStr == null) {
2425             return -1;
2426         }
2427 
2428         try {
2429             boolean result =
2430                     mInterface.setCarrierSingleRegistrationEnabledOverride(subId, enabledStr);
2431             if (VDBG) {
2432                 Log.v(LOG_TAG, "src set-carrier-enabled -s " + subId + " "
2433                         + enabledStr + ", result=" + result);
2434             }
2435             getOutPrintWriter().println(result);
2436         } catch (NumberFormatException | RemoteException e) {
2437             Log.w(LOG_TAG, "src set-carrier-enabled -s " + subId + " "
2438                     + enabledStr + ", error" + e.getMessage());
2439             getErrPrintWriter().println("Exception: " + e.getMessage());
2440             return -1;
2441         }
2442         return 0;
2443     }
2444 
handleSrcGetCarrierEnabledCommand()2445     private int handleSrcGetCarrierEnabledCommand() {
2446         int subId = getSubId("src get-carrier-enabled");
2447         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2448             return -1;
2449         }
2450 
2451         boolean result = false;
2452         try {
2453             result = mInterface.getCarrierSingleRegistrationEnabled(subId);
2454         } catch (RemoteException e) {
2455             return -1;
2456         }
2457         if (VDBG) {
2458             Log.v(LOG_TAG, "src get-carrier-enabled -s " + subId + ", returned: " + result);
2459         }
2460         getOutPrintWriter().println(result);
2461         return 0;
2462     }
2463 
handleSrcSetFeatureValidationCommand()2464     private int handleSrcSetFeatureValidationCommand() {
2465         //the release time value could be -1
2466         int subId = getRemainingArgsCount() > 1 ? getSubId("src set-feature-validation")
2467                 : SubscriptionManager.getDefaultSubscriptionId();
2468         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2469             return -1;
2470         }
2471 
2472         String enabledStr = getNextArg();
2473         if (enabledStr == null) {
2474             return -1;
2475         }
2476 
2477         try {
2478             boolean result =
2479                     mInterface.setImsFeatureValidationOverride(subId, enabledStr);
2480             if (VDBG) {
2481                 Log.v(LOG_TAG, "src set-feature-validation -s " + subId + " "
2482                         + enabledStr + ", result=" + result);
2483             }
2484             getOutPrintWriter().println(result);
2485         } catch (NumberFormatException | RemoteException e) {
2486             Log.w(LOG_TAG, "src set-feature-validation -s " + subId + " "
2487                     + enabledStr + ", error" + e.getMessage());
2488             getErrPrintWriter().println("Exception: " + e.getMessage());
2489             return -1;
2490         }
2491         return 0;
2492     }
2493 
handleSrcGetFeatureValidationCommand()2494     private int handleSrcGetFeatureValidationCommand() {
2495         int subId = getSubId("src get-feature-validation");
2496         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2497             return -1;
2498         }
2499 
2500         Boolean result = false;
2501         try {
2502             result = mInterface.getImsFeatureValidationOverride(subId);
2503         } catch (RemoteException e) {
2504             return -1;
2505         }
2506         if (VDBG) {
2507             Log.v(LOG_TAG, "src get-feature-validation -s " + subId + ", returned: " + result);
2508         }
2509         getOutPrintWriter().println(result);
2510         return 0;
2511     }
2512 
2513 
onHelpCallComposer()2514     private void onHelpCallComposer() {
2515         PrintWriter pw = getOutPrintWriter();
2516         pw.println("Call composer commands");
2517         pw.println("  callcomposer test-mode enable|disable|query");
2518         pw.println("    Enables or disables test mode for call composer. In test mode, picture");
2519         pw.println("    upload/download from carrier servers is disabled, and operations are");
2520         pw.println("    performed using emulated local files instead.");
2521         pw.println("  callcomposer simulate-outgoing-call [subId] [UUID]");
2522         pw.println("    Simulates an outgoing call being placed with the picture ID as");
2523         pw.println("    the provided UUID. This triggers storage to the call log.");
2524         pw.println("  callcomposer user-setting [subId] enable|disable|query");
2525         pw.println("    Enables or disables the user setting for call composer, as set by");
2526         pw.println("    TelephonyManager#setCallComposerStatus.");
2527     }
2528 
handleCallComposerCommand()2529     private int handleCallComposerCommand() {
2530         String arg = getNextArg();
2531         if (arg == null) {
2532             onHelpCallComposer();
2533             return 0;
2534         }
2535 
2536         mContext.enforceCallingPermission(Manifest.permission.MODIFY_PHONE_STATE,
2537                 "MODIFY_PHONE_STATE required for call composer shell cmds");
2538         switch (arg) {
2539             case CALL_COMPOSER_TEST_MODE: {
2540                 String enabledStr = getNextArg();
2541                 if (ENABLE.equals(enabledStr)) {
2542                     CallComposerPictureManager.sTestMode = true;
2543                 } else if (DISABLE.equals(enabledStr)) {
2544                     CallComposerPictureManager.sTestMode = false;
2545                 } else if (QUERY.equals(enabledStr)) {
2546                     getOutPrintWriter().println(CallComposerPictureManager.sTestMode);
2547                 } else {
2548                     onHelpCallComposer();
2549                     return 1;
2550                 }
2551                 break;
2552             }
2553             case CALL_COMPOSER_SIMULATE_CALL: {
2554                 int subscriptionId = Integer.valueOf(getNextArg());
2555                 String uuidString = getNextArg();
2556                 UUID uuid = UUID.fromString(uuidString);
2557                 CompletableFuture<Uri> storageUriFuture = new CompletableFuture<>();
2558                 Binder.withCleanCallingIdentity(() -> {
2559                     CallComposerPictureManager.getInstance(mContext, subscriptionId)
2560                             .storeUploadedPictureToCallLog(uuid, storageUriFuture::complete);
2561                 });
2562                 try {
2563                     Uri uri = storageUriFuture.get();
2564                     getOutPrintWriter().println(String.valueOf(uri));
2565                 } catch (Exception e) {
2566                     throw new RuntimeException(e);
2567                 }
2568                 break;
2569             }
2570             case CALL_COMPOSER_USER_SETTING: {
2571                 try {
2572                     int subscriptionId = Integer.valueOf(getNextArg());
2573                     String enabledStr = getNextArg();
2574                     if (ENABLE.equals(enabledStr)) {
2575                         mInterface.setCallComposerStatus(subscriptionId,
2576                                 TelephonyManager.CALL_COMPOSER_STATUS_ON);
2577                     } else if (DISABLE.equals(enabledStr)) {
2578                         mInterface.setCallComposerStatus(subscriptionId,
2579                                 TelephonyManager.CALL_COMPOSER_STATUS_OFF);
2580                     } else if (QUERY.equals(enabledStr)) {
2581                         getOutPrintWriter().println(mInterface.getCallComposerStatus(subscriptionId)
2582                                 == TelephonyManager.CALL_COMPOSER_STATUS_ON);
2583                     } else {
2584                         onHelpCallComposer();
2585                         return 1;
2586                     }
2587                 } catch (RemoteException e) {
2588                     e.printStackTrace(getOutPrintWriter());
2589                     return 1;
2590                 }
2591                 break;
2592             }
2593         }
2594         return 0;
2595     }
2596 
handleHasCarrierPrivilegesCommand()2597     private int handleHasCarrierPrivilegesCommand() {
2598         String packageName = getNextArgRequired();
2599 
2600         boolean hasCarrierPrivileges;
2601         final long token = Binder.clearCallingIdentity();
2602         try {
2603             hasCarrierPrivileges =
2604                     mInterface.checkCarrierPrivilegesForPackageAnyPhone(packageName)
2605                             == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
2606         } catch (RemoteException e) {
2607             Log.w(LOG_TAG, HAS_CARRIER_PRIVILEGES_COMMAND + " exception", e);
2608             getErrPrintWriter().println("Exception: " + e.getMessage());
2609             return -1;
2610         } finally {
2611             Binder.restoreCallingIdentity(token);
2612         }
2613 
2614         getOutPrintWriter().println(hasCarrierPrivileges);
2615         return 0;
2616     }
2617 
handleAllowedNetworkTypesCommand(String command)2618     private int handleAllowedNetworkTypesCommand(String command) {
2619         if (!checkShellUid()) {
2620             return -1;
2621         }
2622 
2623         PrintWriter errPw = getErrPrintWriter();
2624         String tag = command + ": ";
2625         String opt;
2626         int subId = -1;
2627         Log.v(LOG_TAG, command + " start");
2628 
2629         while ((opt = getNextOption()) != null) {
2630             if (opt.equals("-s")) {
2631                 try {
2632                     subId = slotStringToSubId(tag, getNextArgRequired());
2633                     if (!SubscriptionManager.isValidSubscriptionId(subId)) {
2634                         errPw.println(tag + "No valid subscription found.");
2635                         return -1;
2636                     }
2637                 } catch (IllegalArgumentException e) {
2638                     // Missing slot id
2639                     errPw.println(tag + "SLOT_ID expected after -s.");
2640                     return -1;
2641                 }
2642             } else {
2643                 errPw.println(tag + "Unknown option " + opt);
2644                 return -1;
2645             }
2646         }
2647 
2648         if (GET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) {
2649             return handleGetAllowedNetworkTypesCommand(subId);
2650         }
2651         if (SET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) {
2652             return handleSetAllowedNetworkTypesCommand(subId);
2653         }
2654         return -1;
2655     }
2656 
handleGetAllowedNetworkTypesCommand(int subId)2657     private int handleGetAllowedNetworkTypesCommand(int subId) {
2658         PrintWriter errPw = getErrPrintWriter();
2659 
2660         long result = -1;
2661         try {
2662             if (mInterface != null) {
2663                 result = mInterface.getAllowedNetworkTypesForReason(subId,
2664                         TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER);
2665             } else {
2666                 throw new IllegalStateException("telephony service is null.");
2667             }
2668         } catch (RemoteException e) {
2669             Log.e(TAG, "getAllowedNetworkTypesForReason RemoteException" + e);
2670             errPw.println(GET_ALLOWED_NETWORK_TYPES_FOR_USER + "RemoteException " + e);
2671             return -1;
2672         }
2673 
2674         getOutPrintWriter().println(TelephonyManager.convertNetworkTypeBitmaskToString(result));
2675         return 0;
2676     }
2677 
handleSetAllowedNetworkTypesCommand(int subId)2678     private int handleSetAllowedNetworkTypesCommand(int subId) {
2679         PrintWriter errPw = getErrPrintWriter();
2680 
2681         String bitmaskString = getNextArg();
2682         if (TextUtils.isEmpty(bitmaskString)) {
2683             errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No NETWORK_TYPES_BITMASK");
2684             return -1;
2685         }
2686         long allowedNetworkTypes = convertNetworkTypeBitmaskFromStringToLong(bitmaskString);
2687         if (allowedNetworkTypes < 0) {
2688             errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No valid NETWORK_TYPES_BITMASK");
2689             return -1;
2690         }
2691         boolean result = false;
2692         try {
2693             if (mInterface != null) {
2694                 result = mInterface.setAllowedNetworkTypesForReason(subId,
2695                         TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, allowedNetworkTypes);
2696             } else {
2697                 throw new IllegalStateException("telephony service is null.");
2698             }
2699         } catch (RemoteException e) {
2700             Log.e(TAG, "setAllowedNetworkTypesForReason RemoteException" + e);
2701             errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " RemoteException " + e);
2702             return -1;
2703         }
2704 
2705         String resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " failed";
2706         if (result) {
2707             resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " completed";
2708         }
2709         getOutPrintWriter().println(resultMessage);
2710         return 0;
2711     }
2712 
convertNetworkTypeBitmaskFromStringToLong(String bitmaskString)2713     private long convertNetworkTypeBitmaskFromStringToLong(String bitmaskString) {
2714         if (TextUtils.isEmpty(bitmaskString)) {
2715             return -1;
2716         }
2717         if (VDBG) {
2718             Log.v(LOG_TAG, "AllowedNetworkTypes:" + bitmaskString
2719                             + ", length: " + bitmaskString.length());
2720         }
2721         try {
2722             return Long.parseLong(bitmaskString, 2);
2723         } catch (NumberFormatException e) {
2724             Log.e(LOG_TAG, "AllowedNetworkTypes: " + e);
2725             return -1;
2726         }
2727     }
2728 }
2729