blob: 33d0721b95403ec6ca4769eeeadf53008373d721 [file] [log] [blame]
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.phone;
18
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010019import android.content.Context;
Hall Liud892bec2018-11-30 14:51:45 -080020import android.os.Binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010021import android.os.PersistableBundle;
Hall Liud892bec2018-11-30 14:51:45 -080022import android.os.Process;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070023import android.os.RemoteException;
Shuo Qian489d9282020-07-09 11:30:03 -070024import android.provider.BlockedNumberContract;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010025import android.telephony.CarrierConfigManager;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070026import android.telephony.SubscriptionManager;
sqian9d4df8b2019-01-15 18:32:07 -080027import android.telephony.emergency.EmergencyNumber;
Brad Ebinger24c29992019-12-05 13:03:21 -080028import android.telephony.ims.feature.ImsFeature;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070029import android.util.Log;
30
31import com.android.internal.telephony.ITelephony;
Qiong Liuf25799b2020-09-10 10:13:46 +080032import com.android.internal.telephony.Phone;
33import com.android.internal.telephony.PhoneFactory;
sqian9d4df8b2019-01-15 18:32:07 -080034import com.android.internal.telephony.emergency.EmergencyNumberTracker;
Meng Wangc4f61042019-11-21 10:51:05 -080035import com.android.internal.telephony.util.TelephonyUtils;
Chiachang Wang99890092020-11-04 10:59:17 +080036import com.android.modules.utils.BasicShellCommandHandler;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070037
38import java.io.PrintWriter;
sqian9d4df8b2019-01-15 18:32:07 -080039import java.util.ArrayList;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010040import java.util.HashMap;
Brad Ebinger24c29992019-12-05 13:03:21 -080041import java.util.List;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010042import java.util.Map;
43import java.util.TreeSet;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070044
45/**
46 * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
47 * permission checks have been done before onCommand was called. Make sure any commands processed
48 * here also contain the appropriate permissions checks.
49 */
50
Hall Liua1548bd2019-12-24 14:14:12 -080051public class TelephonyShellCommand extends BasicShellCommandHandler {
Brad Ebinger4dc095a2018-04-03 15:17:52 -070052
53 private static final String LOG_TAG = "TelephonyShellCommand";
54 // Don't commit with this true.
55 private static final boolean VDBG = true;
Brad Ebinger0aa2f242018-04-12 09:49:23 -070056 private static final int DEFAULT_PHONE_ID = 0;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070057
58 private static final String IMS_SUBCOMMAND = "ims";
Hall Liud892bec2018-11-30 14:51:45 -080059 private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
sqian9d4df8b2019-01-15 18:32:07 -080060 private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
Shuo Qian489d9282020-07-09 11:30:03 -070061 private static final String END_BLOCK_SUPPRESSION = "end-block-suppression";
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010062 private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
Shuo Qianf5125122019-12-16 17:03:07 -080063 private static final String DATA_TEST_MODE = "data";
64 private static final String DATA_ENABLE = "enable";
65 private static final String DATA_DISABLE = "disable";
Hall Liud892bec2018-11-30 14:51:45 -080066
Brad Ebinger999d3302020-11-25 14:31:39 -080067 private static final String IMS_SET_IMS_SERVICE = "set-ims-service";
68 private static final String IMS_GET_IMS_SERVICE = "get-ims-service";
69 private static final String IMS_CLEAR_SERVICE_OVERRIDE = "clear-ims-service-override";
Brad Ebinger4dc095a2018-04-03 15:17:52 -070070 private static final String IMS_ENABLE = "enable";
71 private static final String IMS_DISABLE = "disable";
Tyler Gunn7bcdc742019-10-04 15:56:59 -070072 // Used to disable or enable processing of conference event package data from the network.
73 // This is handy for testing scenarios where CEP data does not exist on a network which does
74 // support CEP data.
75 private static final String IMS_CEP = "conference-event-package";
Brad Ebinger4dc095a2018-04-03 15:17:52 -070076
Hall Liud892bec2018-11-30 14:51:45 -080077 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
Hall Liuca5af3a2018-12-04 16:58:23 -080078 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
Hall Liud892bec2018-11-30 14:51:45 -080079
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010080 private static final String CC_GET_VALUE = "get-value";
81 private static final String CC_SET_VALUE = "set-value";
82 private static final String CC_CLEAR_VALUES = "clear-values";
83
Brad Ebinger4dc095a2018-04-03 15:17:52 -070084 // Take advantage of existing methods that already contain permissions checks when possible.
85 private final ITelephony mInterface;
86
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010087 private SubscriptionManager mSubscriptionManager;
88 private CarrierConfigManager mCarrierConfigManager;
Shuo Qian489d9282020-07-09 11:30:03 -070089 private Context mContext;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010090
91 private enum CcType {
92 BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
93 STRING_ARRAY, UNKNOWN
94 }
95
Torbjorn Eklund723527a2019-02-13 11:16:25 +010096 private class CcOptionParseResult {
97 public int mSubId;
98 public boolean mPersistent;
99 }
100
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100101 // Maps carrier config keys to type. It is possible to infer the type for most carrier config
102 // keys by looking at the end of the string which usually tells the type.
103 // For instance: "xxxx_string", "xxxx_string_array", etc.
104 // The carrier config keys in this map does not follow this convention. It is therefore not
105 // possible to infer the type for these keys by looking at the string.
106 private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
107 put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
108 put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
109 put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
110 put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
111 put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
112 put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
113 put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
114 put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
115 put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
116 put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
117 put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
118 CcType.STRING);
119 put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
120 CcType.STRING_ARRAY);
121 put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
122 CcType.STRING_ARRAY);
123 put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
124 put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
125 put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
126 put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
127 put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
128 put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
129 put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
130 put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
131 }
132 };
133
134 public TelephonyShellCommand(ITelephony binder, Context context) {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700135 mInterface = binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100136 mCarrierConfigManager =
137 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
138 mSubscriptionManager = (SubscriptionManager)
139 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Shuo Qian489d9282020-07-09 11:30:03 -0700140 mContext = context;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700141 }
142
143 @Override
144 public int onCommand(String cmd) {
145 if (cmd == null) {
146 return handleDefaultCommands(null);
147 }
148
149 switch (cmd) {
150 case IMS_SUBCOMMAND: {
151 return handleImsCommand();
152 }
Hall Liud892bec2018-11-30 14:51:45 -0800153 case NUMBER_VERIFICATION_SUBCOMMAND:
154 return handleNumberVerificationCommand();
sqian9d4df8b2019-01-15 18:32:07 -0800155 case EMERGENCY_NUMBER_TEST_MODE:
156 return handleEmergencyNumberTestModeCommand();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100157 case CARRIER_CONFIG_SUBCOMMAND: {
158 return handleCcCommand();
159 }
Shuo Qianf5125122019-12-16 17:03:07 -0800160 case DATA_TEST_MODE:
161 return handleDataTestModeCommand();
Shuo Qian489d9282020-07-09 11:30:03 -0700162 case END_BLOCK_SUPPRESSION:
163 return handleEndBlockSuppressionCommand();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700164 default: {
165 return handleDefaultCommands(cmd);
166 }
167 }
168 }
169
170 @Override
171 public void onHelp() {
172 PrintWriter pw = getOutPrintWriter();
173 pw.println("Telephony Commands:");
174 pw.println(" help");
175 pw.println(" Print this help text.");
176 pw.println(" ims");
177 pw.println(" IMS Commands.");
sqian9d4df8b2019-01-15 18:32:07 -0800178 pw.println(" emergency-number-test-mode");
179 pw.println(" Emergency Number Test Mode Commands.");
Shuo Qian489d9282020-07-09 11:30:03 -0700180 pw.println(" end-block-suppression");
181 pw.println(" End Block Suppression command.");
Shuo Qianf5125122019-12-16 17:03:07 -0800182 pw.println(" data");
183 pw.println(" Data Test Mode Commands.");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100184 pw.println(" cc");
185 pw.println(" Carrier Config Commands.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700186 onHelpIms();
sqian9d4df8b2019-01-15 18:32:07 -0800187 onHelpEmergencyNumber();
Shuo Qian489d9282020-07-09 11:30:03 -0700188 onHelpEndBlockSupperssion();
Shuo Qianf5125122019-12-16 17:03:07 -0800189 onHelpDataTestMode();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100190 onHelpCc();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700191 }
192
193 private void onHelpIms() {
194 PrintWriter pw = getOutPrintWriter();
195 pw.println("IMS Commands:");
Brad Ebinger24c29992019-12-05 13:03:21 -0800196 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700197 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
198 pw.println(" ImsService. Options are:");
199 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
200 pw.println(" is specified, it will choose the default voice SIM slot.");
201 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
202 pw.println(" -d: Override the ImsService defined in the device overlay.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800203 pw.println(" -f: Set the feature that this override if for, if no option is");
204 pw.println(" specified, the new package name will be used for all features.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700205 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
206 pw.println(" Gets the package name of the currently defined ImsService.");
207 pw.println(" Options are:");
208 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
209 pw.println(" is specified, it will choose the default voice SIM slot.");
210 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
Peter Kalauskas1defdc32020-09-03 19:20:26 +0000211 pw.println(" -d: The ImsService defined as the device default ImsService.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800212 pw.println(" -f: The feature type that the query will be requested for. If none is");
213 pw.println(" specified, the returned package name will correspond to MMTEL.");
Brad Ebinger999d3302020-11-25 14:31:39 -0800214 pw.println(" ims clear-ims-service-override [-s SLOT_ID]");
215 pw.println(" Clear all carrier ImsService overrides. This does not work for device ");
216 pw.println(" configuration overrides. Options are:");
217 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
218 pw.println(" is specified, it will choose the default voice SIM slot.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700219 pw.println(" ims enable [-s SLOT_ID]");
220 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
221 pw.println(" if none is specified.");
222 pw.println(" ims disable [-s SLOT_ID]");
223 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
224 pw.println(" slot if none is specified.");
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700225 pw.println(" ims conference-event-package [enable/disable]");
226 pw.println(" enables or disables handling or network conference event package data.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700227 }
228
Hall Liud892bec2018-11-30 14:51:45 -0800229 private void onHelpNumberVerification() {
230 PrintWriter pw = getOutPrintWriter();
231 pw.println("Number verification commands");
232 pw.println(" numverify override-package PACKAGE_NAME;");
233 pw.println(" Set the authorized package for number verification.");
234 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800235 pw.println(" numverify fake-call NUMBER;");
236 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
237 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800238 }
239
Shuo Qianf5125122019-12-16 17:03:07 -0800240 private void onHelpDataTestMode() {
241 PrintWriter pw = getOutPrintWriter();
242 pw.println("Mobile Data Test Mode Commands:");
243 pw.println(" data enable: enable mobile data connectivity");
244 pw.println(" data disable: disable mobile data connectivity");
245 }
246
sqian9d4df8b2019-01-15 18:32:07 -0800247 private void onHelpEmergencyNumber() {
248 PrintWriter pw = getOutPrintWriter();
249 pw.println("Emergency Number Test Mode Commands:");
250 pw.println(" emergency-number-test-mode ");
251 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
252 + " the test mode");
253 pw.println(" -a <emergency number address>: add an emergency number address for the"
sqian9121f982019-03-14 19:45:39 -0700254 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800255 pw.println(" -c: clear the emergency number list in the test mode.");
256 pw.println(" -r <emergency number address>: remove an existing emergency number"
sqian9121f982019-03-14 19:45:39 -0700257 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800258 pw.println(" -p: get the full emergency number list in the test mode.");
259 }
260
Shuo Qian489d9282020-07-09 11:30:03 -0700261 private void onHelpEndBlockSupperssion() {
262 PrintWriter pw = getOutPrintWriter();
263 pw.println("End Block Suppression command:");
264 pw.println(" end-block-suppression: disable suppressing blocking by contact");
265 pw.println(" with emergency services.");
266 }
267
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100268 private void onHelpCc() {
269 PrintWriter pw = getOutPrintWriter();
270 pw.println("Carrier Config Commands:");
271 pw.println(" cc get-value [-s SLOT_ID] [KEY]");
272 pw.println(" Print carrier config values.");
273 pw.println(" Options are:");
274 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
275 pw.println(" is specified, it will choose the default voice SIM slot.");
276 pw.println(" KEY: The key to the carrier config value to print. All values are printed");
277 pw.println(" if KEY is not specified.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100278 pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100279 pw.println(" Set carrier config KEY to NEW_VALUE.");
280 pw.println(" Options are:");
281 pw.println(" -s: The SIM slot ID to set carrier config value for. If no option");
282 pw.println(" is specified, it will choose the default voice SIM slot.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100283 pw.println(" -p: Value will be stored persistent");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100284 pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be");
285 pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with");
286 pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
287 pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\"");
288 pw.println(" cc clear-values [-s SLOT_ID]");
289 pw.println(" Clear all carrier override values that has previously been set");
290 pw.println(" with set-value");
291 pw.println(" Options are:");
292 pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option");
293 pw.println(" is specified, it will choose the default voice SIM slot.");
294 }
295
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700296 private int handleImsCommand() {
297 String arg = getNextArg();
298 if (arg == null) {
299 onHelpIms();
300 return 0;
301 }
302
303 switch (arg) {
Brad Ebinger999d3302020-11-25 14:31:39 -0800304 case IMS_SET_IMS_SERVICE: {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700305 return handleImsSetServiceCommand();
306 }
Brad Ebinger999d3302020-11-25 14:31:39 -0800307 case IMS_GET_IMS_SERVICE: {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700308 return handleImsGetServiceCommand();
309 }
Brad Ebinger999d3302020-11-25 14:31:39 -0800310 case IMS_CLEAR_SERVICE_OVERRIDE: {
311 return handleImsClearCarrierServiceCommand();
312 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700313 case IMS_ENABLE: {
314 return handleEnableIms();
315 }
316 case IMS_DISABLE: {
317 return handleDisableIms();
318 }
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700319 case IMS_CEP: {
320 return handleCepChange();
321 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700322 }
323
324 return -1;
325 }
326
Shuo Qianf5125122019-12-16 17:03:07 -0800327 private int handleDataTestModeCommand() {
328 PrintWriter errPw = getErrPrintWriter();
329 String arg = getNextArgRequired();
330 if (arg == null) {
331 onHelpDataTestMode();
332 return 0;
333 }
334 switch (arg) {
335 case DATA_ENABLE: {
336 try {
337 mInterface.enableDataConnectivity();
338 } catch (RemoteException ex) {
339 Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
340 errPw.println("Exception: " + ex.getMessage());
341 return -1;
342 }
343 break;
344 }
345 case DATA_DISABLE: {
346 try {
347 mInterface.disableDataConnectivity();
348 } catch (RemoteException ex) {
349 Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
350 errPw.println("Exception: " + ex.getMessage());
351 return -1;
352 }
353 break;
354 }
355 default:
356 onHelpDataTestMode();
357 break;
358 }
359 return 0;
360 }
361
sqian9d4df8b2019-01-15 18:32:07 -0800362 private int handleEmergencyNumberTestModeCommand() {
363 PrintWriter errPw = getErrPrintWriter();
364 String opt = getNextOption();
365 if (opt == null) {
366 onHelpEmergencyNumber();
367 return 0;
368 }
369
370 switch (opt) {
371 case "-a": {
372 String emergencyNumberCmd = getNextArgRequired();
373 if (emergencyNumberCmd == null
374 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700375 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800376 + " to be specified after -a in the command ");
377 return -1;
378 }
379 try {
380 mInterface.updateEmergencyNumberListTestMode(
381 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
382 new EmergencyNumber(emergencyNumberCmd, "", "",
383 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
384 new ArrayList<String>(),
385 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
386 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
387 } catch (RemoteException ex) {
388 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
389 + ", error " + ex.getMessage());
390 errPw.println("Exception: " + ex.getMessage());
391 return -1;
392 }
393 break;
394 }
395 case "-c": {
396 try {
397 mInterface.updateEmergencyNumberListTestMode(
398 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
399 } catch (RemoteException ex) {
400 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
401 errPw.println("Exception: " + ex.getMessage());
402 return -1;
403 }
404 break;
405 }
406 case "-r": {
407 String emergencyNumberCmd = getNextArgRequired();
408 if (emergencyNumberCmd == null
409 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700410 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800411 + " to be specified after -r in the command ");
412 return -1;
413 }
414 try {
415 mInterface.updateEmergencyNumberListTestMode(
416 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
417 new EmergencyNumber(emergencyNumberCmd, "", "",
418 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
419 new ArrayList<String>(),
420 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
421 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
422 } catch (RemoteException ex) {
423 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
424 + ", error " + ex.getMessage());
425 errPw.println("Exception: " + ex.getMessage());
426 return -1;
427 }
428 break;
429 }
430 case "-p": {
431 try {
432 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
433 } catch (RemoteException ex) {
434 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
435 errPw.println("Exception: " + ex.getMessage());
436 return -1;
437 }
438 break;
439 }
440 default:
441 onHelpEmergencyNumber();
442 break;
443 }
444 return 0;
445 }
446
Hall Liud892bec2018-11-30 14:51:45 -0800447 private int handleNumberVerificationCommand() {
448 String arg = getNextArg();
449 if (arg == null) {
450 onHelpNumberVerification();
451 return 0;
452 }
453
Hall Liuca5af3a2018-12-04 16:58:23 -0800454 if (!checkShellUid()) {
455 return -1;
456 }
457
Hall Liud892bec2018-11-30 14:51:45 -0800458 switch (arg) {
459 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800460 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
461 return 0;
462 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800463 case NUMBER_VERIFICATION_FAKE_CALL: {
464 boolean val = NumberVerificationManager.getInstance()
465 .checkIncomingCall(getNextArg());
466 getOutPrintWriter().println(val ? "1" : "0");
467 return 0;
468 }
Hall Liud892bec2018-11-30 14:51:45 -0800469 }
470
471 return -1;
472 }
473
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700474 // ims set-ims-service
475 private int handleImsSetServiceCommand() {
476 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700477 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700478 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800479 List<Integer> featuresList = new ArrayList<>();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700480
481 String opt;
482 while ((opt = getNextOption()) != null) {
483 switch (opt) {
484 case "-s": {
485 try {
486 slotId = Integer.parseInt(getNextArgRequired());
487 } catch (NumberFormatException e) {
488 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
489 return -1;
490 }
491 break;
492 }
493 case "-c": {
494 isCarrierService = true;
495 break;
496 }
497 case "-d": {
498 isCarrierService = false;
499 break;
500 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800501 case "-f": {
502 String featureString = getNextArgRequired();
503 String[] features = featureString.split(",");
504 for (int i = 0; i < features.length; i++) {
505 try {
506 Integer result = Integer.parseInt(features[i]);
507 if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
508 || result >= ImsFeature.FEATURE_MAX) {
509 errPw.println("ims set-ims-service -f " + result
510 + " is an invalid feature.");
511 return -1;
512 }
513 featuresList.add(result);
514 } catch (NumberFormatException e) {
515 errPw.println("ims set-ims-service -f tried to parse " + features[i]
516 + " as an integer.");
517 return -1;
518 }
519 }
520 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700521 }
522 }
523 // Mandatory param, either -c or -d
524 if (isCarrierService == null) {
525 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
526 return -1;
527 }
528
529 String packageName = getNextArg();
530
531 try {
532 if (packageName == null) {
533 packageName = "";
534 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800535 int[] featureArray = new int[featuresList.size()];
536 for (int i = 0; i < featuresList.size(); i++) {
537 featureArray[i] = featuresList.get(i);
538 }
539 boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
540 featureArray, packageName);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700541 if (VDBG) {
542 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800543 + (isCarrierService ? "-c " : "-d ")
544 + "-f " + featuresList + " "
545 + packageName + ", result=" + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700546 }
547 getOutPrintWriter().println(result);
548 } catch (RemoteException e) {
549 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800550 + (isCarrierService ? "-c " : "-d ")
551 + "-f " + featuresList + " "
552 + packageName + ", error" + e.getMessage());
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700553 errPw.println("Exception: " + e.getMessage());
554 return -1;
555 }
556 return 0;
557 }
558
Brad Ebinger999d3302020-11-25 14:31:39 -0800559 // ims clear-ims-service-override
560 private int handleImsClearCarrierServiceCommand() {
561 PrintWriter errPw = getErrPrintWriter();
562 int slotId = getDefaultSlot();
563
564 String opt;
565 while ((opt = getNextOption()) != null) {
566 switch (opt) {
567 case "-s": {
568 try {
569 slotId = Integer.parseInt(getNextArgRequired());
570 } catch (NumberFormatException e) {
571 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
572 return -1;
573 }
574 break;
575 }
576 }
577 }
578
579 try {
580 boolean result = mInterface.clearCarrierImsServiceOverride(slotId);
581 if (VDBG) {
582 Log.v(LOG_TAG, "ims clear-ims-service-override -s " + slotId
583 + ", result=" + result);
584 }
585 getOutPrintWriter().println(result);
586 } catch (RemoteException e) {
587 Log.w(LOG_TAG, "ims clear-ims-service-override -s " + slotId
588 + ", error" + e.getMessage());
589 errPw.println("Exception: " + e.getMessage());
590 return -1;
591 }
592 return 0;
593 }
594
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700595 // ims get-ims-service
596 private int handleImsGetServiceCommand() {
597 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700598 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700599 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800600 Integer featureType = ImsFeature.FEATURE_MMTEL;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700601
602 String opt;
603 while ((opt = getNextOption()) != null) {
604 switch (opt) {
605 case "-s": {
606 try {
607 slotId = Integer.parseInt(getNextArgRequired());
608 } catch (NumberFormatException e) {
609 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
610 return -1;
611 }
612 break;
613 }
614 case "-c": {
615 isCarrierService = true;
616 break;
617 }
618 case "-d": {
619 isCarrierService = false;
620 break;
621 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800622 case "-f": {
623 try {
624 featureType = Integer.parseInt(getNextArg());
625 } catch (NumberFormatException e) {
626 errPw.println("ims get-ims-service -f requires valid integer as feature.");
627 return -1;
628 }
629 if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
630 || featureType >= ImsFeature.FEATURE_MAX) {
631 errPw.println("ims get-ims-service -f invalid feature.");
632 return -1;
633 }
634 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700635 }
636 }
637 // Mandatory param, either -c or -d
638 if (isCarrierService == null) {
Brad Ebinger24c29992019-12-05 13:03:21 -0800639 errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700640 return -1;
641 }
642
643 String result;
644 try {
Brad Ebinger24c29992019-12-05 13:03:21 -0800645 result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700646 } catch (RemoteException e) {
647 return -1;
648 }
649 if (VDBG) {
650 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800651 + (isCarrierService ? "-c " : "-d ")
652 + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
653 + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700654 }
655 getOutPrintWriter().println(result);
656 return 0;
657 }
658
659 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700660 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700661 String opt;
662 while ((opt = getNextOption()) != null) {
663 switch (opt) {
664 case "-s": {
665 try {
666 slotId = Integer.parseInt(getNextArgRequired());
667 } catch (NumberFormatException e) {
668 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
669 return -1;
670 }
671 break;
672 }
673 }
674 }
675 try {
676 mInterface.enableIms(slotId);
677 } catch (RemoteException e) {
678 return -1;
679 }
680 if (VDBG) {
681 Log.v(LOG_TAG, "ims enable -s " + slotId);
682 }
683 return 0;
684 }
685
686 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700687 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700688 String opt;
689 while ((opt = getNextOption()) != null) {
690 switch (opt) {
691 case "-s": {
692 try {
693 slotId = Integer.parseInt(getNextArgRequired());
694 } catch (NumberFormatException e) {
695 getErrPrintWriter().println(
696 "ims disable requires an integer as a SLOT_ID.");
697 return -1;
698 }
699 break;
700 }
701 }
702 }
703 try {
704 mInterface.disableIms(slotId);
705 } catch (RemoteException e) {
706 return -1;
707 }
708 if (VDBG) {
709 Log.v(LOG_TAG, "ims disable -s " + slotId);
710 }
711 return 0;
712 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700713
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700714 private int handleCepChange() {
715 Log.i(LOG_TAG, "handleCepChange");
716 String opt = getNextArg();
717 if (opt == null) {
718 return -1;
719 }
720 boolean isCepEnabled = opt.equals("enable");
721
722 try {
723 mInterface.setCepEnabled(isCepEnabled);
724 } catch (RemoteException e) {
725 return -1;
726 }
727 return 0;
728 }
729
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700730 private int getDefaultSlot() {
731 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
732 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
733 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
734 // If there is no default, default to slot 0.
735 slotId = DEFAULT_PHONE_ID;
736 }
737 return slotId;
738 }
sqian2fff4a32018-11-05 14:18:37 -0800739
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100740 // Parse options related to Carrier Config Commands.
741 private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100742 PrintWriter errPw = getErrPrintWriter();
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100743 CcOptionParseResult result = new CcOptionParseResult();
744 result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
745 result.mPersistent = false;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100746
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100747 String opt;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100748 while ((opt = getNextOption()) != null) {
749 switch (opt) {
750 case "-s": {
751 try {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100752 result.mSubId = slotStringToSubId(tag, getNextArgRequired());
753 if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
754 errPw.println(tag + "No valid subscription found.");
755 return null;
756 }
757
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100758 } catch (IllegalArgumentException e) {
759 // Missing slot id
760 errPw.println(tag + "SLOT_ID expected after -s.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100761 return null;
762 }
763 break;
764 }
765 case "-p": {
766 if (allowOptionPersistent) {
767 result.mPersistent = true;
768 } else {
769 errPw.println(tag + "Unexpected option " + opt);
770 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100771 }
772 break;
773 }
774 default: {
775 errPw.println(tag + "Unknown option " + opt);
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100776 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100777 }
778 }
779 }
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100780 return result;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100781 }
782
783 private int slotStringToSubId(String tag, String slotString) {
784 int slotId = -1;
785 try {
786 slotId = Integer.parseInt(slotString);
787 } catch (NumberFormatException e) {
Qiong Liuf25799b2020-09-10 10:13:46 +0800788 getErrPrintWriter().println(tag + slotString + " is not a valid number for SLOT_ID.");
789 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
790 }
791
792 if (!SubscriptionManager.isValidPhoneId(slotId)) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100793 getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
794 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
795 }
796
Qiong Liuf25799b2020-09-10 10:13:46 +0800797 Phone phone = PhoneFactory.getPhone(slotId);
798 if (phone == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100799 getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
800 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
801 }
Qiong Liuf25799b2020-09-10 10:13:46 +0800802 return phone.getSubId();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100803 }
804
Hall Liud892bec2018-11-30 14:51:45 -0800805 private boolean checkShellUid() {
Hall Liu2ddfc7e2018-12-06 13:09:45 -0800806 // adb can run as root or as shell, depending on whether the device is rooted.
807 return Binder.getCallingUid() == Process.SHELL_UID
808 || Binder.getCallingUid() == Process.ROOT_UID;
Hall Liud892bec2018-11-30 14:51:45 -0800809 }
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100810
811 private int handleCcCommand() {
812 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
813 // non user build.
Meng Wangc4f61042019-11-21 10:51:05 -0800814 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100815 getErrPrintWriter().println("cc: Permission denied.");
816 return -1;
817 }
818
819 String arg = getNextArg();
820 if (arg == null) {
821 onHelpCc();
822 return 0;
823 }
824
825 switch (arg) {
826 case CC_GET_VALUE: {
827 return handleCcGetValue();
828 }
829 case CC_SET_VALUE: {
830 return handleCcSetValue();
831 }
832 case CC_CLEAR_VALUES: {
833 return handleCcClearValues();
834 }
835 default: {
836 getErrPrintWriter().println("cc: Unknown argument: " + arg);
837 }
838 }
839 return -1;
840 }
841
842 // cc get-value
843 private int handleCcGetValue() {
844 PrintWriter errPw = getErrPrintWriter();
845 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
846 String key = null;
847
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100848 // Parse all options
849 CcOptionParseResult options = parseCcOptions(tag, false);
850 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100851 return -1;
852 }
853
854 // Get bundle containing all carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100855 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100856 if (bundle == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100857 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100858 return -1;
859 }
860
861 // Get the key.
862 key = getNextArg();
863 if (key != null) {
864 // A key was provided. Verify if it is a valid key
865 if (!bundle.containsKey(key)) {
866 errPw.println(tag + key + " is not a valid key.");
867 return -1;
868 }
869
870 // Print the carrier config value for key.
871 getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
872 } else {
873 // No key provided. Show all values.
874 // Iterate over a sorted list of all carrier config keys and print them.
875 TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
876 for (String k : sortedSet) {
877 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
878 }
879 }
880 return 0;
881 }
882
883 // cc set-value
884 private int handleCcSetValue() {
885 PrintWriter errPw = getErrPrintWriter();
886 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
887
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100888 // Parse all options
889 CcOptionParseResult options = parseCcOptions(tag, true);
890 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100891 return -1;
892 }
893
894 // Get bundle containing all current carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100895 PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100896 if (originalValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100897 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100898 return -1;
899 }
900
901 // Get the key.
902 String key = getNextArg();
903 if (key == null || key.equals("")) {
904 errPw.println(tag + "KEY is missing");
905 return -1;
906 }
907
908 // Verify if the key is valid
909 if (!originalValues.containsKey(key)) {
910 errPw.println(tag + key + " is not a valid key.");
911 return -1;
912 }
913
914 // Remaining arguments is a list of new values. Add them all into an ArrayList.
915 ArrayList<String> valueList = new ArrayList<String>();
916 while (peekNextArg() != null) {
917 valueList.add(getNextArg());
918 }
919
920 // Find the type of the carrier config value
921 CcType type = getType(tag, key, originalValues);
922 if (type == CcType.UNKNOWN) {
923 errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
924 return -1;
925 }
926
927 // Create an override bundle containing the key and value that should be overriden.
928 PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
929 if (overrideBundle == null) {
930 return -1;
931 }
932
933 // Override the value
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100934 mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100935
936 // Find bundle containing all new carrier configuration values after the override.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100937 PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100938 if (newValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100939 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100940 return -1;
941 }
942
943 // Print the original and new value.
944 String originalValueString = ccValueToString(key, type, originalValues);
945 String newValueString = ccValueToString(key, type, newValues);
946 getOutPrintWriter().println("Previous value: \n" + originalValueString);
947 getOutPrintWriter().println("New value: \n" + newValueString);
948
949 return 0;
950 }
951
952 // cc clear-values
953 private int handleCcClearValues() {
954 PrintWriter errPw = getErrPrintWriter();
955 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
956
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100957 // Parse all options
958 CcOptionParseResult options = parseCcOptions(tag, false);
959 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100960 return -1;
961 }
962
963 // Clear all values that has previously been set.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100964 mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100965 getOutPrintWriter()
966 .println("All previously set carrier config override values has been cleared");
967 return 0;
968 }
969
970 private CcType getType(String tag, String key, PersistableBundle bundle) {
971 // Find the type by checking the type of the current value stored in the bundle.
972 Object value = bundle.get(key);
973
974 if (CC_TYPE_MAP.containsKey(key)) {
975 return CC_TYPE_MAP.get(key);
976 } else if (value != null) {
977 if (value instanceof Boolean) {
978 return CcType.BOOLEAN;
979 } else if (value instanceof Double) {
980 return CcType.DOUBLE;
981 } else if (value instanceof double[]) {
982 return CcType.DOUBLE_ARRAY;
983 } else if (value instanceof Integer) {
984 return CcType.INT;
985 } else if (value instanceof int[]) {
986 return CcType.INT_ARRAY;
987 } else if (value instanceof Long) {
988 return CcType.LONG;
989 } else if (value instanceof long[]) {
990 return CcType.LONG_ARRAY;
991 } else if (value instanceof String) {
992 return CcType.STRING;
993 } else if (value instanceof String[]) {
994 return CcType.STRING_ARRAY;
995 }
996 } else {
997 // Current value was null and can therefore not be used in order to find the type.
998 // Check the name of the key to infer the type. This check is not needed for primitive
999 // data types (boolean, double, int and long), since they can not be null.
1000 if (key.endsWith("double_array")) {
1001 return CcType.DOUBLE_ARRAY;
1002 }
1003 if (key.endsWith("int_array")) {
1004 return CcType.INT_ARRAY;
1005 }
1006 if (key.endsWith("long_array")) {
1007 return CcType.LONG_ARRAY;
1008 }
1009 if (key.endsWith("string")) {
1010 return CcType.STRING;
1011 }
1012 if (key.endsWith("string_array") || key.endsWith("strings")) {
1013 return CcType.STRING_ARRAY;
1014 }
1015 }
1016
1017 // Not possible to infer the type by looking at the current value or the key.
1018 PrintWriter errPw = getErrPrintWriter();
1019 errPw.println(tag + "ERROR: " + key + " has unknown type.");
1020 return CcType.UNKNOWN;
1021 }
1022
1023 private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
1024 String result;
1025 StringBuilder valueString = new StringBuilder();
1026 String typeString = type.toString();
1027 Object value = bundle.get(key);
1028
1029 if (value == null) {
1030 valueString.append("null");
1031 } else {
1032 switch (type) {
1033 case DOUBLE_ARRAY: {
1034 // Format the string representation of the int array as value1 value2......
1035 double[] valueArray = (double[]) value;
1036 for (int i = 0; i < valueArray.length; i++) {
1037 if (i != 0) {
1038 valueString.append(" ");
1039 }
1040 valueString.append(valueArray[i]);
1041 }
1042 break;
1043 }
1044 case INT_ARRAY: {
1045 // Format the string representation of the int array as value1 value2......
1046 int[] valueArray = (int[]) value;
1047 for (int i = 0; i < valueArray.length; i++) {
1048 if (i != 0) {
1049 valueString.append(" ");
1050 }
1051 valueString.append(valueArray[i]);
1052 }
1053 break;
1054 }
1055 case LONG_ARRAY: {
1056 // Format the string representation of the int array as value1 value2......
1057 long[] valueArray = (long[]) value;
1058 for (int i = 0; i < valueArray.length; i++) {
1059 if (i != 0) {
1060 valueString.append(" ");
1061 }
1062 valueString.append(valueArray[i]);
1063 }
1064 break;
1065 }
1066 case STRING: {
1067 valueString.append("\"" + value.toString() + "\"");
1068 break;
1069 }
1070 case STRING_ARRAY: {
1071 // Format the string representation of the string array as "value1" "value2"....
1072 String[] valueArray = (String[]) value;
1073 for (int i = 0; i < valueArray.length; i++) {
1074 if (i != 0) {
1075 valueString.append(" ");
1076 }
1077 if (valueArray[i] != null) {
1078 valueString.append("\"" + valueArray[i] + "\"");
1079 } else {
1080 valueString.append("null");
1081 }
1082 }
1083 break;
1084 }
1085 default: {
1086 valueString.append(value.toString());
1087 }
1088 }
1089 }
1090 return String.format("%-70s %-15s %s", key, typeString, valueString);
1091 }
1092
1093 private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
1094 ArrayList<String> valueList) {
1095 PrintWriter errPw = getErrPrintWriter();
1096 PersistableBundle bundle = new PersistableBundle();
1097
1098 // First verify that a valid number of values has been provided for the type.
1099 switch (type) {
1100 case BOOLEAN:
1101 case DOUBLE:
1102 case INT:
1103 case LONG: {
1104 if (valueList.size() != 1) {
1105 errPw.println(tag + "Expected 1 value for type " + type
1106 + ". Found: " + valueList.size());
1107 return null;
1108 }
1109 break;
1110 }
1111 case STRING: {
1112 if (valueList.size() > 1) {
1113 errPw.println(tag + "Expected 0 or 1 values for type " + type
1114 + ". Found: " + valueList.size());
1115 return null;
1116 }
1117 break;
1118 }
1119 }
1120
1121 // Parse the value according to type and add it to the Bundle.
1122 switch (type) {
1123 case BOOLEAN: {
1124 if ("true".equalsIgnoreCase(valueList.get(0))) {
1125 bundle.putBoolean(key, true);
1126 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
1127 bundle.putBoolean(key, false);
1128 } else {
1129 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1130 return null;
1131 }
1132 break;
1133 }
1134 case DOUBLE: {
1135 try {
1136 bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
1137 } catch (NumberFormatException nfe) {
1138 // Not a valid double
1139 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1140 return null;
1141 }
1142 break;
1143 }
1144 case DOUBLE_ARRAY: {
1145 double[] valueDoubleArray = null;
1146 if (valueList.size() > 0) {
1147 valueDoubleArray = new double[valueList.size()];
1148 for (int i = 0; i < valueList.size(); i++) {
1149 try {
1150 valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
1151 } catch (NumberFormatException nfe) {
1152 // Not a valid double
1153 errPw.println(
1154 tag + "Unable to parse " + valueList.get(i) + " as a double.");
1155 return null;
1156 }
1157 }
1158 }
1159 bundle.putDoubleArray(key, valueDoubleArray);
1160 break;
1161 }
1162 case INT: {
1163 try {
1164 bundle.putInt(key, Integer.parseInt(valueList.get(0)));
1165 } catch (NumberFormatException nfe) {
1166 // Not a valid integer
1167 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
1168 return null;
1169 }
1170 break;
1171 }
1172 case INT_ARRAY: {
1173 int[] valueIntArray = null;
1174 if (valueList.size() > 0) {
1175 valueIntArray = new int[valueList.size()];
1176 for (int i = 0; i < valueList.size(); i++) {
1177 try {
1178 valueIntArray[i] = Integer.parseInt(valueList.get(i));
1179 } catch (NumberFormatException nfe) {
1180 // Not a valid integer
1181 errPw.println(tag
1182 + "Unable to parse " + valueList.get(i) + " as an integer.");
1183 return null;
1184 }
1185 }
1186 }
1187 bundle.putIntArray(key, valueIntArray);
1188 break;
1189 }
1190 case LONG: {
1191 try {
1192 bundle.putLong(key, Long.parseLong(valueList.get(0)));
1193 } catch (NumberFormatException nfe) {
1194 // Not a valid long
1195 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1196 return null;
1197 }
1198 break;
1199 }
1200 case LONG_ARRAY: {
1201 long[] valueLongArray = null;
1202 if (valueList.size() > 0) {
1203 valueLongArray = new long[valueList.size()];
1204 for (int i = 0; i < valueList.size(); i++) {
1205 try {
1206 valueLongArray[i] = Long.parseLong(valueList.get(i));
1207 } catch (NumberFormatException nfe) {
1208 // Not a valid long
1209 errPw.println(
1210 tag + "Unable to parse " + valueList.get(i) + " as a long");
1211 return null;
1212 }
1213 }
1214 }
1215 bundle.putLongArray(key, valueLongArray);
1216 break;
1217 }
1218 case STRING: {
1219 String value = null;
1220 if (valueList.size() > 0) {
1221 value = valueList.get(0);
1222 }
1223 bundle.putString(key, value);
1224 break;
1225 }
1226 case STRING_ARRAY: {
1227 String[] valueStringArray = null;
1228 if (valueList.size() > 0) {
1229 valueStringArray = new String[valueList.size()];
1230 valueList.toArray(valueStringArray);
1231 }
1232 bundle.putStringArray(key, valueStringArray);
1233 break;
1234 }
1235 }
1236 return bundle;
1237 }
Shuo Qian489d9282020-07-09 11:30:03 -07001238
1239 private int handleEndBlockSuppressionCommand() {
1240 if (!checkShellUid()) {
1241 return -1;
1242 }
1243
1244 if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) {
1245 BlockedNumberContract.SystemContract.endBlockSuppression(mContext);
1246 }
1247 return 0;
1248 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001249}