/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.phone; import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_AUDIO_CODEC; import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_RADIO_ACCESS_TYPE; import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_BATTERY_STATE; import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_NETWORK_COVERAGE; import static java.util.Map.entry; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.net.Uri; import android.os.Binder; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.provider.BlockedNumberContract; import android.telephony.BarringInfo; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsException; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.feature.ImsFeature; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import com.android.ims.rcs.uce.util.FeatureTags; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.d2d.Communicator; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.util.TelephonyUtils; import com.android.modules.utils.BasicShellCommandHandler; import com.android.phone.callcomposer.CallComposerPictureManager; import com.android.phone.euicc.EuiccUiDispatcherActivity; import com.android.phone.utils.CarrierAllowListInfo; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.UUID; import java.util.concurrent.CompletableFuture; /** * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no * permission checks have been done before onCommand was called. Make sure any commands processed * here also contain the appropriate permissions checks. */ public class TelephonyShellCommand extends BasicShellCommandHandler { private static final String LOG_TAG = "TelephonyShellCommand"; // Don't commit with this true. private static final boolean VDBG = true; private static final int DEFAULT_PHONE_ID = 0; private static final String CALL_COMPOSER_SUBCOMMAND = "callcomposer"; private static final String IMS_SUBCOMMAND = "ims"; private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify"; private static final String EMERGENCY_CALLBACK_MODE = "emergency-callback-mode"; private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode"; private static final String END_BLOCK_SUPPRESSION = "end-block-suppression"; private static final String RESTART_MODEM = "restart-modem"; private static final String UNATTENDED_REBOOT = "unattended-reboot"; private static final String CARRIER_CONFIG_SUBCOMMAND = "cc"; private static final String DATA_TEST_MODE = "data"; private static final String ENABLE = "enable"; private static final String DISABLE = "disable"; private static final String QUERY = "query"; private static final String CARRIER_RESTRICTION_STATUS_TEST = "carrier_restriction_status_test"; private static final String SET_CARRIER_SERVICE_PACKAGE_OVERRIDE = "set-carrier-service-package-override"; private static final String CLEAR_CARRIER_SERVICE_PACKAGE_OVERRIDE = "clear-carrier-service-package-override"; private final String QUOTES = "\""; private static final String CALL_COMPOSER_TEST_MODE = "test-mode"; private static final String CALL_COMPOSER_SIMULATE_CALL = "simulate-outgoing-call"; private static final String CALL_COMPOSER_USER_SETTING = "user-setting"; private static final String IMS_SET_IMS_SERVICE = "set-ims-service"; private static final String IMS_GET_IMS_SERVICE = "get-ims-service"; private static final String IMS_CLEAR_SERVICE_OVERRIDE = "clear-ims-service-override"; // Used to disable or enable processing of conference event package data from the network. // This is handy for testing scenarios where CEP data does not exist on a network which does // support CEP data. private static final String IMS_CEP = "conference-event-package"; private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package"; private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call"; private static final String CC_GET_VALUE = "get-value"; private static final String CC_SET_VALUE = "set-value"; private static final String CC_SET_VALUES_FROM_XML = "set-values-from-xml"; private static final String CC_CLEAR_VALUES = "clear-values"; private static final String EUICC_SUBCOMMAND = "euicc"; private static final String EUICC_SET_UI_COMPONENT = "set-euicc-uicomponent"; private static final String GBA_SUBCOMMAND = "gba"; private static final String GBA_SET_SERVICE = "set-service"; private static final String GBA_GET_SERVICE = "get-service"; private static final String GBA_SET_RELEASE_TIME = "set-release"; private static final String GBA_GET_RELEASE_TIME = "get-release"; private static final String SINGLE_REGISTATION_CONFIG = "src"; private static final String SRC_SET_DEVICE_ENABLED = "set-device-enabled"; private static final String SRC_GET_DEVICE_ENABLED = "get-device-enabled"; private static final String SRC_SET_CARRIER_ENABLED = "set-carrier-enabled"; private static final String SRC_GET_CARRIER_ENABLED = "get-carrier-enabled"; private static final String SRC_SET_TEST_ENABLED = "set-test-enabled"; private static final String SRC_GET_TEST_ENABLED = "get-test-enabled"; private static final String SRC_SET_FEATURE_ENABLED = "set-feature-validation"; private static final String SRC_GET_FEATURE_ENABLED = "get-feature-validation"; private static final String D2D_SUBCOMMAND = "d2d"; private static final String D2D_SEND = "send"; private static final String D2D_TRANSPORT = "transport"; private static final String D2D_SET_DEVICE_SUPPORT = "set-device-support"; private static final String BARRING_SUBCOMMAND = "barring"; private static final String BARRING_SEND_INFO = "send"; private static final String RCS_UCE_COMMAND = "uce"; private static final String UCE_GET_EAB_CONTACT = "get-eab-contact"; private static final String UCE_GET_EAB_CAPABILITY = "get-eab-capability"; private static final String UCE_REMOVE_EAB_CONTACT = "remove-eab-contact"; private static final String UCE_GET_DEVICE_ENABLED = "get-device-enabled"; private static final String UCE_SET_DEVICE_ENABLED = "set-device-enabled"; private static final String UCE_OVERRIDE_PUBLISH_CAPS = "override-published-caps"; private static final String UCE_GET_LAST_PIDF_XML = "get-last-publish-pidf"; private static final String UCE_REMOVE_REQUEST_DISALLOWED_STATUS = "remove-request-disallowed-status"; private static final String UCE_SET_CAPABILITY_REQUEST_TIMEOUT = "set-capabilities-request-timeout"; private static final String RADIO_SUBCOMMAND = "radio"; private static final String RADIO_SET_MODEM_SERVICE = "set-modem-service"; private static final String RADIO_GET_MODEM_SERVICE = "get-modem-service"; // Check if a package has carrier privileges on any SIM, regardless of subId/phoneId. private static final String HAS_CARRIER_PRIVILEGES_COMMAND = "has-carrier-privileges"; private static final String DISABLE_PHYSICAL_SUBSCRIPTION = "disable-physical-subscription"; private static final String ENABLE_PHYSICAL_SUBSCRIPTION = "enable-physical-subscription"; private static final String THERMAL_MITIGATION_COMMAND = "thermal-mitigation"; private static final String ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "allow-package"; private static final String DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "disallow-package"; private static final String SET_SATELLITE_SERVICE_PACKAGE_NAME = "set-satellite-service-package-name"; private static final String SET_SATELLITE_GATEWAY_SERVICE_PACKAGE_NAME = "set-satellite-gateway-service-package-name"; private static final String SET_SATELLITE_LISTENING_TIMEOUT_DURATION = "set-satellite-listening-timeout-duration"; private static final String SET_SATELLITE_POINTING_UI_CLASS_NAME = "set-satellite-pointing-ui-class-name"; private static final String SET_DATAGRAM_CONTROLLER_TIMEOUT_DURATION = "set-datagram-controller-timeout-duration"; private static final String SET_DATAGRAM_CONTROLLER_BOOLEAN_CONFIG = "set-datagram-controller-boolean-config"; private static final String SET_SATELLITE_CONTROLLER_TIMEOUT_DURATION = "set-satellite-controller-timeout-duration"; private static final String SET_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE = "set-emergency-call-to-satellite-handover-type"; private static final String SET_COUNTRY_CODES = "set-country-codes"; private static final String SET_SATELLITE_ACCESS_CONTROL_OVERLAY_CONFIGS = "set-satellite-access-control-overlay-configs"; private static final String SET_OEM_ENABLED_SATELLITE_PROVISION_STATUS = "set-oem-enabled-satellite-provision-status"; private static final String SET_SHOULD_SEND_DATAGRAM_TO_MODEM_IN_DEMO_MODE = "set-should-send-datagram-to-modem-in-demo-mode"; private static final String SET_IS_SATELLITE_COMMUNICATION_ALLOWED_FOR_CURRENT_LOCATION_CACHE = "set-is-satellite-communication-allowed-for-current-location-cache"; private static final String DOMAIN_SELECTION_SUBCOMMAND = "domainselection"; private static final String DOMAIN_SELECTION_SET_SERVICE_OVERRIDE = "set-dss-override"; private static final String DOMAIN_SELECTION_CLEAR_SERVICE_OVERRIDE = "clear-dss-override"; private static final String INVALID_ENTRY_ERROR = "An emergency number (only allow '0'-'9', " + "'*', '#' or '+') needs to be specified after -a in the command "; private static final int[] ROUTING_TYPES = {EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN, EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY, EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL}; private static final String GET_ALLOWED_NETWORK_TYPES_FOR_USER = "get-allowed-network-types-for-users"; private static final String SET_ALLOWED_NETWORK_TYPES_FOR_USER = "set-allowed-network-types-for-users"; private static final String GET_IMEI = "get-imei"; private static final String GET_SIM_SLOTS_MAPPING = "get-sim-slots-mapping"; // Take advantage of existing methods that already contain permissions checks when possible. private final ITelephony mInterface; private SubscriptionManager mSubscriptionManager; private CarrierConfigManager mCarrierConfigManager; private TelephonyRegistryManager mTelephonyRegistryManager; private Context mContext; private enum CcType { BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING, STRING_ARRAY, PERSISTABLE_BUNDLE, UNKNOWN } private class CcOptionParseResult { public int mSubId; public boolean mPersistent; } // Maps carrier config keys to type. It is possible to infer the type for most carrier config // keys by looking at the end of the string which usually tells the type. // For instance: "xxxx_string", "xxxx_string_array", etc. // The carrier config keys in this map does not follow this convention. It is therefore not // possible to infer the type for these keys by looking at the string. private static final Map CC_TYPE_MAP = Map.ofEntries( entry(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING), entry(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING, CcType.STRING), entry(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, CcType.STRING_ARRAY), entry(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY, CcType.STRING_ARRAY), entry(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING), entry(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING), entry(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING), entry(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING), entry(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING), entry(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING), entry(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING), entry(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY)); /** * Map from a shorthand string to the feature tags required in registration required in order * for the RCS feature to be considered "capable". */ private static final Map> TEST_FEATURE_TAG_MAP; static { ArrayMap> map = new ArrayMap<>(18); map.put("chat_v1", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_IM)); map.put("chat_v2", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_SESSION)); map.put("ft", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER)); map.put("ft_sms", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS)); map.put("mmtel", Collections.singleton(FeatureTags.FEATURE_TAG_MMTEL)); map.put("mmtel_vt", new ArraySet<>(Arrays.asList(FeatureTags.FEATURE_TAG_MMTEL, FeatureTags.FEATURE_TAG_VIDEO))); map.put("geo_push", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH)); map.put("geo_push_sms", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS)); map.put("call_comp", Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING)); map.put("call_comp_mmtel", Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY)); map.put("call_post", Collections.singleton(FeatureTags.FEATURE_TAG_POST_CALL)); map.put("map", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_MAP)); map.put("sketch", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_SKETCH)); // Feature tags defined twice for chatbot session because we want v1 and v2 based on bot // version map.put("chatbot", new ArraySet<>(Arrays.asList( FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION, FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED))); map.put("chatbot_v2", new ArraySet<>(Arrays.asList( FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION, FeatureTags.FEATURE_TAG_CHATBOT_VERSION_V2_SUPPORTED))); map.put("chatbot_sa", new ArraySet<>(Arrays.asList( FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG, FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED))); map.put("chatbot_sa_v2", new ArraySet<>(Arrays.asList( FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG, FeatureTags.FEATURE_TAG_CHATBOT_VERSION_V2_SUPPORTED))); map.put("chatbot_role", Collections.singleton(FeatureTags.FEATURE_TAG_CHATBOT_ROLE)); TEST_FEATURE_TAG_MAP = Collections.unmodifiableMap(map); } public TelephonyShellCommand(ITelephony binder, Context context) { mInterface = binder; mCarrierConfigManager = (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE); mSubscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); mTelephonyRegistryManager = (TelephonyRegistryManager) context.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); mContext = context; } @Override public int onCommand(String cmd) { if (cmd == null) { return handleDefaultCommands(null); } switch (cmd) { case IMS_SUBCOMMAND: { return handleImsCommand(); } case RCS_UCE_COMMAND: return handleRcsUceCommand(); case NUMBER_VERIFICATION_SUBCOMMAND: return handleNumberVerificationCommand(); case EMERGENCY_CALLBACK_MODE: return handleEmergencyCallbackModeCommand(); case EMERGENCY_NUMBER_TEST_MODE: return handleEmergencyNumberTestModeCommand(); case CARRIER_CONFIG_SUBCOMMAND: { return handleCcCommand(); } case DATA_TEST_MODE: return handleDataTestModeCommand(); case END_BLOCK_SUPPRESSION: return handleEndBlockSuppressionCommand(); case EUICC_SUBCOMMAND: return handleEuiccCommand(); case GBA_SUBCOMMAND: return handleGbaCommand(); case D2D_SUBCOMMAND: return handleD2dCommand(); case BARRING_SUBCOMMAND: return handleBarringCommand(); case SINGLE_REGISTATION_CONFIG: return handleSingleRegistrationConfigCommand(); case RESTART_MODEM: return handleRestartModemCommand(); case CALL_COMPOSER_SUBCOMMAND: return handleCallComposerCommand(); case UNATTENDED_REBOOT: return handleUnattendedReboot(); case HAS_CARRIER_PRIVILEGES_COMMAND: return handleHasCarrierPrivilegesCommand(); case THERMAL_MITIGATION_COMMAND: return handleThermalMitigationCommand(); case DISABLE_PHYSICAL_SUBSCRIPTION: return handleEnablePhysicalSubscription(false); case ENABLE_PHYSICAL_SUBSCRIPTION: return handleEnablePhysicalSubscription(true); case GET_ALLOWED_NETWORK_TYPES_FOR_USER: case SET_ALLOWED_NETWORK_TYPES_FOR_USER: return handleAllowedNetworkTypesCommand(cmd); case GET_IMEI: return handleGetImei(); case GET_SIM_SLOTS_MAPPING: return handleGetSimSlotsMapping(); case RADIO_SUBCOMMAND: return handleRadioCommand(); case CARRIER_RESTRICTION_STATUS_TEST: return handleCarrierRestrictionStatusCommand(); case SET_CARRIER_SERVICE_PACKAGE_OVERRIDE: return setCarrierServicePackageOverride(); case CLEAR_CARRIER_SERVICE_PACKAGE_OVERRIDE: return clearCarrierServicePackageOverride(); case DOMAIN_SELECTION_SUBCOMMAND: return handleDomainSelectionCommand(); case SET_SATELLITE_SERVICE_PACKAGE_NAME: return handleSetSatelliteServicePackageNameCommand(); case SET_SATELLITE_GATEWAY_SERVICE_PACKAGE_NAME: return handleSetSatelliteGatewayServicePackageNameCommand(); case SET_SATELLITE_LISTENING_TIMEOUT_DURATION: return handleSetSatelliteListeningTimeoutDuration(); case SET_SATELLITE_POINTING_UI_CLASS_NAME: return handleSetSatellitePointingUiClassNameCommand(); case SET_DATAGRAM_CONTROLLER_TIMEOUT_DURATION: return handleSetDatagramControllerTimeoutDuration(); case SET_DATAGRAM_CONTROLLER_BOOLEAN_CONFIG: return handleSetDatagramControllerBooleanConfig(); case SET_SATELLITE_CONTROLLER_TIMEOUT_DURATION: return handleSetSatelliteControllerTimeoutDuration(); case SET_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE: return handleSetEmergencyCallToSatelliteHandoverType(); case SET_SHOULD_SEND_DATAGRAM_TO_MODEM_IN_DEMO_MODE: return handleSetShouldSendDatagramToModemInDemoMode(); case SET_SATELLITE_ACCESS_CONTROL_OVERLAY_CONFIGS: return handleSetSatelliteAccessControlOverlayConfigs(); case SET_COUNTRY_CODES: return handleSetCountryCodes(); case SET_OEM_ENABLED_SATELLITE_PROVISION_STATUS: return handleSetOemEnabledSatelliteProvisionStatus(); case SET_IS_SATELLITE_COMMUNICATION_ALLOWED_FOR_CURRENT_LOCATION_CACHE: return handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache(); default: { return handleDefaultCommands(cmd); } } } @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); pw.println("Telephony Commands:"); pw.println(" help"); pw.println(" Print this help text."); pw.println(" ims"); pw.println(" IMS Commands."); pw.println(" uce"); pw.println(" RCS User Capability Exchange Commands."); pw.println(" emergency-number-test-mode"); pw.println(" Emergency Number Test Mode Commands."); pw.println(" end-block-suppression"); pw.println(" End Block Suppression command."); pw.println(" data"); pw.println(" Data Test Mode Commands."); pw.println(" cc"); pw.println(" Carrier Config Commands."); pw.println(" gba"); pw.println(" GBA Commands."); pw.println(" src"); pw.println(" RCS VoLTE Single Registration Config Commands."); pw.println(" restart-modem"); pw.println(" Restart modem command."); pw.println(" unattended-reboot"); pw.println(" Prepare for unattended reboot."); pw.println(" has-carrier-privileges [package]"); pw.println(" Query carrier privilege status for a package. Prints true or false."); pw.println(" get-allowed-network-types-for-users"); pw.println(" Get the Allowed Network Types."); pw.println(" set-allowed-network-types-for-users"); pw.println(" Set the Allowed Network Types."); pw.println(" radio"); pw.println(" Radio Commands."); onHelpIms(); onHelpUce(); onHelpEmergencyNumber(); onHelpEndBlockSupperssion(); onHelpDataTestMode(); onHelpCc(); onHelpGba(); onHelpSrc(); onHelpD2D(); onHelpDisableOrEnablePhysicalSubscription(); onHelpAllowedNetworkTypes(); onHelpRadio(); onHelpImei(); onHelpSatellite(); onHelpDomainSelection(); } private void onHelpD2D() { PrintWriter pw = getOutPrintWriter(); pw.println("D2D Comms Commands:"); pw.println(" d2d send TYPE VALUE"); pw.println(" Sends a D2D message of specified type and value."); pw.println(" Type: " + MESSAGE_CALL_RADIO_ACCESS_TYPE + " - " + Communicator.messageToString(MESSAGE_CALL_RADIO_ACCESS_TYPE)); pw.println(" Type: " + MESSAGE_CALL_AUDIO_CODEC + " - " + Communicator.messageToString( MESSAGE_CALL_AUDIO_CODEC)); pw.println(" Type: " + MESSAGE_DEVICE_BATTERY_STATE + " - " + Communicator.messageToString( MESSAGE_DEVICE_BATTERY_STATE)); pw.println(" Type: " + MESSAGE_DEVICE_NETWORK_COVERAGE + " - " + Communicator.messageToString(MESSAGE_DEVICE_NETWORK_COVERAGE)); pw.println(" d2d transport TYPE"); pw.println(" Forces the specified D2D transport TYPE to be active. Use the"); pw.println(" short class name of the transport; i.e. DtmfTransport or RtpTransport."); pw.println(" d2d set-device-support true/default"); pw.println(" true - forces device support to be enabled for D2D."); pw.println(" default - clear any previously set force-enable of D2D, reverting to "); pw.println(" the current device's configuration."); } private void onHelpBarring() { PrintWriter pw = getOutPrintWriter(); pw.println("Barring Commands:"); pw.println(" barring send -s SLOT_ID -b BARRING_TYPE -c IS_CONDITIONALLY_BARRED" + " -t CONDITIONAL_BARRING_TIME_SECS"); pw.println(" Notifies of a barring info change for the specified slot id."); pw.println(" BARRING_TYPE: 0 for BARRING_TYPE_NONE"); pw.println(" BARRING_TYPE: 1 for BARRING_TYPE_UNCONDITIONAL"); pw.println(" BARRING_TYPE: 2 for BARRING_TYPE_CONDITIONAL"); pw.println(" BARRING_TYPE: -1 for BARRING_TYPE_UNKNOWN"); } private void onHelpIms() { PrintWriter pw = getOutPrintWriter(); pw.println("IMS Commands:"); pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME"); pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound"); pw.println(" ImsService. Options are:"); pw.println(" -s: the slot ID that the ImsService should be bound for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" -c: Override the ImsService defined in the carrier configuration."); pw.println(" -d: Override the ImsService defined in the device overlay."); pw.println(" -f: Set the feature that this override if for, if no option is"); pw.println(" specified, the new package name will be used for all features."); pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]"); pw.println(" Gets the package name of the currently defined ImsService."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID for the registered ImsService. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" -c: The ImsService defined as the carrier configured ImsService."); pw.println(" -d: The ImsService defined as the device default ImsService."); pw.println(" -f: The feature type that the query will be requested for. If none is"); pw.println(" specified, the returned package name will correspond to MMTEL."); pw.println(" ims clear-ims-service-override [-s SLOT_ID]"); pw.println(" Clear all carrier ImsService overrides. This does not work for device "); pw.println(" configuration overrides. Options are:"); pw.println(" -s: The SIM slot ID for the registered ImsService. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" ims enable [-s SLOT_ID]"); pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot"); pw.println(" if none is specified."); pw.println(" ims disable [-s SLOT_ID]"); pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM"); pw.println(" slot if none is specified."); pw.println(" ims conference-event-package [enable/disable]"); pw.println(" enables or disables handling or network conference event package data."); } private void onHelpUce() { PrintWriter pw = getOutPrintWriter(); pw.println("User Capability Exchange Commands:"); pw.println(" uce get-eab-contact [PHONE_NUMBER]"); pw.println(" Get the EAB contacts from the EAB database."); pw.println(" Options are:"); pw.println(" PHONE_NUMBER: The phone numbers to be removed from the EAB databases"); pw.println(" Expected output format :"); pw.println(" [PHONE_NUMBER],[RAW_CONTACT_ID],[CONTACT_ID],[DATA_ID]"); pw.println(" uce remove-eab-contact [-s SLOT_ID] [PHONE_NUMBER]"); pw.println(" Remove the EAB contacts from the EAB database."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" PHONE_NUMBER: The phone numbers to be removed from the EAB databases"); pw.println(" uce get-device-enabled"); pw.println(" Get the config to check whether the device supports RCS UCE or not."); pw.println(" uce set-device-enabled true|false"); pw.println(" Set the device config for RCS User Capability Exchange to the value."); pw.println(" The value could be true, false."); pw.println(" uce override-published-caps [-s SLOT_ID] add|remove|clear [CAPABILITIES]"); pw.println(" Override the existing SIP PUBLISH with different capabilities."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" add [CAPABILITY]: add a new capability"); pw.println(" remove [CAPABILITY]: remove a capability"); pw.println(" clear: clear all capability overrides"); pw.println(" CAPABILITY: \":\" separated list of capabilities."); pw.println(" Valid options are: [mmtel(_vt), chat_v1, chat_v2, ft, ft_sms,"); pw.println(" geo_push, geo_push_sms, call_comp, call_post, map, sketch, chatbot,"); pw.println(" chatbot_sa, chatbot_role] as well as full length"); pw.println(" featureTag=\"featureValue\" feature tags that are not defined here."); pw.println(" uce get-last-publish-pidf [-s SLOT_ID]"); pw.println(" Get the PIDF XML included in the last SIP PUBLISH, or \"none\" if no "); pw.println(" PUBLISH is active"); pw.println(" uce remove-request-disallowed-status [-s SLOT_ID]"); pw.println(" Remove the UCE is disallowed to execute UCE requests status"); pw.println(" uce set-capabilities-request-timeout [-s SLOT_ID] [REQUEST_TIMEOUT_MS]"); pw.println(" Set the timeout for contact capabilities request."); } private void onHelpNumberVerification() { PrintWriter pw = getOutPrintWriter(); pw.println("Number verification commands"); pw.println(" numverify override-package PACKAGE_NAME;"); pw.println(" Set the authorized package for number verification."); pw.println(" Leave the package name blank to reset."); pw.println(" numverify fake-call NUMBER;"); pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be"); pw.println(" 1 if the call would have been intercepted, 0 otherwise."); } private void onHelpThermalMitigation() { PrintWriter pw = getOutPrintWriter(); pw.println("Thermal mitigation commands"); pw.println(" thermal-mitigation allow-package PACKAGE_NAME"); pw.println(" Set the package as one of authorized packages for thermal mitigation."); pw.println(" thermal-mitigation disallow-package PACKAGE_NAME"); pw.println(" Remove the package from one of the authorized packages for thermal " + "mitigation."); } private void onHelpDisableOrEnablePhysicalSubscription() { PrintWriter pw = getOutPrintWriter(); pw.println("Disable or enable a physical subscription"); pw.println(" disable-physical-subscription SUB_ID"); pw.println(" Disable the physical subscription with the provided subId, if allowed."); pw.println(" enable-physical-subscription SUB_ID"); pw.println(" Enable the physical subscription with the provided subId, if allowed."); } private void onHelpDataTestMode() { PrintWriter pw = getOutPrintWriter(); pw.println("Mobile Data Test Mode Commands:"); pw.println(" data enable: enable mobile data connectivity"); pw.println(" data disable: disable mobile data connectivity"); } private void onHelpEmergencyNumber() { PrintWriter pw = getOutPrintWriter(); pw.println("Emergency Number Test Mode Commands:"); pw.println(" emergency-number-test-mode "); pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in" + " the test mode"); pw.println(" -a : add an emergency number address for the" + " test mode, only allows '0'-'9', '*', '#' or '+'."); pw.println(" -c: clear the emergency number list in the test mode."); pw.println(" -r : remove an existing emergency number" + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'."); pw.println(" -p: get the full emergency number list in the test mode."); } private void onHelpEndBlockSupperssion() { PrintWriter pw = getOutPrintWriter(); pw.println("End Block Suppression command:"); pw.println(" end-block-suppression: disable suppressing blocking by contact"); pw.println(" with emergency services."); } private void onHelpCc() { PrintWriter pw = getOutPrintWriter(); pw.println("Carrier Config Commands:"); pw.println(" cc get-value [-s SLOT_ID] [KEY]"); pw.println(" Print carrier config values."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" KEY: The key to the carrier config value to print. All values are printed"); pw.println(" if KEY is not specified."); pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]"); pw.println(" Set carrier config KEY to NEW_VALUE."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to set carrier config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" -p: Value will be stored persistent"); pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be"); pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with"); pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\""); pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\""); pw.println(" cc set-values-from-xml [-s SLOT_ID] [-p] < XML_FILE_PATH"); pw.println(" Set carrier config based on the contents of the XML_FILE. File must be"); pw.println(" provided through standard input and follow CarrierConfig XML format."); pw.println(" Example: packages/apps/CarrierConfig/assets/*.xml"); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to set carrier config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" -p: Value will be stored persistent"); pw.println(" cc clear-values [-s SLOT_ID]"); pw.println(" Clear all carrier override values that has previously been set"); pw.println(" with set-value or set-values-from-xml"); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); } private void onHelpEuicc() { PrintWriter pw = getOutPrintWriter(); pw.println("Euicc Commands:"); pw.println(" euicc set-euicc-uicomponent COMPONENT_NAME PACKAGE_NAME"); pw.println(" Sets the Euicc Ui-Component which handles EuiccService Actions."); pw.println(" COMPONENT_NAME: The component name which handles UI Actions."); pw.println(" PACKAGE_NAME: THe package name in which ui component belongs."); } private void onHelpGba() { PrintWriter pw = getOutPrintWriter(); pw.println("Gba Commands:"); pw.println(" gba set-service [-s SLOT_ID] PACKAGE_NAME"); pw.println(" Sets the GbaService defined in PACKAGE_NAME to to be the bound."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" gba get-service [-s SLOT_ID]"); pw.println(" Gets the package name of the currently defined GbaService."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" gba set-release [-s SLOT_ID] n"); pw.println(" Sets the time to release/unbind GbaService in n milli-second."); pw.println(" Do not release/unbind if n is -1."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" gba get-release [-s SLOT_ID]"); pw.println(" Gets the time to release/unbind GbaService in n milli-sencond."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); } private void onHelpSrc() { PrintWriter pw = getOutPrintWriter(); pw.println("RCS VoLTE Single Registration Config Commands:"); pw.println(" src set-test-enabled true|false"); pw.println(" Sets the test mode enabled for RCS VoLTE single registration."); pw.println(" The value could be true, false, or null(undefined)."); pw.println(" src get-test-enabled"); pw.println(" Gets the test mode for RCS VoLTE single registration."); pw.println(" src set-device-enabled true|false|null"); pw.println(" Sets the device config for RCS VoLTE single registration to the value."); pw.println(" The value could be true, false, or null(undefined)."); pw.println(" src get-device-enabled"); pw.println(" Gets the device config for RCS VoLTE single registration."); pw.println(" src set-carrier-enabled [-s SLOT_ID] true|false|null"); pw.println(" Sets the carrier config for RCS VoLTE single registration to the value."); pw.println(" The value could be true, false, or null(undefined)."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to set the config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" src get-carrier-enabled [-s SLOT_ID]"); pw.println(" Gets the carrier config for RCS VoLTE single registration."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read the config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" src set-feature-validation [-s SLOT_ID] true|false|null"); pw.println(" Sets ims feature validation result."); pw.println(" The value could be true, false, or null(undefined)."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to set the config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); pw.println(" src get-feature-validation [-s SLOT_ID]"); pw.println(" Gets ims feature validation override value."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read the config value for. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); } private void onHelpAllowedNetworkTypes() { PrintWriter pw = getOutPrintWriter(); pw.println("Allowed Network Types Commands:"); pw.println(" get-allowed-network-types-for-users [-s SLOT_ID]"); pw.println(" Print allowed network types value."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to read allowed network types value for. If no"); pw.println(" option is specified, it will choose the default voice SIM slot."); pw.println(" set-allowed-network-types-for-users [-s SLOT_ID] [NETWORK_TYPES_BITMASK]"); pw.println(" Sets allowed network types to NETWORK_TYPES_BITMASK."); pw.println(" Options are:"); pw.println(" -s: The SIM slot ID to set allowed network types value for. If no"); pw.println(" option is specified, it will choose the default voice SIM slot."); pw.println(" NETWORK_TYPES_BITMASK specifies the new network types value and this type"); pw.println(" is bitmask in binary format. Reference the NetworkTypeBitMask"); pw.println(" at TelephonyManager.java"); pw.println(" For example:"); pw.println(" NR only : 10000000000000000000"); pw.println(" NR|LTE : 11000001000000000000"); pw.println(" NR|LTE|CDMA|EVDO|GSM|WCDMA : 11001111101111111111"); pw.println(" LTE|CDMA|EVDO|GSM|WCDMA : 01001111101111111111"); pw.println(" LTE only : 01000001000000000000"); } private void onHelpRadio() { PrintWriter pw = getOutPrintWriter(); pw.println("Radio Commands:"); pw.println(" radio set-modem-service [-s SERVICE_NAME]"); pw.println(" Sets the class name of modem service defined in SERVICE_NAME"); pw.println(" to be the bound. Options are:"); pw.println(" -s: the service name that the modem service should be bound for."); pw.println(" If no option is specified, it will bind to the default."); pw.println(" radio get-modem-service"); pw.println(" Gets the service name of the currently defined modem service."); pw.println(" If it is binding to default, 'default' returns."); pw.println(" If it doesn't bind to any modem service for some reasons,"); pw.println(" the result would be 'unknown'."); } private void onHelpSatellite() { PrintWriter pw = getOutPrintWriter(); pw.println("Satellite Commands:"); pw.println(" set-satellite-service-package-name [-s SERVICE_PACKAGE_NAME]"); pw.println(" Sets the package name of satellite service defined in"); pw.println(" SERVICE_PACKAGE_NAME to be bound. Options are:"); pw.println(" -s: the satellite service package name that Telephony will bind to."); pw.println(" If no option is specified, it will bind to the default."); pw.println(" set-satellite-gateway-service-package-name [-s SERVICE_PACKAGE_NAME]"); pw.println(" Sets the package name of satellite gateway service defined in"); pw.println(" SERVICE_PACKAGE_NAME to be bound. Options are:"); pw.println(" -s: the satellite gateway service package name that Telephony will bind"); pw.println(" to. If no option is specified, it will bind to the default."); pw.println(" set-satellite-listening-timeout-duration [-t TIMEOUT_MILLIS]"); pw.println(" Sets the timeout duration in millis that satellite will stay at listening"); pw.println(" mode. Options are:"); pw.println(" -t: the timeout duration in milliseconds."); pw.println(" If no option is specified, it will use the default values."); pw.println(" set-satellite-pointing-ui-class-name [-p PACKAGE_NAME -c CLASS_NAME]"); pw.println(" Sets the package and class name of satellite pointing UI app defined in"); pw.println(" PACKAGE_NAME and CLASS_NAME to be launched. Options are:"); pw.println(" -p: the satellite pointing UI app package name that Telephony will"); pw.println(" launch. If no option is specified, it will launch the default."); pw.println(" -c: the satellite pointing UI app class name that Telephony will"); pw.println(" launch."); pw.println(" set-emergency-call-to-satellite-handover-type [-t HANDOVER_TYPE "); pw.println(" -d DELAY_SECONDS] Override connectivity status in monitoring emergency "); pw.println(" call and sending EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer."); pw.println(" Options are:"); pw.println(" -t: the emergency call to satellite handover type."); pw.println(" If no option is specified, override is disabled."); pw.println(" -d: the delay in seconds in sending EVENT_DISPLAY_EMERGENCY_MESSAGE."); pw.println(" If no option is specified, there is no delay in sending the event."); pw.println(" set-satellite-access-control-overlay-configs [-r -a -f SATELLITE_S2_FILE "); pw.println(" -d LOCATION_FRESH_DURATION_NANOS -c COUNTRY_CODES] Override the overlay"); pw.println(" configs of satellite access controller."); pw.println(" Options are:"); pw.println(" -r: clear the overriding. Absent means enable overriding."); pw.println(" -a: the country codes is an allowed list. Absent means disallowed."); pw.println(" -f: the satellite s2 file."); pw.println(" -d: the location fresh duration nanos."); pw.println(" -c: the list of satellite country codes separated by comma."); pw.println(" set-country-codes [-r -n CURRENT_NETWORK_COUNTRY_CODES -c"); pw.println(" CACHED_NETWORK_COUNTRY_CODES -l LOCATION_COUNTRY_CODE -t"); pw.println(" LOCATION_COUNTRY_CODE_TIMESTAMP] "); pw.println(" Override the cached location country code and its update timestamp. "); pw.println(" Options are:"); pw.println(" -r: clear the overriding. Absent means enable overriding."); pw.println(" -n: the current network country code ISOs."); pw.println(" -c: the cached network country code ISOs."); pw.println(" -l: the location country code ISO."); pw.println(" -t: the update timestamp nanos of the location country code."); pw.println(" set-oem-enabled-satellite-provision-status [-p true/false]"); pw.println(" Sets the OEM-enabled satellite provision status. Options are:"); pw.println(" -p: the overriding satellite provision status. If no option is "); pw.println(" specified, reset the overridden provision status."); } private void onHelpImei() { PrintWriter pw = getOutPrintWriter(); pw.println("IMEI Commands:"); pw.println(" get-imei [-s SLOT_ID]"); pw.println(" Gets the device IMEI. Options are:"); pw.println(" -s: the slot ID to get the IMEI. If no option"); pw.println(" is specified, it will choose the default voice SIM slot."); } private void onHelpDomainSelection() { PrintWriter pw = getOutPrintWriter(); pw.println("Domain Selection Commands:"); pw.println(" domainselection set-dss-override COMPONENT_NAME"); pw.println(" Sets the service defined in COMPONENT_NAME to be bound"); pw.println(" domainselection clear-dss-override"); pw.println(" Clears DomainSelectionService override."); } private int handleImsCommand() { String arg = getNextArg(); if (arg == null) { onHelpIms(); return 0; } switch (arg) { case IMS_SET_IMS_SERVICE: { return handleImsSetServiceCommand(); } case IMS_GET_IMS_SERVICE: { return handleImsGetServiceCommand(); } case IMS_CLEAR_SERVICE_OVERRIDE: { return handleImsClearCarrierServiceCommand(); } case ENABLE: { return handleEnableIms(); } case DISABLE: { return handleDisableIms(); } case IMS_CEP: { return handleCepChange(); } } return -1; } private int handleDataTestModeCommand() { PrintWriter errPw = getErrPrintWriter(); String arg = getNextArgRequired(); if (arg == null) { onHelpDataTestMode(); return 0; } switch (arg) { case ENABLE: { try { mInterface.enableDataConnectivity(mContext.getOpPackageName()); } catch (RemoteException ex) { Log.w(LOG_TAG, "data enable, error " + ex.getMessage()); errPw.println("Exception: " + ex.getMessage()); return -1; } break; } case DISABLE: { try { mInterface.disableDataConnectivity(mContext.getOpPackageName()); } catch (RemoteException ex) { Log.w(LOG_TAG, "data disable, error " + ex.getMessage()); errPw.println("Exception: " + ex.getMessage()); return -1; } break; } default: onHelpDataTestMode(); break; } return 0; } private int handleEmergencyCallbackModeCommand() { PrintWriter errPw = getErrPrintWriter(); try { mInterface.startEmergencyCallbackMode(); Log.d(LOG_TAG, "handleEmergencyCallbackModeCommand: triggered"); } catch (RemoteException ex) { Log.w(LOG_TAG, "emergency-callback-mode error: " + ex.getMessage()); errPw.println("Exception: " + ex.getMessage()); return -1; } return 0; } private void removeEmergencyNumberTestMode(String emergencyNumber) { PrintWriter errPw = getErrPrintWriter(); for (int routingType : ROUTING_TYPES) { try { mInterface.updateEmergencyNumberListTestMode( EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE, new EmergencyNumber(emergencyNumber, "", "", EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, new ArrayList(), EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST, routingType)); } catch (RemoteException ex) { Log.w(LOG_TAG, "emergency-number-test-mode " + "error " + ex.getMessage()); errPw.println("Exception: " + ex.getMessage()); } } } private int handleEmergencyNumberTestModeCommand() { PrintWriter errPw = getErrPrintWriter(); String opt = getNextOption(); if (opt == null) { onHelpEmergencyNumber(); return 0; } switch (opt) { case "-a": { String emergencyNumberCmd = getNextArgRequired(); if (emergencyNumberCmd == null){ errPw.println(INVALID_ENTRY_ERROR); return -1; } String[] params = emergencyNumberCmd.split(":"); String emergencyNumber; if (params[0] == null || !EmergencyNumber.validateEmergencyNumberAddress(params[0])){ errPw.println(INVALID_ENTRY_ERROR); return -1; } else { emergencyNumber = params[0]; } removeEmergencyNumberTestMode(emergencyNumber); int emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN; if (params.length > 1) { switch (params[1].toLowerCase(Locale.ROOT)) { case "emergency": emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY; break; case "normal": emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL; break; case "unknown": break; default: errPw.println("\"" + params[1] + "\" is not a valid specification for " + "emergency call routing. Please enter either \"normal\", " + "\"unknown\", or \"emergency\" for call routing. " + "(-a 1234:normal)"); return -1; } } try { mInterface.updateEmergencyNumberListTestMode( EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE, new EmergencyNumber(emergencyNumber, "", "", EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, new ArrayList(), EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST, emergencyCallRouting)); } catch (RemoteException ex) { Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumber + ", error " + ex.getMessage()); errPw.println("Exception: " + ex.getMessage()); return -1; } break; } case "-c": { try { mInterface.updateEmergencyNumberListTestMode( EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null); } catch (RemoteException ex) { Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage()); errPw.println("Exception: " + ex.getMessage()); return -1; } break; } case "-r": { String emergencyNumberCmd = getNextArgRequired(); if (emergencyNumberCmd == null || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) { errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs" + " to be specified after -r in the command "); return -1; } removeEmergencyNumberTestMode(emergencyNumberCmd); break; } case "-p": { try { getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode()); } catch (RemoteException ex) { Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage()); errPw.println("Exception: " + ex.getMessage()); return -1; } break; } default: onHelpEmergencyNumber(); break; } return 0; } private int handleNumberVerificationCommand() { String arg = getNextArg(); if (arg == null) { onHelpNumberVerification(); return 0; } if (!checkShellUid()) { return -1; } switch (arg) { case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: { NumberVerificationManager.overrideAuthorizedPackage(getNextArg()); return 0; } case NUMBER_VERIFICATION_FAKE_CALL: { boolean val = NumberVerificationManager.getInstance() .checkIncomingCall(getNextArg()); getOutPrintWriter().println(val ? "1" : "0"); return 0; } } return -1; } private boolean subIsEsim(int subId) { SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId); if (info != null) { return info.isEmbedded(); } return false; } private int handleEnablePhysicalSubscription(boolean enable) { PrintWriter errPw = getErrPrintWriter(); int subId = 0; try { subId = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { errPw.println((enable ? "enable" : "disable") + "-physical-subscription requires an integer as a subId."); return -1; } // Verify that the user is allowed to run the command. Only allowed in rooted device in a // non user build. if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { errPw.println("cc: Permission denied."); return -1; } // Verify that the subId represents a physical sub if (subIsEsim(subId)) { errPw.println("SubId " + subId + " is not for a physical subscription"); return -1; } Log.d(LOG_TAG, (enable ? "Enabling" : "Disabling") + " physical subscription with subId=" + subId); mSubscriptionManager.setUiccApplicationsEnabled(subId, enable); return 0; } private int handleThermalMitigationCommand() { String arg = getNextArg(); String packageName = getNextArg(); if (arg == null || packageName == null) { onHelpThermalMitigation(); return 0; } if (!checkShellUid()) { return -1; } switch (arg) { case ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: { PhoneInterfaceManager.addPackageToThermalMitigationAllowlist(packageName, mContext); return 0; } case DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: { PhoneInterfaceManager.removePackageFromThermalMitigationAllowlist(packageName, mContext); return 0; } default: onHelpThermalMitigation(); } return -1; } private int handleD2dCommand() { String arg = getNextArg(); if (arg == null) { onHelpD2D(); return 0; } switch (arg) { case D2D_SEND: { return handleD2dSendCommand(); } case D2D_TRANSPORT: { return handleD2dTransportCommand(); } case D2D_SET_DEVICE_SUPPORT: { return handleD2dDeviceSupportedCommand(); } } return -1; } private int handleD2dSendCommand() { PrintWriter errPw = getErrPrintWriter(); int messageType = -1; int messageValue = -1; String arg = getNextArg(); if (arg == null) { onHelpD2D(); return 0; } try { messageType = Integer.parseInt(arg); } catch (NumberFormatException e) { errPw.println("message type must be a valid integer"); return -1; } arg = getNextArg(); if (arg == null) { onHelpD2D(); return 0; } try { messageValue = Integer.parseInt(arg); } catch (NumberFormatException e) { errPw.println("message value must be a valid integer"); return -1; } try { mInterface.sendDeviceToDeviceMessage(messageType, messageValue); } catch (RemoteException e) { Log.w(LOG_TAG, "d2d send error: " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleD2dTransportCommand() { PrintWriter errPw = getErrPrintWriter(); String arg = getNextArg(); if (arg == null) { onHelpD2D(); return 0; } try { mInterface.setActiveDeviceToDeviceTransport(arg); } catch (RemoteException e) { Log.w(LOG_TAG, "d2d transport error: " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleBarringCommand() { String arg = getNextArg(); if (arg == null) { onHelpBarring(); return 0; } switch (arg) { case BARRING_SEND_INFO: { return handleBarringSendCommand(); } } return -1; } private int handleBarringSendCommand() { PrintWriter errPw = getErrPrintWriter(); int slotId = getDefaultSlot(); int subId = SubscriptionManager.getSubscriptionId(slotId); @BarringInfo.BarringServiceInfo.BarringType int barringType = BarringInfo.BarringServiceInfo.BARRING_TYPE_UNCONDITIONAL; boolean isConditionallyBarred = false; int conditionalBarringTimeSeconds = 0; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { try { slotId = Integer.parseInt(getNextArgRequired()); subId = SubscriptionManager.getSubscriptionId(slotId); } catch (NumberFormatException e) { errPw.println("barring send requires an integer as a SLOT_ID."); return -1; } break; } case "-b": { try { barringType = Integer.parseInt(getNextArgRequired()); if (barringType < -1 || barringType > 2) { throw new NumberFormatException(); } } catch (NumberFormatException e) { errPw.println("barring send requires an integer in range [-1,2] as " + "a BARRING_TYPE."); return -1; } break; } case "-c": { try { isConditionallyBarred = Boolean.parseBoolean(getNextArgRequired()); } catch (Exception e) { errPw.println("barring send requires a boolean after -c indicating" + " conditional barring"); return -1; } break; } case "-t": { try { conditionalBarringTimeSeconds = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { errPw.println("barring send requires an integer for time of barring" + " in seconds after -t for conditional barring"); return -1; } break; } } } SparseArray barringServiceInfos = new SparseArray<>(); BarringInfo.BarringServiceInfo bsi = new BarringInfo.BarringServiceInfo( barringType, isConditionallyBarred, 0, conditionalBarringTimeSeconds); barringServiceInfos.append(0, bsi); BarringInfo barringInfo = new BarringInfo(null, barringServiceInfos); try { mTelephonyRegistryManager.notifyBarringInfoChanged(slotId, subId, barringInfo); } catch (Exception e) { Log.w(LOG_TAG, "barring send error: " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleD2dDeviceSupportedCommand() { PrintWriter errPw = getErrPrintWriter(); String arg = getNextArg(); if (arg == null) { onHelpD2D(); return 0; } boolean isEnabled = "true".equals(arg.toLowerCase(Locale.ROOT)); try { mInterface.setDeviceToDeviceForceEnabled(isEnabled); } catch (RemoteException e) { Log.w(LOG_TAG, "Error forcing D2D enabled: " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } // ims set-ims-service private int handleImsSetServiceCommand() { PrintWriter errPw = getErrPrintWriter(); int slotId = getDefaultSlot(); Boolean isCarrierService = null; List featuresList = new ArrayList<>(); String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { try { slotId = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { errPw.println("ims set-ims-service requires an integer as a SLOT_ID."); return -1; } break; } case "-c": { isCarrierService = true; break; } case "-d": { isCarrierService = false; break; } case "-f": { String featureString = getNextArgRequired(); String[] features = featureString.split(","); for (int i = 0; i < features.length; i++) { try { Integer result = Integer.parseInt(features[i]); if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL || result >= ImsFeature.FEATURE_MAX) { errPw.println("ims set-ims-service -f " + result + " is an invalid feature."); return -1; } featuresList.add(result); } catch (NumberFormatException e) { errPw.println("ims set-ims-service -f tried to parse " + features[i] + " as an integer."); return -1; } } } } } // Mandatory param, either -c or -d if (isCarrierService == null) { errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set."); return -1; } String packageName = getNextArg(); try { if (packageName == null) { packageName = ""; } int[] featureArray = new int[featuresList.size()]; for (int i = 0; i < featuresList.size(); i++) { featureArray[i] = featuresList.get(i); } boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService, featureArray, packageName); if (VDBG) { Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " " + (isCarrierService ? "-c " : "-d ") + "-f " + featuresList + " " + packageName + ", result=" + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " " + (isCarrierService ? "-c " : "-d ") + "-f " + featuresList + " " + packageName + ", error" + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } // ims clear-ims-service-override private int handleImsClearCarrierServiceCommand() { PrintWriter errPw = getErrPrintWriter(); int slotId = getDefaultSlot(); String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { try { slotId = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { errPw.println("ims set-ims-service requires an integer as a SLOT_ID."); return -1; } break; } } } try { boolean result = mInterface.clearCarrierImsServiceOverride(slotId); if (VDBG) { Log.v(LOG_TAG, "ims clear-ims-service-override -s " + slotId + ", result=" + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "ims clear-ims-service-override -s " + slotId + ", error" + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } // ims get-ims-service private int handleImsGetServiceCommand() { PrintWriter errPw = getErrPrintWriter(); int slotId = getDefaultSlot(); Boolean isCarrierService = null; Integer featureType = ImsFeature.FEATURE_MMTEL; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { try { slotId = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { errPw.println("ims set-ims-service requires an integer as a SLOT_ID."); return -1; } break; } case "-c": { isCarrierService = true; break; } case "-d": { isCarrierService = false; break; } case "-f": { try { featureType = Integer.parseInt(getNextArg()); } catch (NumberFormatException e) { errPw.println("ims get-ims-service -f requires valid integer as feature."); return -1; } if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL || featureType >= ImsFeature.FEATURE_MAX) { errPw.println("ims get-ims-service -f invalid feature."); return -1; } } } } // Mandatory param, either -c or -d if (isCarrierService == null) { errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set."); return -1; } String result; try { result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType); } catch (RemoteException e) { return -1; } if (VDBG) { Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " " + (isCarrierService ? "-c " : "-d ") + (featureType != null ? ("-f " + featureType) : "") + " , returned: " + result); } getOutPrintWriter().println(result); return 0; } private int handleEnableIms() { int slotId = getDefaultSlot(); String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { try { slotId = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID."); return -1; } break; } } } try { mInterface.enableIms(slotId); } catch (RemoteException e) { return -1; } if (VDBG) { Log.v(LOG_TAG, "ims enable -s " + slotId); } return 0; } private int handleDisableIms() { int slotId = getDefaultSlot(); String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { try { slotId = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { getErrPrintWriter().println( "ims disable requires an integer as a SLOT_ID."); return -1; } break; } } } try { mInterface.disableIms(slotId); } catch (RemoteException e) { return -1; } if (VDBG) { Log.v(LOG_TAG, "ims disable -s " + slotId); } return 0; } private int handleCepChange() { Log.i(LOG_TAG, "handleCepChange"); String opt = getNextArg(); if (opt == null) { return -1; } boolean isCepEnabled = opt.equals("enable"); try { mInterface.setCepEnabled(isCepEnabled); } catch (RemoteException e) { return -1; } return 0; } private int getDefaultSlot() { int slotId = SubscriptionManager.getDefaultVoicePhoneId(); if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) { // If there is no default, default to slot 0. slotId = DEFAULT_PHONE_ID; } return slotId; } // Parse options related to Carrier Config Commands. private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) { PrintWriter errPw = getErrPrintWriter(); CcOptionParseResult result = new CcOptionParseResult(); result.mSubId = SubscriptionManager.getDefaultSubscriptionId(); result.mPersistent = false; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { try { result.mSubId = slotStringToSubId(tag, getNextArgRequired()); if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) { errPw.println(tag + "No valid subscription found."); return null; } } catch (IllegalArgumentException e) { // Missing slot id errPw.println(tag + "SLOT_ID expected after -s."); return null; } break; } case "-p": { if (allowOptionPersistent) { result.mPersistent = true; } else { errPw.println(tag + "Unexpected option " + opt); return null; } break; } default: { errPw.println(tag + "Unknown option " + opt); return null; } } } return result; } private int slotStringToSubId(String tag, String slotString) { int slotId = -1; try { slotId = Integer.parseInt(slotString); } catch (NumberFormatException e) { getErrPrintWriter().println(tag + slotString + " is not a valid number for SLOT_ID."); return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } if (!SubscriptionManager.isValidPhoneId(slotId)) { getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID."); return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } Phone phone = PhoneFactory.getPhone(slotId); if (phone == null) { getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + "."); return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } return phone.getSubId(); } private boolean checkShellUid() { // adb can run as root or as shell, depending on whether the device is rooted. return Binder.getCallingUid() == Process.SHELL_UID || Binder.getCallingUid() == Process.ROOT_UID; } private int handleCcCommand() { // Verify that the user is allowed to run the command. Only allowed in rooted device in a // non user build. if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { getErrPrintWriter().println("cc: Permission denied."); return -1; } String arg = getNextArg(); if (arg == null) { onHelpCc(); return 0; } switch (arg) { case CC_GET_VALUE: { return handleCcGetValue(); } case CC_SET_VALUE: { return handleCcSetValue(); } case CC_SET_VALUES_FROM_XML: { return handleCcSetValuesFromXml(); } case CC_CLEAR_VALUES: { return handleCcClearValues(); } default: { getErrPrintWriter().println("cc: Unknown argument: " + arg); } } return -1; } // cc get-value private int handleCcGetValue() { PrintWriter errPw = getErrPrintWriter(); String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": "; String key = null; // Parse all options CcOptionParseResult options = parseCcOptions(tag, false); if (options == null) { return -1; } // Get bundle containing all carrier configuration values. PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId); if (bundle == null) { errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); return -1; } // Get the key. key = getNextArg(); if (key != null) { // A key was provided. Verify if it is a valid key if (!bundle.containsKey(key)) { errPw.println(tag + key + " is not a valid key."); return -1; } // Print the carrier config value for key. getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle)); } else { // No key provided. Show all values. // Iterate over a sorted list of all carrier config keys and print them. TreeSet sortedSet = new TreeSet(bundle.keySet()); for (String k : sortedSet) { getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle)); } } return 0; } // cc set-value private int handleCcSetValue() { PrintWriter errPw = getErrPrintWriter(); String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": "; // Parse all options CcOptionParseResult options = parseCcOptions(tag, true); if (options == null) { return -1; } // Get bundle containing all current carrier configuration values. PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId); if (originalValues == null) { errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); return -1; } // Get the key. String key = getNextArg(); if (key == null || key.equals("")) { errPw.println(tag + "KEY is missing"); return -1; } // Verify if the key is valid if (!originalValues.containsKey(key)) { errPw.println(tag + key + " is not a valid key."); return -1; } // Remaining arguments is a list of new values. Add them all into an ArrayList. ArrayList valueList = new ArrayList(); while (peekNextArg() != null) { valueList.add(getNextArg()); } // Find the type of the carrier config value CcType type = getType(tag, key, originalValues); if (type == CcType.UNKNOWN) { errPw.println(tag + "ERROR: Not possible to override key with unknown type."); return -1; } if (type == CcType.PERSISTABLE_BUNDLE) { errPw.println(tag + "ERROR: Overriding of persistable bundle type is not supported. " + "Use set-values-from-xml instead."); return -1; } // Create an override bundle containing the key and value that should be overriden. PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList); if (overrideBundle == null) { return -1; } // Override the value mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent); // Find bundle containing all new carrier configuration values after the override. PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId); if (newValues == null) { errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); return -1; } // Print the original and new value. String originalValueString = ccValueToString(key, type, originalValues); String newValueString = ccValueToString(key, type, newValues); getOutPrintWriter().println("Previous value: \n" + originalValueString); getOutPrintWriter().println("New value: \n" + newValueString); return 0; } // cc set-values-from-xml private int handleCcSetValuesFromXml() { PrintWriter errPw = getErrPrintWriter(); String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUES_FROM_XML + ": "; // Parse all options CcOptionParseResult options = parseCcOptions(tag, true); if (options == null) { return -1; } // Get bundle containing all current carrier configuration values. PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId); if (originalValues == null) { errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); return -1; } PersistableBundle overrideBundle = readPersistableBundleFromXml(tag); if (overrideBundle == null) { return -1; } // Verify all values are valid types for (String key : overrideBundle.keySet()) { CcType type = getType(tag, key, originalValues); if (type == CcType.UNKNOWN) { errPw.println(tag + "ERROR: Not possible to override key with unknown type."); return -1; } } // Override the value mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent); // Find bundle containing all new carrier configuration values after the override. PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId); if (newValues == null) { errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); return -1; } // Print the original and new values overrideBundle.keySet().forEach(key -> { CcType type = getType(tag, key, originalValues); String originalValueString = ccValueToString(key, type, originalValues); String newValueString = ccValueToString(key, type, newValues); getOutPrintWriter().println("Previous value: \n" + originalValueString); getOutPrintWriter().println("New value: \n" + newValueString); }); return 0; } private PersistableBundle readPersistableBundleFromXml(String tag) { PersistableBundle subIdBundles; try { subIdBundles = PersistableBundle.readFromStream(getRawInputStream()); } catch (IOException | RuntimeException e) { PrintWriter errPw = getErrPrintWriter(); errPw.println(tag + e); return null; } return subIdBundles; } // cc clear-values private int handleCcClearValues() { String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": "; // Parse all options CcOptionParseResult options = parseCcOptions(tag, false); if (options == null) { return -1; } // Clear all values that has previously been set. mCarrierConfigManager.overrideConfig(options.mSubId, null, true); getOutPrintWriter() .println("All previously set carrier config override values has been cleared"); return 0; } private CcType getType(String tag, String key, PersistableBundle bundle) { // Find the type by checking the type of the current value stored in the bundle. Object value = bundle.get(key); if (CC_TYPE_MAP.containsKey(key)) { return CC_TYPE_MAP.get(key); } else if (value != null) { if (value instanceof Boolean) { return CcType.BOOLEAN; } if (value instanceof Double) { return CcType.DOUBLE; } if (value instanceof double[]) { return CcType.DOUBLE_ARRAY; } if (value instanceof Integer) { return CcType.INT; } if (value instanceof int[]) { return CcType.INT_ARRAY; } if (value instanceof Long) { return CcType.LONG; } if (value instanceof long[]) { return CcType.LONG_ARRAY; } if (value instanceof String) { return CcType.STRING; } if (value instanceof String[]) { return CcType.STRING_ARRAY; } if (value instanceof PersistableBundle) { return CcType.PERSISTABLE_BUNDLE; } } else { // Current value was null and can therefore not be used in order to find the type. // Check the name of the key to infer the type. This check is not needed for primitive // data types (boolean, double, int and long), since they can not be null. if (key.endsWith("double_array")) { return CcType.DOUBLE_ARRAY; } if (key.endsWith("int_array")) { return CcType.INT_ARRAY; } if (key.endsWith("long_array")) { return CcType.LONG_ARRAY; } if (key.endsWith("string")) { return CcType.STRING; } if (key.endsWith("string_array") || key.endsWith("strings")) { return CcType.STRING_ARRAY; } if (key.endsWith("bundle")) { return CcType.PERSISTABLE_BUNDLE; } } // Not possible to infer the type by looking at the current value or the key. PrintWriter errPw = getErrPrintWriter(); errPw.println(tag + "ERROR: " + key + " has unknown type."); return CcType.UNKNOWN; } private String ccValueToString(String key, CcType type, PersistableBundle bundle) { String result; StringBuilder valueString = new StringBuilder(); String typeString = type.toString(); Object value = bundle.get(key); if (value == null) { valueString.append("null"); } else { switch (type) { case DOUBLE_ARRAY: { // Format the string representation of the int array as value1 value2...... double[] valueArray = (double[]) value; for (int i = 0; i < valueArray.length; i++) { if (i != 0) { valueString.append(" "); } valueString.append(valueArray[i]); } break; } case INT_ARRAY: { // Format the string representation of the int array as value1 value2...... int[] valueArray = (int[]) value; for (int i = 0; i < valueArray.length; i++) { if (i != 0) { valueString.append(" "); } valueString.append(valueArray[i]); } break; } case LONG_ARRAY: { // Format the string representation of the int array as value1 value2...... long[] valueArray = (long[]) value; for (int i = 0; i < valueArray.length; i++) { if (i != 0) { valueString.append(" "); } valueString.append(valueArray[i]); } break; } case STRING: { valueString.append("\"" + value.toString() + "\""); break; } case STRING_ARRAY: { // Format the string representation of the string array as "value1" "value2".... String[] valueArray = (String[]) value; for (int i = 0; i < valueArray.length; i++) { if (i != 0) { valueString.append(" "); } if (valueArray[i] != null) { valueString.append("\"" + valueArray[i] + "\""); } else { valueString.append("null"); } } break; } default: { valueString.append(value.toString()); } } } return String.format("%-70s %-15s %s", key, typeString, valueString); } private PersistableBundle getOverrideBundle(String tag, CcType type, String key, ArrayList valueList) { PrintWriter errPw = getErrPrintWriter(); PersistableBundle bundle = new PersistableBundle(); // First verify that a valid number of values has been provided for the type. switch (type) { case BOOLEAN: case DOUBLE: case INT: case LONG: { if (valueList.size() != 1) { errPw.println(tag + "Expected 1 value for type " + type + ". Found: " + valueList.size()); return null; } break; } case STRING: { if (valueList.size() > 1) { errPw.println(tag + "Expected 0 or 1 values for type " + type + ". Found: " + valueList.size()); return null; } break; } } // Parse the value according to type and add it to the Bundle. switch (type) { case BOOLEAN: { if ("true".equalsIgnoreCase(valueList.get(0))) { bundle.putBoolean(key, true); } else if ("false".equalsIgnoreCase(valueList.get(0))) { bundle.putBoolean(key, false); } else { errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type); return null; } break; } case DOUBLE: { try { bundle.putDouble(key, Double.parseDouble(valueList.get(0))); } catch (NumberFormatException nfe) { // Not a valid double errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type); return null; } break; } case DOUBLE_ARRAY: { double[] valueDoubleArray = null; if (valueList.size() > 0) { valueDoubleArray = new double[valueList.size()]; for (int i = 0; i < valueList.size(); i++) { try { valueDoubleArray[i] = Double.parseDouble(valueList.get(i)); } catch (NumberFormatException nfe) { // Not a valid double errPw.println( tag + "Unable to parse " + valueList.get(i) + " as a double."); return null; } } } bundle.putDoubleArray(key, valueDoubleArray); break; } case INT: { try { bundle.putInt(key, Integer.parseInt(valueList.get(0))); } catch (NumberFormatException nfe) { // Not a valid integer errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type); return null; } break; } case INT_ARRAY: { int[] valueIntArray = null; if (valueList.size() > 0) { valueIntArray = new int[valueList.size()]; for (int i = 0; i < valueList.size(); i++) { try { valueIntArray[i] = Integer.parseInt(valueList.get(i)); } catch (NumberFormatException nfe) { // Not a valid integer errPw.println(tag + "Unable to parse " + valueList.get(i) + " as an integer."); return null; } } } bundle.putIntArray(key, valueIntArray); break; } case LONG: { try { bundle.putLong(key, Long.parseLong(valueList.get(0))); } catch (NumberFormatException nfe) { // Not a valid long errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type); return null; } break; } case LONG_ARRAY: { long[] valueLongArray = null; if (valueList.size() > 0) { valueLongArray = new long[valueList.size()]; for (int i = 0; i < valueList.size(); i++) { try { valueLongArray[i] = Long.parseLong(valueList.get(i)); } catch (NumberFormatException nfe) { // Not a valid long errPw.println( tag + "Unable to parse " + valueList.get(i) + " as a long"); return null; } } } bundle.putLongArray(key, valueLongArray); break; } case STRING: { String value = null; if (valueList.size() > 0) { value = valueList.get(0); } bundle.putString(key, value); break; } case STRING_ARRAY: { String[] valueStringArray = null; if (valueList.size() > 0) { valueStringArray = new String[valueList.size()]; valueList.toArray(valueStringArray); } bundle.putStringArray(key, valueStringArray); break; } } return bundle; } private int handleEndBlockSuppressionCommand() { if (!checkShellUid()) { return -1; } if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) { BlockedNumberContract.SystemContract.endBlockSuppression(mContext); } return 0; } private int handleEuiccCommand() { String arg = getNextArg(); if (arg == null) { onHelpEuicc(); return 0; } switch (arg) { case EUICC_SET_UI_COMPONENT: { return handleEuiccServiceCommand(); } } return -1; } private int handleEuiccServiceCommand() { String uiComponent = getNextArg(); String packageName = getNextArg(); if (packageName == null || uiComponent == null) { return -1; } EuiccUiDispatcherActivity.setTestEuiccUiComponent(packageName, uiComponent); if (VDBG) { Log.v(LOG_TAG, "euicc set-euicc-uicomponent " + uiComponent +" " + packageName); } return 0; } private int handleRestartModemCommand() { // Verify that the user is allowed to run the command. Only allowed in rooted device in a // non user build. if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { getErrPrintWriter().println("RestartModem: Permission denied."); return -1; } boolean result = TelephonyManager.getDefault().rebootRadio(); getOutPrintWriter().println(result); return result ? 0 : -1; } private int handleGetImei() { // Verify that the user is allowed to run the command. Only allowed in rooted device in a // non user build. if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { getErrPrintWriter().println("Device IMEI: Permission denied."); return -1; } final long identity = Binder.clearCallingIdentity(); String imei = null; String arg = getNextArg(); if (arg != null) { try { int specifiedSlotIndex = Integer.parseInt(arg); imei = TelephonyManager.from(mContext).getImei(specifiedSlotIndex); } catch (NumberFormatException exception) { PrintWriter errPw = getErrPrintWriter(); errPw.println("-s requires an integer as slot index."); return -1; } } else { imei = TelephonyManager.from(mContext).getImei(); } getOutPrintWriter().println("Device IMEI: " + imei); Binder.restoreCallingIdentity(identity); return 0; } private int handleUnattendedReboot() { // Verify that the user is allowed to run the command. Only allowed in rooted device in a // non user build. if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { getErrPrintWriter().println("UnattendedReboot: Permission denied."); return -1; } int result = TelephonyManager.getDefault().prepareForUnattendedReboot(); getOutPrintWriter().println("result: " + result); return result != TelephonyManager.PREPARE_UNATTENDED_REBOOT_ERROR ? 0 : -1; } private int handleGetSimSlotsMapping() { // Verify that the user is allowed to run the command. Only allowed in rooted device in a // non user build. if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { getErrPrintWriter().println("GetSimSlotsMapping: Permission denied."); return -1; } TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class); String result = telephonyManager.getSimSlotMapping().toString(); getOutPrintWriter().println("simSlotsMapping: " + result); return 0; } private int handleGbaCommand() { String arg = getNextArg(); if (arg == null) { onHelpGba(); return 0; } switch (arg) { case GBA_SET_SERVICE: { return handleGbaSetServiceCommand(); } case GBA_GET_SERVICE: { return handleGbaGetServiceCommand(); } case GBA_SET_RELEASE_TIME: { return handleGbaSetReleaseCommand(); } case GBA_GET_RELEASE_TIME: { return handleGbaGetReleaseCommand(); } } return -1; } private int getSubId(String cmd) { int slotId = getDefaultSlot(); String opt = getNextOption(); if (opt != null && opt.equals("-s")) { try { slotId = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { getErrPrintWriter().println(cmd + " requires an integer as a SLOT_ID."); return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } } return SubscriptionManager.getSubscriptionId(slotId); } private int handleGbaSetServiceCommand() { int subId = getSubId("gba set-service"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } String packageName = getNextArg(); try { if (packageName == null) { packageName = ""; } boolean result = mInterface.setBoundGbaServiceOverride(subId, packageName); if (VDBG) { Log.v(LOG_TAG, "gba set-service -s " + subId + " " + packageName + ", result=" + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "gba set-service " + subId + " " + packageName + ", error" + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleGbaGetServiceCommand() { String result; int subId = getSubId("gba get-service"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } try { result = mInterface.getBoundGbaService(subId); } catch (RemoteException e) { return -1; } if (VDBG) { Log.v(LOG_TAG, "gba get-service -s " + subId + ", returned: " + result); } getOutPrintWriter().println(result); return 0; } private int handleGbaSetReleaseCommand() { //the release time value could be -1 int subId = getRemainingArgsCount() > 1 ? getSubId("gba set-release") : SubscriptionManager.getDefaultSubscriptionId(); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } String intervalStr = getNextArg(); if (intervalStr == null) { return -1; } try { int interval = Integer.parseInt(intervalStr); boolean result = mInterface.setGbaReleaseTimeOverride(subId, interval); if (VDBG) { Log.v(LOG_TAG, "gba set-release -s " + subId + " " + intervalStr + ", result=" + result); } getOutPrintWriter().println(result); } catch (NumberFormatException | RemoteException e) { Log.w(LOG_TAG, "gba set-release -s " + subId + " " + intervalStr + ", error" + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleGbaGetReleaseCommand() { int subId = getSubId("gba get-release"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } int result = 0; try { result = mInterface.getGbaReleaseTime(subId); } catch (RemoteException e) { return -1; } if (VDBG) { Log.v(LOG_TAG, "gba get-release -s " + subId + ", returned: " + result); } getOutPrintWriter().println(result); return 0; } private int handleSingleRegistrationConfigCommand() { String arg = getNextArg(); if (arg == null) { onHelpSrc(); return 0; } switch (arg) { case SRC_SET_TEST_ENABLED: { return handleSrcSetTestEnabledCommand(); } case SRC_GET_TEST_ENABLED: { return handleSrcGetTestEnabledCommand(); } case SRC_SET_DEVICE_ENABLED: { return handleSrcSetDeviceEnabledCommand(); } case SRC_GET_DEVICE_ENABLED: { return handleSrcGetDeviceEnabledCommand(); } case SRC_SET_CARRIER_ENABLED: { return handleSrcSetCarrierEnabledCommand(); } case SRC_GET_CARRIER_ENABLED: { return handleSrcGetCarrierEnabledCommand(); } case SRC_SET_FEATURE_ENABLED: { return handleSrcSetFeatureValidationCommand(); } case SRC_GET_FEATURE_ENABLED: { return handleSrcGetFeatureValidationCommand(); } } return -1; } private int handleRcsUceCommand() { String arg = getNextArg(); if (arg == null) { onHelpUce(); return 0; } switch (arg) { case UCE_REMOVE_EAB_CONTACT: return handleRemovingEabContactCommand(); case UCE_GET_EAB_CONTACT: return handleGettingEabContactCommand(); case UCE_GET_EAB_CAPABILITY: return handleGettingEabCapabilityCommand(); case UCE_GET_DEVICE_ENABLED: return handleUceGetDeviceEnabledCommand(); case UCE_SET_DEVICE_ENABLED: return handleUceSetDeviceEnabledCommand(); case UCE_OVERRIDE_PUBLISH_CAPS: return handleUceOverridePublishCaps(); case UCE_GET_LAST_PIDF_XML: return handleUceGetPidfXml(); case UCE_REMOVE_REQUEST_DISALLOWED_STATUS: return handleUceRemoveRequestDisallowedStatus(); case UCE_SET_CAPABILITY_REQUEST_TIMEOUT: return handleUceSetCapRequestTimeout(); } return -1; } private int handleRemovingEabContactCommand() { int subId = getSubId("uce remove-eab-contact"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } String phoneNumber = getNextArgRequired(); if (TextUtils.isEmpty(phoneNumber)) { return -1; } int result = 0; try { result = mInterface.removeContactFromEab(subId, phoneNumber); } catch (RemoteException e) { Log.w(LOG_TAG, "uce remove-eab-contact -s " + subId + ", error " + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } if (VDBG) { Log.v(LOG_TAG, "uce remove-eab-contact -s " + subId + ", result: " + result); } return 0; } private int handleGettingEabContactCommand() { String phoneNumber = getNextArgRequired(); if (TextUtils.isEmpty(phoneNumber)) { return -1; } String result = ""; try { result = mInterface.getContactFromEab(phoneNumber); } catch (RemoteException e) { Log.w(LOG_TAG, "uce get-eab-contact, error " + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } if (VDBG) { Log.v(LOG_TAG, "uce get-eab-contact, result: " + result); } getOutPrintWriter().println(result); return 0; } private int handleGettingEabCapabilityCommand() { String phoneNumber = getNextArgRequired(); if (TextUtils.isEmpty(phoneNumber)) { return -1; } String result = ""; try { result = mInterface.getCapabilityFromEab(phoneNumber); } catch (RemoteException e) { Log.w(LOG_TAG, "uce get-eab-capability, error " + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } if (VDBG) { Log.v(LOG_TAG, "uce get-eab-capability, result: " + result); } getOutPrintWriter().println(result); return 0; } private int handleUceGetDeviceEnabledCommand() { boolean result = false; try { result = mInterface.getDeviceUceEnabled(); } catch (RemoteException e) { Log.w(LOG_TAG, "uce get-device-enabled, error " + e.getMessage()); return -1; } if (VDBG) { Log.v(LOG_TAG, "uce get-device-enabled, returned: " + result); } getOutPrintWriter().println(result); return 0; } private int handleUceSetDeviceEnabledCommand() { String enabledStr = getNextArg(); if (TextUtils.isEmpty(enabledStr)) { return -1; } try { boolean isEnabled = Boolean.parseBoolean(enabledStr); mInterface.setDeviceUceEnabled(isEnabled); if (VDBG) { Log.v(LOG_TAG, "uce set-device-enabled " + enabledStr + ", done"); } } catch (NumberFormatException | RemoteException e) { Log.w(LOG_TAG, "uce set-device-enabled " + enabledStr + ", error " + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleUceRemoveRequestDisallowedStatus() { int subId = getSubId("uce remove-request-disallowed-status"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { Log.w(LOG_TAG, "uce remove-request-disallowed-status, Invalid subscription ID"); return -1; } boolean result; try { result = mInterface.removeUceRequestDisallowedStatus(subId); } catch (RemoteException e) { Log.w(LOG_TAG, "uce remove-request-disallowed-status, error " + e.getMessage()); return -1; } if (VDBG) { Log.v(LOG_TAG, "uce remove-request-disallowed-status, returned: " + result); } getOutPrintWriter().println(result); return 0; } private int handleUceSetCapRequestTimeout() { int subId = getSubId("uce set-capabilities-request-timeout"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { Log.w(LOG_TAG, "uce set-capabilities-request-timeout, Invalid subscription ID"); return -1; } long timeoutAfterMs = Long.valueOf(getNextArg()); boolean result; try { result = mInterface.setCapabilitiesRequestTimeout(subId, timeoutAfterMs); } catch (RemoteException e) { Log.w(LOG_TAG, "uce set-capabilities-request-timeout, error " + e.getMessage()); return -1; } if (VDBG) { Log.v(LOG_TAG, "uce set-capabilities-request-timeout, returned: " + result); } getOutPrintWriter().println(result); return 0; } private int handleSrcSetTestEnabledCommand() { String enabledStr = getNextArg(); if (enabledStr == null) { return -1; } try { mInterface.setRcsSingleRegistrationTestModeEnabled(Boolean.parseBoolean(enabledStr)); if (VDBG) { Log.v(LOG_TAG, "src set-test-enabled " + enabledStr + ", done"); } getOutPrintWriter().println("Done"); } catch (NumberFormatException | RemoteException e) { Log.w(LOG_TAG, "src set-test-enabled " + enabledStr + ", error" + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSrcGetTestEnabledCommand() { boolean result = false; try { result = mInterface.getRcsSingleRegistrationTestModeEnabled(); } catch (RemoteException e) { return -1; } if (VDBG) { Log.v(LOG_TAG, "src get-test-enabled, returned: " + result); } getOutPrintWriter().println(result); return 0; } private int handleUceOverridePublishCaps() { int subId = getSubId("uce override-published-caps"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } //uce override-published-caps [-s SLOT_ID] add|remove|clear|list [CAPABILITIES] String operation = getNextArgRequired(); String caps = getNextArg(); if (!"add".equals(operation) && !"remove".equals(operation) && !"clear".equals(operation) && !"list".equals(operation)) { getErrPrintWriter().println("Invalid operation: " + operation); return -1; } // add/remove requires capabilities to be specified. if ((!"clear".equals(operation) && !"list".equals(operation)) && TextUtils.isEmpty(caps)) { getErrPrintWriter().println("\"" + operation + "\" requires capabilities to be " + "specified"); return -1; } ArraySet capSet = new ArraySet<>(); if (!TextUtils.isEmpty(caps)) { String[] capArray = caps.split(":"); for (String cap : capArray) { // Allow unknown tags to be passed in as well. capSet.addAll(TEST_FEATURE_TAG_MAP.getOrDefault(cap, Collections.singleton(cap))); } } RcsContactUceCapability result = null; try { switch (operation) { case "add": result = mInterface.addUceRegistrationOverrideShell(subId, new ArrayList<>(capSet)); break; case "remove": result = mInterface.removeUceRegistrationOverrideShell(subId, new ArrayList<>(capSet)); break; case "clear": result = mInterface.clearUceRegistrationOverrideShell(subId); break; case "list": result = mInterface.getLatestRcsContactUceCapabilityShell(subId); break; } } catch (RemoteException e) { Log.w(LOG_TAG, "uce override-published-caps, error " + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } catch (ServiceSpecificException sse) { // Reconstruct ImsException ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode); Log.w(LOG_TAG, "uce override-published-caps, error " + imsException); getErrPrintWriter().println("Exception: " + imsException); return -1; } if (result == null) { getErrPrintWriter().println("Service not available"); return -1; } getOutPrintWriter().println(result); return 0; } private int handleUceGetPidfXml() { int subId = getSubId("uce get-last-publish-pidf"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } String result; try { result = mInterface.getLastUcePidfXmlShell(subId); } catch (RemoteException e) { Log.w(LOG_TAG, "uce get-last-publish-pidf, error " + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } catch (ServiceSpecificException sse) { // Reconstruct ImsException ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode); Log.w(LOG_TAG, "uce get-last-publish-pidf error " + imsException); getErrPrintWriter().println("Exception: " + imsException); return -1; } if (result == null) { getErrPrintWriter().println("Service not available"); return -1; } getOutPrintWriter().println(result); return 0; } private int handleSrcSetDeviceEnabledCommand() { String enabledStr = getNextArg(); if (enabledStr == null) { return -1; } try { mInterface.setDeviceSingleRegistrationEnabledOverride(enabledStr); if (VDBG) { Log.v(LOG_TAG, "src set-device-enabled " + enabledStr + ", done"); } getOutPrintWriter().println("Done"); } catch (NumberFormatException | RemoteException e) { Log.w(LOG_TAG, "src set-device-enabled " + enabledStr + ", error" + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSrcGetDeviceEnabledCommand() { boolean result = false; try { result = mInterface.getDeviceSingleRegistrationEnabled(); } catch (RemoteException e) { return -1; } if (VDBG) { Log.v(LOG_TAG, "src get-device-enabled, returned: " + result); } getOutPrintWriter().println(result); return 0; } private int handleSrcSetCarrierEnabledCommand() { //the release time value could be -1 int subId = getRemainingArgsCount() > 1 ? getSubId("src set-carrier-enabled") : SubscriptionManager.getDefaultSubscriptionId(); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } String enabledStr = getNextArg(); if (enabledStr == null) { return -1; } try { boolean result = mInterface.setCarrierSingleRegistrationEnabledOverride(subId, enabledStr); if (VDBG) { Log.v(LOG_TAG, "src set-carrier-enabled -s " + subId + " " + enabledStr + ", result=" + result); } getOutPrintWriter().println(result); } catch (NumberFormatException | RemoteException e) { Log.w(LOG_TAG, "src set-carrier-enabled -s " + subId + " " + enabledStr + ", error" + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSrcGetCarrierEnabledCommand() { int subId = getSubId("src get-carrier-enabled"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } boolean result = false; try { result = mInterface.getCarrierSingleRegistrationEnabled(subId); } catch (RemoteException e) { return -1; } if (VDBG) { Log.v(LOG_TAG, "src get-carrier-enabled -s " + subId + ", returned: " + result); } getOutPrintWriter().println(result); return 0; } private int handleSrcSetFeatureValidationCommand() { //the release time value could be -1 int subId = getRemainingArgsCount() > 1 ? getSubId("src set-feature-validation") : SubscriptionManager.getDefaultSubscriptionId(); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } String enabledStr = getNextArg(); if (enabledStr == null) { return -1; } try { boolean result = mInterface.setImsFeatureValidationOverride(subId, enabledStr); if (VDBG) { Log.v(LOG_TAG, "src set-feature-validation -s " + subId + " " + enabledStr + ", result=" + result); } getOutPrintWriter().println(result); } catch (NumberFormatException | RemoteException e) { Log.w(LOG_TAG, "src set-feature-validation -s " + subId + " " + enabledStr + ", error" + e.getMessage()); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSrcGetFeatureValidationCommand() { int subId = getSubId("src get-feature-validation"); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return -1; } Boolean result = false; try { result = mInterface.getImsFeatureValidationOverride(subId); } catch (RemoteException e) { return -1; } if (VDBG) { Log.v(LOG_TAG, "src get-feature-validation -s " + subId + ", returned: " + result); } getOutPrintWriter().println(result); return 0; } private void onHelpCallComposer() { PrintWriter pw = getOutPrintWriter(); pw.println("Call composer commands"); pw.println(" callcomposer test-mode enable|disable|query"); pw.println(" Enables or disables test mode for call composer. In test mode, picture"); pw.println(" upload/download from carrier servers is disabled, and operations are"); pw.println(" performed using emulated local files instead."); pw.println(" callcomposer simulate-outgoing-call [subId] [UUID]"); pw.println(" Simulates an outgoing call being placed with the picture ID as"); pw.println(" the provided UUID. This triggers storage to the call log."); pw.println(" callcomposer user-setting [subId] enable|disable|query"); pw.println(" Enables or disables the user setting for call composer, as set by"); pw.println(" TelephonyManager#setCallComposerStatus."); } private int handleCallComposerCommand() { String arg = getNextArg(); if (arg == null) { onHelpCallComposer(); return 0; } mContext.enforceCallingPermission(Manifest.permission.MODIFY_PHONE_STATE, "MODIFY_PHONE_STATE required for call composer shell cmds"); switch (arg) { case CALL_COMPOSER_TEST_MODE: { String enabledStr = getNextArg(); if (ENABLE.equals(enabledStr)) { CallComposerPictureManager.sTestMode = true; } else if (DISABLE.equals(enabledStr)) { CallComposerPictureManager.sTestMode = false; } else if (QUERY.equals(enabledStr)) { getOutPrintWriter().println(CallComposerPictureManager.sTestMode); } else { onHelpCallComposer(); return 1; } break; } case CALL_COMPOSER_SIMULATE_CALL: { int subscriptionId = Integer.valueOf(getNextArg()); String uuidString = getNextArg(); UUID uuid = UUID.fromString(uuidString); CompletableFuture storageUriFuture = new CompletableFuture<>(); Binder.withCleanCallingIdentity(() -> { CallComposerPictureManager.getInstance(mContext, subscriptionId) .storeUploadedPictureToCallLog(uuid, storageUriFuture::complete); }); try { Uri uri = storageUriFuture.get(); getOutPrintWriter().println(String.valueOf(uri)); } catch (Exception e) { throw new RuntimeException(e); } break; } case CALL_COMPOSER_USER_SETTING: { try { int subscriptionId = Integer.valueOf(getNextArg()); String enabledStr = getNextArg(); if (ENABLE.equals(enabledStr)) { mInterface.setCallComposerStatus(subscriptionId, TelephonyManager.CALL_COMPOSER_STATUS_ON); } else if (DISABLE.equals(enabledStr)) { mInterface.setCallComposerStatus(subscriptionId, TelephonyManager.CALL_COMPOSER_STATUS_OFF); } else if (QUERY.equals(enabledStr)) { getOutPrintWriter().println(mInterface.getCallComposerStatus(subscriptionId) == TelephonyManager.CALL_COMPOSER_STATUS_ON); } else { onHelpCallComposer(); return 1; } } catch (RemoteException e) { e.printStackTrace(getOutPrintWriter()); return 1; } break; } } return 0; } private int handleHasCarrierPrivilegesCommand() { String packageName = getNextArgRequired(); boolean hasCarrierPrivileges; final long token = Binder.clearCallingIdentity(); try { hasCarrierPrivileges = mInterface.checkCarrierPrivilegesForPackageAnyPhone(packageName) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; } catch (RemoteException e) { Log.w(LOG_TAG, HAS_CARRIER_PRIVILEGES_COMMAND + " exception", e); getErrPrintWriter().println("Exception: " + e.getMessage()); return -1; } finally { Binder.restoreCallingIdentity(token); } getOutPrintWriter().println(hasCarrierPrivileges); return 0; } private int handleAllowedNetworkTypesCommand(String command) { if (!checkShellUid()) { return -1; } PrintWriter errPw = getErrPrintWriter(); String tag = command + ": "; String opt; int subId = -1; Log.v(LOG_TAG, command + " start"); while ((opt = getNextOption()) != null) { if (opt.equals("-s")) { try { subId = slotStringToSubId(tag, getNextArgRequired()); if (!SubscriptionManager.isValidSubscriptionId(subId)) { errPw.println(tag + "No valid subscription found."); return -1; } } catch (IllegalArgumentException e) { // Missing slot id errPw.println(tag + "SLOT_ID expected after -s."); return -1; } } else { errPw.println(tag + "Unknown option " + opt); return -1; } } if (GET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) { return handleGetAllowedNetworkTypesCommand(subId); } if (SET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) { return handleSetAllowedNetworkTypesCommand(subId); } return -1; } private int handleGetAllowedNetworkTypesCommand(int subId) { PrintWriter errPw = getErrPrintWriter(); long result = -1; try { if (mInterface != null) { result = mInterface.getAllowedNetworkTypesForReason(subId, TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER); } else { throw new IllegalStateException("telephony service is null."); } } catch (RemoteException e) { Log.e(TAG, "getAllowedNetworkTypesForReason RemoteException" + e); errPw.println(GET_ALLOWED_NETWORK_TYPES_FOR_USER + "RemoteException " + e); return -1; } getOutPrintWriter().println(TelephonyManager.convertNetworkTypeBitmaskToString(result)); return 0; } private int handleSetAllowedNetworkTypesCommand(int subId) { PrintWriter errPw = getErrPrintWriter(); String bitmaskString = getNextArg(); if (TextUtils.isEmpty(bitmaskString)) { errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No NETWORK_TYPES_BITMASK"); return -1; } long allowedNetworkTypes = convertNetworkTypeBitmaskFromStringToLong(bitmaskString); if (allowedNetworkTypes < 0) { errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No valid NETWORK_TYPES_BITMASK"); return -1; } boolean result = false; try { if (mInterface != null) { result = mInterface.setAllowedNetworkTypesForReason(subId, TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, allowedNetworkTypes); } else { throw new IllegalStateException("telephony service is null."); } } catch (RemoteException e) { Log.e(TAG, "setAllowedNetworkTypesForReason RemoteException" + e); errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " RemoteException " + e); return -1; } String resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " failed"; if (result) { resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " completed"; } getOutPrintWriter().println(resultMessage); return 0; } private long convertNetworkTypeBitmaskFromStringToLong(String bitmaskString) { if (TextUtils.isEmpty(bitmaskString)) { return -1; } if (VDBG) { Log.v(LOG_TAG, "AllowedNetworkTypes:" + bitmaskString + ", length: " + bitmaskString.length()); } try { return Long.parseLong(bitmaskString, 2); } catch (NumberFormatException e) { Log.e(LOG_TAG, "AllowedNetworkTypes: " + e); return -1; } } private int handleRadioSetModemServiceCommand() { PrintWriter errPw = getErrPrintWriter(); String serviceName = null; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { serviceName = getNextArgRequired(); break; } } } try { boolean result = mInterface.setModemService(serviceName); if (VDBG) { Log.v(LOG_TAG, "RadioSetModemService " + serviceName + ", result = " + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "RadioSetModemService: " + serviceName + ", error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleRadioGetModemServiceCommand() { PrintWriter errPw = getErrPrintWriter(); String result; try { result = mInterface.getModemService(); getOutPrintWriter().println(result); } catch (RemoteException e) { errPw.println("Exception: " + e.getMessage()); return -1; } if (VDBG) { Log.v(LOG_TAG, "RadioGetModemService, result = " + result); } return 0; } private int handleRadioCommand() { String arg = getNextArg(); if (arg == null) { onHelpRadio(); return 0; } switch (arg) { case RADIO_SET_MODEM_SERVICE: return handleRadioSetModemServiceCommand(); case RADIO_GET_MODEM_SERVICE: return handleRadioGetModemServiceCommand(); } return -1; } private int handleSetSatelliteServicePackageNameCommand() { PrintWriter errPw = getErrPrintWriter(); String serviceName = null; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { serviceName = getNextArgRequired(); break; } } } Log.d(LOG_TAG, "handleSetSatelliteServicePackageNameCommand: serviceName=" + serviceName); try { boolean result = mInterface.setSatelliteServicePackageName(serviceName); if (VDBG) { Log.v(LOG_TAG, "SetSatelliteServicePackageName " + serviceName + ", result = " + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "SetSatelliteServicePackageName: " + serviceName + ", error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetSatelliteGatewayServicePackageNameCommand() { PrintWriter errPw = getErrPrintWriter(); String serviceName = null; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": { serviceName = getNextArgRequired(); break; } } } Log.d(LOG_TAG, "handleSetSatelliteGatewayServicePackageNameCommand: serviceName=" + serviceName); try { boolean result = mInterface.setSatelliteGatewayServicePackageName(serviceName); if (VDBG) { Log.v(LOG_TAG, "setSatelliteGatewayServicePackageName " + serviceName + ", result = " + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "setSatelliteGatewayServicePackageName: " + serviceName + ", error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetSatellitePointingUiClassNameCommand() { PrintWriter errPw = getErrPrintWriter(); String packageName = null; String className = null; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-p": { packageName = getNextArgRequired(); break; } case "-c": { className = getNextArgRequired(); break; } } } Log.d(LOG_TAG, "handleSetSatellitePointingUiClassNameCommand: packageName=" + packageName + ", className=" + className); try { boolean result = mInterface.setSatellitePointingUiClassName(packageName, className); if (VDBG) { Log.v(LOG_TAG, "setSatellitePointingUiClassName result =" + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.e(LOG_TAG, "setSatellitePointingUiClassName: " + packageName + ", error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetEmergencyCallToSatelliteHandoverType() { PrintWriter errPw = getErrPrintWriter(); int handoverType = -1; int delaySeconds = 0; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-t": { try { handoverType = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { errPw.println("SetEmergencyCallToSatelliteHandoverType: require an integer" + " for handoverType"); return -1; } break; } case "-d": { try { delaySeconds = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { errPw.println("SetEmergencyCallToSatelliteHandoverType: require an integer" + " for delaySeconds"); return -1; } break; } } } Log.d(LOG_TAG, "handleSetEmergencyCallToSatelliteHandoverType: handoverType=" + handoverType + ", delaySeconds=" + delaySeconds); try { boolean result = mInterface.setEmergencyCallToSatelliteHandoverType(handoverType, delaySeconds); if (VDBG) { Log.v(LOG_TAG, "setEmergencyCallToSatelliteHandoverType result =" + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.e(LOG_TAG, "setEmergencyCallToSatelliteHandoverType: " + handoverType + ", error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetSatelliteListeningTimeoutDuration() { PrintWriter errPw = getErrPrintWriter(); long timeoutMillis = 0; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-t": { timeoutMillis = Long.parseLong(getNextArgRequired()); break; } } } Log.d(LOG_TAG, "handleSetSatelliteListeningTimeoutDuration: timeoutMillis=" + timeoutMillis); try { boolean result = mInterface.setSatelliteListeningTimeoutDuration(timeoutMillis); if (VDBG) { Log.v(LOG_TAG, "setSatelliteListeningTimeoutDuration " + timeoutMillis + ", result = " + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "setSatelliteListeningTimeoutDuration: " + timeoutMillis + ", error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetDatagramControllerTimeoutDuration() { PrintWriter errPw = getErrPrintWriter(); boolean reset = false; int timeoutType = 0; long timeoutMillis = 0; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-d": { timeoutMillis = Long.parseLong(getNextArgRequired()); break; } case "-r": { reset = true; break; } case "-t": { timeoutType = Integer.parseInt(getNextArgRequired()); break; } } } Log.d(LOG_TAG, "setDatagramControllerTimeoutDuration: timeoutMillis=" + timeoutMillis + ", reset=" + reset + ", timeoutType=" + timeoutType); try { boolean result = mInterface.setDatagramControllerTimeoutDuration( reset, timeoutType, timeoutMillis); if (VDBG) { Log.v(LOG_TAG, "setDatagramControllerTimeoutDuration " + timeoutMillis + ", result = " + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "setDatagramControllerTimeoutDuration: " + timeoutMillis + ", error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetDatagramControllerBooleanConfig() { PrintWriter errPw = getErrPrintWriter(); boolean reset = false; int booleanType = 0; boolean enable = false; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-d": { enable = Boolean.parseBoolean(getNextArgRequired()); break; } case "-r": { reset = true; break; } case "-t": { booleanType = Integer.parseInt(getNextArgRequired()); break; } } } Log.d(LOG_TAG, "setDatagramControllerBooleanConfig: enable=" + enable + ", reset=" + reset + ", booleanType=" + booleanType); try { boolean result = mInterface.setDatagramControllerBooleanConfig( reset, booleanType, enable); if (VDBG) { Log.v(LOG_TAG, "setDatagramControllerBooleanConfig result = " + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "setDatagramControllerBooleanConfig: error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetSatelliteControllerTimeoutDuration() { PrintWriter errPw = getErrPrintWriter(); boolean reset = false; int timeoutType = 0; long timeoutMillis = 0; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-d": { timeoutMillis = Long.parseLong(getNextArgRequired()); break; } case "-r": { reset = true; break; } case "-t": { timeoutType = Integer.parseInt(getNextArgRequired()); break; } } } Log.d(LOG_TAG, "setSatelliteControllerTimeoutDuration: timeoutMillis=" + timeoutMillis + ", reset=" + reset + ", timeoutType=" + timeoutType); try { boolean result = mInterface.setSatelliteControllerTimeoutDuration( reset, timeoutType, timeoutMillis); if (VDBG) { Log.v(LOG_TAG, "setSatelliteControllerTimeoutDuration " + timeoutMillis + ", result = " + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "setSatelliteControllerTimeoutDuration: " + timeoutMillis + ", error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetShouldSendDatagramToModemInDemoMode() { PrintWriter errPw = getErrPrintWriter(); String opt; boolean shouldSendToDemoMode; if ((opt = getNextArg()) == null) { errPw.println( "adb shell cmd phone set-should-send-datagram-to-modem-in-demo-mode :" + " Invalid Argument"); return -1; } else { switch (opt) { case "true": { shouldSendToDemoMode = true; break; } case "false": { shouldSendToDemoMode = false; break; } default: errPw.println( "adb shell cmd phone set-should-send-datagram-to-modem-in-demo-mode :" + " Invalid Argument"); return -1; } } Log.d(LOG_TAG, "handleSetShouldSendDatagramToModemInDemoMode(" + shouldSendToDemoMode + ")"); try { boolean result = mInterface.setShouldSendDatagramToModemInDemoMode( shouldSendToDemoMode); if (VDBG) { Log.v(LOG_TAG, "handleSetShouldSendDatagramToModemInDemoMode returns: " + result); } getOutPrintWriter().println(false); } catch (RemoteException e) { Log.w(LOG_TAG, "setShouldSendDatagramToModemInDemoMode(" + shouldSendToDemoMode + "), error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetSatelliteAccessControlOverlayConfigs() { PrintWriter errPw = getErrPrintWriter(); boolean reset = false; boolean isAllowed = false; String s2CellFile = null; long locationFreshDurationNanos = 0; List satelliteCountryCodes = null; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-r": { reset = true; break; } case "-a": { isAllowed = true; break; } case "-f": { s2CellFile = getNextArgRequired(); break; } case "-d": { locationFreshDurationNanos = Long.parseLong(getNextArgRequired()); break; } case "-c": { String countryCodeStr = getNextArgRequired(); satelliteCountryCodes = Arrays.asList(countryCodeStr.split(",")); break; } } } Log.d(LOG_TAG, "handleSetSatelliteAccessControlOverlayConfigs: reset=" + reset + ", isAllowed=" + isAllowed + ", s2CellFile=" + s2CellFile + ", locationFreshDurationNanos=" + locationFreshDurationNanos + ", satelliteCountryCodes=" + satelliteCountryCodes); try { boolean result = mInterface.setSatelliteAccessControlOverlayConfigs(reset, isAllowed, s2CellFile, locationFreshDurationNanos, satelliteCountryCodes); if (VDBG) { Log.v(LOG_TAG, "setSatelliteAccessControlOverlayConfigs result =" + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.e(LOG_TAG, "setSatelliteAccessControlOverlayConfigs: ex=" + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetCountryCodes() { PrintWriter errPw = getErrPrintWriter(); List currentNetworkCountryCodes = new ArrayList<>(); String locationCountryCode = null; long locationCountryCodeTimestampNanos = 0; Map cachedNetworkCountryCodes = new HashMap<>(); boolean reset = false; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-r": { reset = true; break; } case "-n": { String countryCodeStr = getNextArgRequired(); currentNetworkCountryCodes = Arrays.asList(countryCodeStr.split(",")); break; } case "-c": { String cachedNetworkCountryCodeStr = getNextArgRequired(); cachedNetworkCountryCodes = parseStringLongMap(cachedNetworkCountryCodeStr); break; } case "-l": { locationCountryCode = getNextArgRequired(); break; } case "-t": { locationCountryCodeTimestampNanos = Long.parseLong(getNextArgRequired()); break; } } } Log.d(LOG_TAG, "setCountryCodes: locationCountryCode=" + locationCountryCode + ", locationCountryCodeTimestampNanos=" + locationCountryCodeTimestampNanos + ", currentNetworkCountryCodes=" + currentNetworkCountryCodes); try { boolean result = mInterface.setCountryCodes(reset, currentNetworkCountryCodes, cachedNetworkCountryCodes, locationCountryCode, locationCountryCodeTimestampNanos); if (VDBG) { Log.v(LOG_TAG, "setCountryCodes result =" + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.e(LOG_TAG, "setCountryCodes: ex=" + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetOemEnabledSatelliteProvisionStatus() { PrintWriter errPw = getErrPrintWriter(); boolean isProvisioned = false; boolean reset = true; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-p": { try { isProvisioned = Boolean.parseBoolean(getNextArgRequired()); reset = false; } catch (Exception e) { errPw.println("setOemEnabledSatelliteProvisionStatus requires a boolean " + "after -p indicating provision status"); return -1; } } } } Log.d(LOG_TAG, "setOemEnabledSatelliteProvisionStatus: reset=" + reset + ", isProvisioned=" + isProvisioned); try { boolean result = mInterface.setOemEnabledSatelliteProvisionStatus(reset, isProvisioned); if (VDBG) { Log.v(LOG_TAG, "setOemEnabledSatelliteProvisionStatus result = " + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "setOemEnabledSatelliteProvisionStatus: error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache() { PrintWriter errPw = getErrPrintWriter(); String opt; String state; if ((opt = getNextArg()) == null) { errPw.println( "adb shell cmd phone set-is-satellite-communication-allowed-for-current" + "-location-cache :" + " Invalid Argument"); return -1; } else { switch (opt) { case "-a": { state = "cache_allowed"; break; } case "-n": { state = "cache_clear_and_not_allowed"; break; } case "-c": { state = "clear_cache_only"; break; } default: errPw.println( "adb shell cmd phone set-is-satellite-communication-allowed-for-current" + "-location-cache :" + " Invalid Argument"); return -1; } } Log.d(LOG_TAG, "handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache(" + state + ")"); try { boolean result = mInterface.setIsSatelliteCommunicationAllowedForCurrentLocationCache( state); if (VDBG) { Log.v(LOG_TAG, "setIsSatelliteCommunicationAllowedForCurrentLocationCache " + "returns: " + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "setIsSatelliteCommunicationAllowedForCurrentLocationCache(" + state + "), error = " + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } /** * Sample inputStr = "US,UK,CA;2,1,3" * Sample output: {[US,2], [UK,1], [CA,3]} */ @NonNull private Map parseStringLongMap(@Nullable String inputStr) { Map result = new HashMap<>(); if (!TextUtils.isEmpty(inputStr)) { String[] stringLongArr = inputStr.split(";"); if (stringLongArr.length != 2) { Log.e(LOG_TAG, "parseStringLongMap: invalid inputStr=" + inputStr); return result; } String[] stringArr = stringLongArr[0].split(","); String[] longArr = stringLongArr[1].split(","); if (stringArr.length != longArr.length) { Log.e(LOG_TAG, "parseStringLongMap: invalid inputStr=" + inputStr); return result; } for (int i = 0; i < stringArr.length; i++) { try { result.put(stringArr[i], Long.parseLong(longArr[i])); } catch (Exception ex) { Log.e(LOG_TAG, "parseStringLongMap: invalid inputStr=" + inputStr + ", ex=" + ex); return result; } } } return result; } private int handleCarrierRestrictionStatusCommand() { try { String MOCK_MODEM_SERVICE_NAME = "android.telephony.mockmodem.MockModemService"; if (!(checkShellUid() && MOCK_MODEM_SERVICE_NAME.equalsIgnoreCase( mInterface.getModemService()))) { Log.v(LOG_TAG, "handleCarrierRestrictionStatusCommand, MockModem service check fails or " + " checkShellUid fails"); return -1; } } catch (RemoteException ex) { ex.printStackTrace(); } String callerInfo = getNextOption(); CarrierAllowListInfo allowListInfo = CarrierAllowListInfo.loadInstance(mContext); if (TextUtils.isEmpty(callerInfo)) { // reset the Json content after testing allowListInfo.updateJsonForTest(null); return 0; } if (callerInfo.startsWith("--")) { callerInfo = callerInfo.replace("--", ""); } String params[] = callerInfo.split(","); StringBuffer jsonStrBuffer = new StringBuffer(); String tokens; for (int index = 0; index < params.length; index++) { tokens = convertToJsonString(index, params[index]); if (TextUtils.isEmpty(tokens)) { // received wrong format from CTS if (VDBG) { Log.v(LOG_TAG, "handleCarrierRestrictionStatusCommand, Shell command parsing error"); } return -1; } jsonStrBuffer.append(tokens); } int result = allowListInfo.updateJsonForTest(jsonStrBuffer.toString()); return result; } // set-carrier-service-package-override private int setCarrierServicePackageOverride() { PrintWriter errPw = getErrPrintWriter(); int subId = SubscriptionManager.getDefaultSubscriptionId(); String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": try { subId = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { errPw.println( "set-carrier-service-package-override requires an integer as a" + " subscription ID."); return -1; } break; } } String packageName = getNextArg(); if (packageName == null) { errPw.println("set-carrier-service-package-override requires a override package name."); return -1; } try { mInterface.setCarrierServicePackageOverride( subId, packageName, mContext.getOpPackageName()); if (VDBG) { Log.v( LOG_TAG, "set-carrier-service-package-override -s " + subId + " " + packageName); } } catch (RemoteException | IllegalArgumentException | IllegalStateException e) { Log.w( LOG_TAG, "set-carrier-service-package-override -s " + subId + " " + packageName + ", error" + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } // clear-carrier-service-package-override private int clearCarrierServicePackageOverride() { PrintWriter errPw = getErrPrintWriter(); int subId = SubscriptionManager.getDefaultSubscriptionId(); String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-s": try { subId = Integer.parseInt(getNextArgRequired()); } catch (NumberFormatException e) { errPw.println( "clear-carrier-service-package-override requires an integer as a" + " subscription ID."); return -1; } break; } } try { mInterface.setCarrierServicePackageOverride(subId, null, mContext.getOpPackageName()); if (VDBG) { Log.v(LOG_TAG, "clear-carrier-service-package-override -s " + subId); } } catch (RemoteException | IllegalArgumentException | IllegalStateException e) { Log.w( LOG_TAG, "clear-carrier-service-package-override -s " + subId + ", error" + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } private int handleDomainSelectionCommand() { String arg = getNextArg(); if (arg == null) { onHelpDomainSelection(); return 0; } switch (arg) { case DOMAIN_SELECTION_SET_SERVICE_OVERRIDE: { return handleDomainSelectionSetServiceOverrideCommand(); } case DOMAIN_SELECTION_CLEAR_SERVICE_OVERRIDE: { return handleDomainSelectionClearServiceOverrideCommand(); } } return -1; } // domainselection set-dss-override private int handleDomainSelectionSetServiceOverrideCommand() { PrintWriter errPw = getErrPrintWriter(); String componentName = getNextArg(); try { boolean result = mInterface.setDomainSelectionServiceOverride( ComponentName.unflattenFromString(componentName)); if (VDBG) { Log.v(LOG_TAG, "domainselection set-dss-override " + componentName + ", result=" + result); } getOutPrintWriter().println(result); } catch (Exception e) { Log.w(LOG_TAG, "domainselection set-dss-override " + componentName + ", error=" + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } // domainselection clear-dss-override private int handleDomainSelectionClearServiceOverrideCommand() { PrintWriter errPw = getErrPrintWriter(); try { boolean result = mInterface.clearDomainSelectionServiceOverride(); if (VDBG) { Log.v(LOG_TAG, "domainselection clear-dss-override result=" + result); } getOutPrintWriter().println(result); } catch (RemoteException e) { Log.w(LOG_TAG, "domainselection clear-dss-override error=" + e.getMessage()); errPw.println("Exception: " + e.getMessage()); return -1; } return 0; } /** * Building the string that can be used to build the JsonObject which supports to stub the data * in CarrierAllowListInfo for CTS testing. sample format is like * {"com.android.example":{"carrierIds":[10000],"callerSHA256Ids":["XXXXXXXXXXXXXX"]}} */ private String convertToJsonString(int index, String param) { String token[] = param.split(":"); String jSonString; switch (index) { case 0: jSonString = "{" + QUOTES + token[1] + QUOTES + ":"; break; case 1: jSonString = "{" + QUOTES + token[0] + QUOTES + ":" + "[" + token[1] + "],"; break; case 2: jSonString = QUOTES + token[0] + QUOTES + ":" + "[" + QUOTES + token[1] + QUOTES + "]}}"; break; default: jSonString = null; } return jSonString; } }