blob: 8d670924834854af99e6b11f2569ef269d403228 [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
Hui Wang641e81c2020-10-12 12:14:23 -070084 private static final String GBA_SUBCOMMAND = "gba";
85 private static final String GBA_SET_SERVICE = "set-service";
86 private static final String GBA_GET_SERVICE = "get-service";
87 private static final String GBA_SET_RELEASE_TIME = "set-release";
88 private static final String GBA_GET_RELEASE_TIME = "get-release";
89
Brad Ebinger4dc095a2018-04-03 15:17:52 -070090 // Take advantage of existing methods that already contain permissions checks when possible.
91 private final ITelephony mInterface;
92
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010093 private SubscriptionManager mSubscriptionManager;
94 private CarrierConfigManager mCarrierConfigManager;
Shuo Qian489d9282020-07-09 11:30:03 -070095 private Context mContext;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010096
97 private enum CcType {
98 BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
99 STRING_ARRAY, UNKNOWN
100 }
101
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100102 private class CcOptionParseResult {
103 public int mSubId;
104 public boolean mPersistent;
105 }
106
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100107 // Maps carrier config keys to type. It is possible to infer the type for most carrier config
108 // keys by looking at the end of the string which usually tells the type.
109 // For instance: "xxxx_string", "xxxx_string_array", etc.
110 // The carrier config keys in this map does not follow this convention. It is therefore not
111 // possible to infer the type for these keys by looking at the string.
112 private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
113 put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
114 put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
115 put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
116 put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
117 put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
118 put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
119 put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
120 put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
121 put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
122 put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
123 put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
124 CcType.STRING);
125 put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
126 CcType.STRING_ARRAY);
127 put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
128 CcType.STRING_ARRAY);
129 put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
130 put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
131 put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
132 put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
133 put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
134 put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
135 put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
136 put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
137 }
138 };
139
140 public TelephonyShellCommand(ITelephony binder, Context context) {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700141 mInterface = binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100142 mCarrierConfigManager =
143 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
144 mSubscriptionManager = (SubscriptionManager)
145 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Shuo Qian489d9282020-07-09 11:30:03 -0700146 mContext = context;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700147 }
148
149 @Override
150 public int onCommand(String cmd) {
151 if (cmd == null) {
152 return handleDefaultCommands(null);
153 }
154
155 switch (cmd) {
156 case IMS_SUBCOMMAND: {
157 return handleImsCommand();
158 }
Hall Liud892bec2018-11-30 14:51:45 -0800159 case NUMBER_VERIFICATION_SUBCOMMAND:
160 return handleNumberVerificationCommand();
sqian9d4df8b2019-01-15 18:32:07 -0800161 case EMERGENCY_NUMBER_TEST_MODE:
162 return handleEmergencyNumberTestModeCommand();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100163 case CARRIER_CONFIG_SUBCOMMAND: {
164 return handleCcCommand();
165 }
Shuo Qianf5125122019-12-16 17:03:07 -0800166 case DATA_TEST_MODE:
167 return handleDataTestModeCommand();
Shuo Qian489d9282020-07-09 11:30:03 -0700168 case END_BLOCK_SUPPRESSION:
169 return handleEndBlockSuppressionCommand();
Hui Wang641e81c2020-10-12 12:14:23 -0700170 case GBA_SUBCOMMAND:
171 return handleGbaCommand();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700172 default: {
173 return handleDefaultCommands(cmd);
174 }
175 }
176 }
177
178 @Override
179 public void onHelp() {
180 PrintWriter pw = getOutPrintWriter();
181 pw.println("Telephony Commands:");
182 pw.println(" help");
183 pw.println(" Print this help text.");
184 pw.println(" ims");
185 pw.println(" IMS Commands.");
sqian9d4df8b2019-01-15 18:32:07 -0800186 pw.println(" emergency-number-test-mode");
187 pw.println(" Emergency Number Test Mode Commands.");
Shuo Qian489d9282020-07-09 11:30:03 -0700188 pw.println(" end-block-suppression");
189 pw.println(" End Block Suppression command.");
Shuo Qianf5125122019-12-16 17:03:07 -0800190 pw.println(" data");
191 pw.println(" Data Test Mode Commands.");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100192 pw.println(" cc");
193 pw.println(" Carrier Config Commands.");
Hui Wang641e81c2020-10-12 12:14:23 -0700194 pw.println(" gba");
195 pw.println(" GBA Commands.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700196 onHelpIms();
sqian9d4df8b2019-01-15 18:32:07 -0800197 onHelpEmergencyNumber();
Shuo Qian489d9282020-07-09 11:30:03 -0700198 onHelpEndBlockSupperssion();
Shuo Qianf5125122019-12-16 17:03:07 -0800199 onHelpDataTestMode();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100200 onHelpCc();
Hui Wang641e81c2020-10-12 12:14:23 -0700201 onHelpGba();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700202 }
203
204 private void onHelpIms() {
205 PrintWriter pw = getOutPrintWriter();
206 pw.println("IMS Commands:");
Brad Ebinger24c29992019-12-05 13:03:21 -0800207 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700208 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
209 pw.println(" ImsService. Options are:");
210 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
211 pw.println(" is specified, it will choose the default voice SIM slot.");
212 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
213 pw.println(" -d: Override the ImsService defined in the device overlay.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800214 pw.println(" -f: Set the feature that this override if for, if no option is");
215 pw.println(" specified, the new package name will be used for all features.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700216 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
217 pw.println(" Gets the package name of the currently defined ImsService.");
218 pw.println(" Options are:");
219 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
220 pw.println(" is specified, it will choose the default voice SIM slot.");
221 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
Peter Kalauskas1defdc32020-09-03 19:20:26 +0000222 pw.println(" -d: The ImsService defined as the device default ImsService.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800223 pw.println(" -f: The feature type that the query will be requested for. If none is");
224 pw.println(" specified, the returned package name will correspond to MMTEL.");
Brad Ebinger999d3302020-11-25 14:31:39 -0800225 pw.println(" ims clear-ims-service-override [-s SLOT_ID]");
226 pw.println(" Clear all carrier ImsService overrides. This does not work for device ");
227 pw.println(" configuration overrides. Options are:");
228 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
229 pw.println(" is specified, it will choose the default voice SIM slot.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700230 pw.println(" ims enable [-s SLOT_ID]");
231 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
232 pw.println(" if none is specified.");
233 pw.println(" ims disable [-s SLOT_ID]");
234 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
235 pw.println(" slot if none is specified.");
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700236 pw.println(" ims conference-event-package [enable/disable]");
237 pw.println(" enables or disables handling or network conference event package data.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700238 }
239
Hall Liud892bec2018-11-30 14:51:45 -0800240 private void onHelpNumberVerification() {
241 PrintWriter pw = getOutPrintWriter();
242 pw.println("Number verification commands");
243 pw.println(" numverify override-package PACKAGE_NAME;");
244 pw.println(" Set the authorized package for number verification.");
245 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800246 pw.println(" numverify fake-call NUMBER;");
247 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
248 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800249 }
250
Shuo Qianf5125122019-12-16 17:03:07 -0800251 private void onHelpDataTestMode() {
252 PrintWriter pw = getOutPrintWriter();
253 pw.println("Mobile Data Test Mode Commands:");
254 pw.println(" data enable: enable mobile data connectivity");
255 pw.println(" data disable: disable mobile data connectivity");
256 }
257
sqian9d4df8b2019-01-15 18:32:07 -0800258 private void onHelpEmergencyNumber() {
259 PrintWriter pw = getOutPrintWriter();
260 pw.println("Emergency Number Test Mode Commands:");
261 pw.println(" emergency-number-test-mode ");
262 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
263 + " the test mode");
264 pw.println(" -a <emergency number address>: add an emergency number address for the"
sqian9121f982019-03-14 19:45:39 -0700265 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800266 pw.println(" -c: clear the emergency number list in the test mode.");
267 pw.println(" -r <emergency number address>: remove an existing emergency number"
sqian9121f982019-03-14 19:45:39 -0700268 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800269 pw.println(" -p: get the full emergency number list in the test mode.");
270 }
271
Shuo Qian489d9282020-07-09 11:30:03 -0700272 private void onHelpEndBlockSupperssion() {
273 PrintWriter pw = getOutPrintWriter();
274 pw.println("End Block Suppression command:");
275 pw.println(" end-block-suppression: disable suppressing blocking by contact");
276 pw.println(" with emergency services.");
277 }
278
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100279 private void onHelpCc() {
280 PrintWriter pw = getOutPrintWriter();
281 pw.println("Carrier Config Commands:");
282 pw.println(" cc get-value [-s SLOT_ID] [KEY]");
283 pw.println(" Print carrier config values.");
284 pw.println(" Options are:");
285 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
286 pw.println(" is specified, it will choose the default voice SIM slot.");
287 pw.println(" KEY: The key to the carrier config value to print. All values are printed");
288 pw.println(" if KEY is not specified.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100289 pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100290 pw.println(" Set carrier config KEY to NEW_VALUE.");
291 pw.println(" Options are:");
292 pw.println(" -s: The SIM slot ID to set carrier config value for. If no option");
293 pw.println(" is specified, it will choose the default voice SIM slot.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100294 pw.println(" -p: Value will be stored persistent");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100295 pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be");
296 pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with");
297 pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
298 pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\"");
299 pw.println(" cc clear-values [-s SLOT_ID]");
300 pw.println(" Clear all carrier override values that has previously been set");
301 pw.println(" with set-value");
302 pw.println(" Options are:");
303 pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option");
304 pw.println(" is specified, it will choose the default voice SIM slot.");
305 }
306
Hui Wang641e81c2020-10-12 12:14:23 -0700307 private void onHelpGba() {
308 PrintWriter pw = getOutPrintWriter();
309 pw.println("Gba Commands:");
310 pw.println(" gba set-service [-s SLOT_ID] PACKAGE_NAME");
311 pw.println(" Sets the GbaService defined in PACKAGE_NAME to to be the bound.");
312 pw.println(" Options are:");
313 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
314 pw.println(" is specified, it will choose the default voice SIM slot.");
315 pw.println(" gba get-service [-s SLOT_ID]");
316 pw.println(" Gets the package name of the currently defined GbaService.");
317 pw.println(" Options are:");
318 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
319 pw.println(" is specified, it will choose the default voice SIM slot.");
320 pw.println(" gba set-release [-s SLOT_ID] n");
321 pw.println(" Sets the time to release/unbind GbaService in n milli-second.");
322 pw.println(" Do not release/unbind if n is -1.");
323 pw.println(" Options are:");
324 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
325 pw.println(" is specified, it will choose the default voice SIM slot.");
326 pw.println(" gba get-release [-s SLOT_ID]");
327 pw.println(" Gets the time to release/unbind GbaService in n milli-sencond.");
328 pw.println(" Options are:");
329 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
330 pw.println(" is specified, it will choose the default voice SIM slot.");
331 }
332
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700333 private int handleImsCommand() {
334 String arg = getNextArg();
335 if (arg == null) {
336 onHelpIms();
337 return 0;
338 }
339
340 switch (arg) {
Brad Ebinger999d3302020-11-25 14:31:39 -0800341 case IMS_SET_IMS_SERVICE: {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700342 return handleImsSetServiceCommand();
343 }
Brad Ebinger999d3302020-11-25 14:31:39 -0800344 case IMS_GET_IMS_SERVICE: {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700345 return handleImsGetServiceCommand();
346 }
Brad Ebinger999d3302020-11-25 14:31:39 -0800347 case IMS_CLEAR_SERVICE_OVERRIDE: {
348 return handleImsClearCarrierServiceCommand();
349 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700350 case IMS_ENABLE: {
351 return handleEnableIms();
352 }
353 case IMS_DISABLE: {
354 return handleDisableIms();
355 }
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700356 case IMS_CEP: {
357 return handleCepChange();
358 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700359 }
360
361 return -1;
362 }
363
Shuo Qianf5125122019-12-16 17:03:07 -0800364 private int handleDataTestModeCommand() {
365 PrintWriter errPw = getErrPrintWriter();
366 String arg = getNextArgRequired();
367 if (arg == null) {
368 onHelpDataTestMode();
369 return 0;
370 }
371 switch (arg) {
372 case DATA_ENABLE: {
373 try {
374 mInterface.enableDataConnectivity();
375 } catch (RemoteException ex) {
376 Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
377 errPw.println("Exception: " + ex.getMessage());
378 return -1;
379 }
380 break;
381 }
382 case DATA_DISABLE: {
383 try {
384 mInterface.disableDataConnectivity();
385 } catch (RemoteException ex) {
386 Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
387 errPw.println("Exception: " + ex.getMessage());
388 return -1;
389 }
390 break;
391 }
392 default:
393 onHelpDataTestMode();
394 break;
395 }
396 return 0;
397 }
398
sqian9d4df8b2019-01-15 18:32:07 -0800399 private int handleEmergencyNumberTestModeCommand() {
400 PrintWriter errPw = getErrPrintWriter();
401 String opt = getNextOption();
402 if (opt == null) {
403 onHelpEmergencyNumber();
404 return 0;
405 }
406
407 switch (opt) {
408 case "-a": {
409 String emergencyNumberCmd = getNextArgRequired();
410 if (emergencyNumberCmd == null
411 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700412 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800413 + " to be specified after -a in the command ");
414 return -1;
415 }
416 try {
417 mInterface.updateEmergencyNumberListTestMode(
418 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
419 new EmergencyNumber(emergencyNumberCmd, "", "",
420 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
421 new ArrayList<String>(),
422 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
423 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
424 } catch (RemoteException ex) {
425 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
426 + ", error " + ex.getMessage());
427 errPw.println("Exception: " + ex.getMessage());
428 return -1;
429 }
430 break;
431 }
432 case "-c": {
433 try {
434 mInterface.updateEmergencyNumberListTestMode(
435 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
436 } catch (RemoteException ex) {
437 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
438 errPw.println("Exception: " + ex.getMessage());
439 return -1;
440 }
441 break;
442 }
443 case "-r": {
444 String emergencyNumberCmd = getNextArgRequired();
445 if (emergencyNumberCmd == null
446 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700447 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800448 + " to be specified after -r in the command ");
449 return -1;
450 }
451 try {
452 mInterface.updateEmergencyNumberListTestMode(
453 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
454 new EmergencyNumber(emergencyNumberCmd, "", "",
455 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
456 new ArrayList<String>(),
457 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
458 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
459 } catch (RemoteException ex) {
460 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
461 + ", error " + ex.getMessage());
462 errPw.println("Exception: " + ex.getMessage());
463 return -1;
464 }
465 break;
466 }
467 case "-p": {
468 try {
469 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
470 } catch (RemoteException ex) {
471 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
472 errPw.println("Exception: " + ex.getMessage());
473 return -1;
474 }
475 break;
476 }
477 default:
478 onHelpEmergencyNumber();
479 break;
480 }
481 return 0;
482 }
483
Hall Liud892bec2018-11-30 14:51:45 -0800484 private int handleNumberVerificationCommand() {
485 String arg = getNextArg();
486 if (arg == null) {
487 onHelpNumberVerification();
488 return 0;
489 }
490
Hall Liuca5af3a2018-12-04 16:58:23 -0800491 if (!checkShellUid()) {
492 return -1;
493 }
494
Hall Liud892bec2018-11-30 14:51:45 -0800495 switch (arg) {
496 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800497 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
498 return 0;
499 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800500 case NUMBER_VERIFICATION_FAKE_CALL: {
501 boolean val = NumberVerificationManager.getInstance()
502 .checkIncomingCall(getNextArg());
503 getOutPrintWriter().println(val ? "1" : "0");
504 return 0;
505 }
Hall Liud892bec2018-11-30 14:51:45 -0800506 }
507
508 return -1;
509 }
510
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700511 // ims set-ims-service
512 private int handleImsSetServiceCommand() {
513 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700514 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700515 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800516 List<Integer> featuresList = new ArrayList<>();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700517
518 String opt;
519 while ((opt = getNextOption()) != null) {
520 switch (opt) {
521 case "-s": {
522 try {
523 slotId = Integer.parseInt(getNextArgRequired());
524 } catch (NumberFormatException e) {
525 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
526 return -1;
527 }
528 break;
529 }
530 case "-c": {
531 isCarrierService = true;
532 break;
533 }
534 case "-d": {
535 isCarrierService = false;
536 break;
537 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800538 case "-f": {
539 String featureString = getNextArgRequired();
540 String[] features = featureString.split(",");
541 for (int i = 0; i < features.length; i++) {
542 try {
543 Integer result = Integer.parseInt(features[i]);
544 if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
545 || result >= ImsFeature.FEATURE_MAX) {
546 errPw.println("ims set-ims-service -f " + result
547 + " is an invalid feature.");
548 return -1;
549 }
550 featuresList.add(result);
551 } catch (NumberFormatException e) {
552 errPw.println("ims set-ims-service -f tried to parse " + features[i]
553 + " as an integer.");
554 return -1;
555 }
556 }
557 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700558 }
559 }
560 // Mandatory param, either -c or -d
561 if (isCarrierService == null) {
562 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
563 return -1;
564 }
565
566 String packageName = getNextArg();
567
568 try {
569 if (packageName == null) {
570 packageName = "";
571 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800572 int[] featureArray = new int[featuresList.size()];
573 for (int i = 0; i < featuresList.size(); i++) {
574 featureArray[i] = featuresList.get(i);
575 }
576 boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
577 featureArray, packageName);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700578 if (VDBG) {
579 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800580 + (isCarrierService ? "-c " : "-d ")
581 + "-f " + featuresList + " "
582 + packageName + ", result=" + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700583 }
584 getOutPrintWriter().println(result);
585 } catch (RemoteException e) {
586 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800587 + (isCarrierService ? "-c " : "-d ")
588 + "-f " + featuresList + " "
589 + packageName + ", error" + e.getMessage());
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700590 errPw.println("Exception: " + e.getMessage());
591 return -1;
592 }
593 return 0;
594 }
595
Brad Ebinger999d3302020-11-25 14:31:39 -0800596 // ims clear-ims-service-override
597 private int handleImsClearCarrierServiceCommand() {
598 PrintWriter errPw = getErrPrintWriter();
599 int slotId = getDefaultSlot();
600
601 String opt;
602 while ((opt = getNextOption()) != null) {
603 switch (opt) {
604 case "-s": {
605 try {
606 slotId = Integer.parseInt(getNextArgRequired());
607 } catch (NumberFormatException e) {
608 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
609 return -1;
610 }
611 break;
612 }
613 }
614 }
615
616 try {
617 boolean result = mInterface.clearCarrierImsServiceOverride(slotId);
618 if (VDBG) {
619 Log.v(LOG_TAG, "ims clear-ims-service-override -s " + slotId
620 + ", result=" + result);
621 }
622 getOutPrintWriter().println(result);
623 } catch (RemoteException e) {
624 Log.w(LOG_TAG, "ims clear-ims-service-override -s " + slotId
625 + ", error" + e.getMessage());
626 errPw.println("Exception: " + e.getMessage());
627 return -1;
628 }
629 return 0;
630 }
631
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700632 // ims get-ims-service
633 private int handleImsGetServiceCommand() {
634 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700635 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700636 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800637 Integer featureType = ImsFeature.FEATURE_MMTEL;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700638
639 String opt;
640 while ((opt = getNextOption()) != null) {
641 switch (opt) {
642 case "-s": {
643 try {
644 slotId = Integer.parseInt(getNextArgRequired());
645 } catch (NumberFormatException e) {
646 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
647 return -1;
648 }
649 break;
650 }
651 case "-c": {
652 isCarrierService = true;
653 break;
654 }
655 case "-d": {
656 isCarrierService = false;
657 break;
658 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800659 case "-f": {
660 try {
661 featureType = Integer.parseInt(getNextArg());
662 } catch (NumberFormatException e) {
663 errPw.println("ims get-ims-service -f requires valid integer as feature.");
664 return -1;
665 }
666 if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
667 || featureType >= ImsFeature.FEATURE_MAX) {
668 errPw.println("ims get-ims-service -f invalid feature.");
669 return -1;
670 }
671 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700672 }
673 }
674 // Mandatory param, either -c or -d
675 if (isCarrierService == null) {
Brad Ebinger24c29992019-12-05 13:03:21 -0800676 errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700677 return -1;
678 }
679
680 String result;
681 try {
Brad Ebinger24c29992019-12-05 13:03:21 -0800682 result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700683 } catch (RemoteException e) {
684 return -1;
685 }
686 if (VDBG) {
687 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800688 + (isCarrierService ? "-c " : "-d ")
689 + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
690 + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700691 }
692 getOutPrintWriter().println(result);
693 return 0;
694 }
695
696 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700697 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700698 String opt;
699 while ((opt = getNextOption()) != null) {
700 switch (opt) {
701 case "-s": {
702 try {
703 slotId = Integer.parseInt(getNextArgRequired());
704 } catch (NumberFormatException e) {
705 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
706 return -1;
707 }
708 break;
709 }
710 }
711 }
712 try {
713 mInterface.enableIms(slotId);
714 } catch (RemoteException e) {
715 return -1;
716 }
717 if (VDBG) {
718 Log.v(LOG_TAG, "ims enable -s " + slotId);
719 }
720 return 0;
721 }
722
723 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700724 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700725 String opt;
726 while ((opt = getNextOption()) != null) {
727 switch (opt) {
728 case "-s": {
729 try {
730 slotId = Integer.parseInt(getNextArgRequired());
731 } catch (NumberFormatException e) {
732 getErrPrintWriter().println(
733 "ims disable requires an integer as a SLOT_ID.");
734 return -1;
735 }
736 break;
737 }
738 }
739 }
740 try {
741 mInterface.disableIms(slotId);
742 } catch (RemoteException e) {
743 return -1;
744 }
745 if (VDBG) {
746 Log.v(LOG_TAG, "ims disable -s " + slotId);
747 }
748 return 0;
749 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700750
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700751 private int handleCepChange() {
752 Log.i(LOG_TAG, "handleCepChange");
753 String opt = getNextArg();
754 if (opt == null) {
755 return -1;
756 }
757 boolean isCepEnabled = opt.equals("enable");
758
759 try {
760 mInterface.setCepEnabled(isCepEnabled);
761 } catch (RemoteException e) {
762 return -1;
763 }
764 return 0;
765 }
766
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700767 private int getDefaultSlot() {
768 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
769 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
770 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
771 // If there is no default, default to slot 0.
772 slotId = DEFAULT_PHONE_ID;
773 }
774 return slotId;
775 }
sqian2fff4a32018-11-05 14:18:37 -0800776
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100777 // Parse options related to Carrier Config Commands.
778 private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100779 PrintWriter errPw = getErrPrintWriter();
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100780 CcOptionParseResult result = new CcOptionParseResult();
781 result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
782 result.mPersistent = false;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100783
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100784 String opt;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100785 while ((opt = getNextOption()) != null) {
786 switch (opt) {
787 case "-s": {
788 try {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100789 result.mSubId = slotStringToSubId(tag, getNextArgRequired());
790 if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
791 errPw.println(tag + "No valid subscription found.");
792 return null;
793 }
794
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100795 } catch (IllegalArgumentException e) {
796 // Missing slot id
797 errPw.println(tag + "SLOT_ID expected after -s.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100798 return null;
799 }
800 break;
801 }
802 case "-p": {
803 if (allowOptionPersistent) {
804 result.mPersistent = true;
805 } else {
806 errPw.println(tag + "Unexpected option " + opt);
807 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100808 }
809 break;
810 }
811 default: {
812 errPw.println(tag + "Unknown option " + opt);
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100813 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100814 }
815 }
816 }
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100817 return result;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100818 }
819
820 private int slotStringToSubId(String tag, String slotString) {
821 int slotId = -1;
822 try {
823 slotId = Integer.parseInt(slotString);
824 } catch (NumberFormatException e) {
Qiong Liuf25799b2020-09-10 10:13:46 +0800825 getErrPrintWriter().println(tag + slotString + " is not a valid number for SLOT_ID.");
826 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
827 }
828
829 if (!SubscriptionManager.isValidPhoneId(slotId)) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100830 getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
831 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
832 }
833
Qiong Liuf25799b2020-09-10 10:13:46 +0800834 Phone phone = PhoneFactory.getPhone(slotId);
835 if (phone == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100836 getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
837 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
838 }
Qiong Liuf25799b2020-09-10 10:13:46 +0800839 return phone.getSubId();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100840 }
841
Hall Liud892bec2018-11-30 14:51:45 -0800842 private boolean checkShellUid() {
Hall Liu2ddfc7e2018-12-06 13:09:45 -0800843 // adb can run as root or as shell, depending on whether the device is rooted.
844 return Binder.getCallingUid() == Process.SHELL_UID
845 || Binder.getCallingUid() == Process.ROOT_UID;
Hall Liud892bec2018-11-30 14:51:45 -0800846 }
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100847
848 private int handleCcCommand() {
849 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
850 // non user build.
Meng Wangc4f61042019-11-21 10:51:05 -0800851 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100852 getErrPrintWriter().println("cc: Permission denied.");
853 return -1;
854 }
855
856 String arg = getNextArg();
857 if (arg == null) {
858 onHelpCc();
859 return 0;
860 }
861
862 switch (arg) {
863 case CC_GET_VALUE: {
864 return handleCcGetValue();
865 }
866 case CC_SET_VALUE: {
867 return handleCcSetValue();
868 }
869 case CC_CLEAR_VALUES: {
870 return handleCcClearValues();
871 }
872 default: {
873 getErrPrintWriter().println("cc: Unknown argument: " + arg);
874 }
875 }
876 return -1;
877 }
878
879 // cc get-value
880 private int handleCcGetValue() {
881 PrintWriter errPw = getErrPrintWriter();
882 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
883 String key = null;
884
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100885 // Parse all options
886 CcOptionParseResult options = parseCcOptions(tag, false);
887 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100888 return -1;
889 }
890
891 // Get bundle containing all carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100892 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100893 if (bundle == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100894 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100895 return -1;
896 }
897
898 // Get the key.
899 key = getNextArg();
900 if (key != null) {
901 // A key was provided. Verify if it is a valid key
902 if (!bundle.containsKey(key)) {
903 errPw.println(tag + key + " is not a valid key.");
904 return -1;
905 }
906
907 // Print the carrier config value for key.
908 getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
909 } else {
910 // No key provided. Show all values.
911 // Iterate over a sorted list of all carrier config keys and print them.
912 TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
913 for (String k : sortedSet) {
914 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
915 }
916 }
917 return 0;
918 }
919
920 // cc set-value
921 private int handleCcSetValue() {
922 PrintWriter errPw = getErrPrintWriter();
923 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
924
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100925 // Parse all options
926 CcOptionParseResult options = parseCcOptions(tag, true);
927 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100928 return -1;
929 }
930
931 // Get bundle containing all current carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100932 PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100933 if (originalValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100934 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100935 return -1;
936 }
937
938 // Get the key.
939 String key = getNextArg();
940 if (key == null || key.equals("")) {
941 errPw.println(tag + "KEY is missing");
942 return -1;
943 }
944
945 // Verify if the key is valid
946 if (!originalValues.containsKey(key)) {
947 errPw.println(tag + key + " is not a valid key.");
948 return -1;
949 }
950
951 // Remaining arguments is a list of new values. Add them all into an ArrayList.
952 ArrayList<String> valueList = new ArrayList<String>();
953 while (peekNextArg() != null) {
954 valueList.add(getNextArg());
955 }
956
957 // Find the type of the carrier config value
958 CcType type = getType(tag, key, originalValues);
959 if (type == CcType.UNKNOWN) {
960 errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
961 return -1;
962 }
963
964 // Create an override bundle containing the key and value that should be overriden.
965 PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
966 if (overrideBundle == null) {
967 return -1;
968 }
969
970 // Override the value
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100971 mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100972
973 // Find bundle containing all new carrier configuration values after the override.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100974 PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100975 if (newValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100976 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100977 return -1;
978 }
979
980 // Print the original and new value.
981 String originalValueString = ccValueToString(key, type, originalValues);
982 String newValueString = ccValueToString(key, type, newValues);
983 getOutPrintWriter().println("Previous value: \n" + originalValueString);
984 getOutPrintWriter().println("New value: \n" + newValueString);
985
986 return 0;
987 }
988
989 // cc clear-values
990 private int handleCcClearValues() {
991 PrintWriter errPw = getErrPrintWriter();
992 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
993
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100994 // Parse all options
995 CcOptionParseResult options = parseCcOptions(tag, false);
996 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100997 return -1;
998 }
999
1000 // Clear all values that has previously been set.
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001001 mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001002 getOutPrintWriter()
1003 .println("All previously set carrier config override values has been cleared");
1004 return 0;
1005 }
1006
1007 private CcType getType(String tag, String key, PersistableBundle bundle) {
1008 // Find the type by checking the type of the current value stored in the bundle.
1009 Object value = bundle.get(key);
1010
1011 if (CC_TYPE_MAP.containsKey(key)) {
1012 return CC_TYPE_MAP.get(key);
1013 } else if (value != null) {
1014 if (value instanceof Boolean) {
1015 return CcType.BOOLEAN;
1016 } else if (value instanceof Double) {
1017 return CcType.DOUBLE;
1018 } else if (value instanceof double[]) {
1019 return CcType.DOUBLE_ARRAY;
1020 } else if (value instanceof Integer) {
1021 return CcType.INT;
1022 } else if (value instanceof int[]) {
1023 return CcType.INT_ARRAY;
1024 } else if (value instanceof Long) {
1025 return CcType.LONG;
1026 } else if (value instanceof long[]) {
1027 return CcType.LONG_ARRAY;
1028 } else if (value instanceof String) {
1029 return CcType.STRING;
1030 } else if (value instanceof String[]) {
1031 return CcType.STRING_ARRAY;
1032 }
1033 } else {
1034 // Current value was null and can therefore not be used in order to find the type.
1035 // Check the name of the key to infer the type. This check is not needed for primitive
1036 // data types (boolean, double, int and long), since they can not be null.
1037 if (key.endsWith("double_array")) {
1038 return CcType.DOUBLE_ARRAY;
1039 }
1040 if (key.endsWith("int_array")) {
1041 return CcType.INT_ARRAY;
1042 }
1043 if (key.endsWith("long_array")) {
1044 return CcType.LONG_ARRAY;
1045 }
1046 if (key.endsWith("string")) {
1047 return CcType.STRING;
1048 }
1049 if (key.endsWith("string_array") || key.endsWith("strings")) {
1050 return CcType.STRING_ARRAY;
1051 }
1052 }
1053
1054 // Not possible to infer the type by looking at the current value or the key.
1055 PrintWriter errPw = getErrPrintWriter();
1056 errPw.println(tag + "ERROR: " + key + " has unknown type.");
1057 return CcType.UNKNOWN;
1058 }
1059
1060 private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
1061 String result;
1062 StringBuilder valueString = new StringBuilder();
1063 String typeString = type.toString();
1064 Object value = bundle.get(key);
1065
1066 if (value == null) {
1067 valueString.append("null");
1068 } else {
1069 switch (type) {
1070 case DOUBLE_ARRAY: {
1071 // Format the string representation of the int array as value1 value2......
1072 double[] valueArray = (double[]) value;
1073 for (int i = 0; i < valueArray.length; i++) {
1074 if (i != 0) {
1075 valueString.append(" ");
1076 }
1077 valueString.append(valueArray[i]);
1078 }
1079 break;
1080 }
1081 case INT_ARRAY: {
1082 // Format the string representation of the int array as value1 value2......
1083 int[] valueArray = (int[]) value;
1084 for (int i = 0; i < valueArray.length; i++) {
1085 if (i != 0) {
1086 valueString.append(" ");
1087 }
1088 valueString.append(valueArray[i]);
1089 }
1090 break;
1091 }
1092 case LONG_ARRAY: {
1093 // Format the string representation of the int array as value1 value2......
1094 long[] valueArray = (long[]) value;
1095 for (int i = 0; i < valueArray.length; i++) {
1096 if (i != 0) {
1097 valueString.append(" ");
1098 }
1099 valueString.append(valueArray[i]);
1100 }
1101 break;
1102 }
1103 case STRING: {
1104 valueString.append("\"" + value.toString() + "\"");
1105 break;
1106 }
1107 case STRING_ARRAY: {
1108 // Format the string representation of the string array as "value1" "value2"....
1109 String[] valueArray = (String[]) value;
1110 for (int i = 0; i < valueArray.length; i++) {
1111 if (i != 0) {
1112 valueString.append(" ");
1113 }
1114 if (valueArray[i] != null) {
1115 valueString.append("\"" + valueArray[i] + "\"");
1116 } else {
1117 valueString.append("null");
1118 }
1119 }
1120 break;
1121 }
1122 default: {
1123 valueString.append(value.toString());
1124 }
1125 }
1126 }
1127 return String.format("%-70s %-15s %s", key, typeString, valueString);
1128 }
1129
1130 private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
1131 ArrayList<String> valueList) {
1132 PrintWriter errPw = getErrPrintWriter();
1133 PersistableBundle bundle = new PersistableBundle();
1134
1135 // First verify that a valid number of values has been provided for the type.
1136 switch (type) {
1137 case BOOLEAN:
1138 case DOUBLE:
1139 case INT:
1140 case LONG: {
1141 if (valueList.size() != 1) {
1142 errPw.println(tag + "Expected 1 value for type " + type
1143 + ". Found: " + valueList.size());
1144 return null;
1145 }
1146 break;
1147 }
1148 case STRING: {
1149 if (valueList.size() > 1) {
1150 errPw.println(tag + "Expected 0 or 1 values for type " + type
1151 + ". Found: " + valueList.size());
1152 return null;
1153 }
1154 break;
1155 }
1156 }
1157
1158 // Parse the value according to type and add it to the Bundle.
1159 switch (type) {
1160 case BOOLEAN: {
1161 if ("true".equalsIgnoreCase(valueList.get(0))) {
1162 bundle.putBoolean(key, true);
1163 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
1164 bundle.putBoolean(key, false);
1165 } else {
1166 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1167 return null;
1168 }
1169 break;
1170 }
1171 case DOUBLE: {
1172 try {
1173 bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
1174 } catch (NumberFormatException nfe) {
1175 // Not a valid double
1176 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1177 return null;
1178 }
1179 break;
1180 }
1181 case DOUBLE_ARRAY: {
1182 double[] valueDoubleArray = null;
1183 if (valueList.size() > 0) {
1184 valueDoubleArray = new double[valueList.size()];
1185 for (int i = 0; i < valueList.size(); i++) {
1186 try {
1187 valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
1188 } catch (NumberFormatException nfe) {
1189 // Not a valid double
1190 errPw.println(
1191 tag + "Unable to parse " + valueList.get(i) + " as a double.");
1192 return null;
1193 }
1194 }
1195 }
1196 bundle.putDoubleArray(key, valueDoubleArray);
1197 break;
1198 }
1199 case INT: {
1200 try {
1201 bundle.putInt(key, Integer.parseInt(valueList.get(0)));
1202 } catch (NumberFormatException nfe) {
1203 // Not a valid integer
1204 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
1205 return null;
1206 }
1207 break;
1208 }
1209 case INT_ARRAY: {
1210 int[] valueIntArray = null;
1211 if (valueList.size() > 0) {
1212 valueIntArray = new int[valueList.size()];
1213 for (int i = 0; i < valueList.size(); i++) {
1214 try {
1215 valueIntArray[i] = Integer.parseInt(valueList.get(i));
1216 } catch (NumberFormatException nfe) {
1217 // Not a valid integer
1218 errPw.println(tag
1219 + "Unable to parse " + valueList.get(i) + " as an integer.");
1220 return null;
1221 }
1222 }
1223 }
1224 bundle.putIntArray(key, valueIntArray);
1225 break;
1226 }
1227 case LONG: {
1228 try {
1229 bundle.putLong(key, Long.parseLong(valueList.get(0)));
1230 } catch (NumberFormatException nfe) {
1231 // Not a valid long
1232 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1233 return null;
1234 }
1235 break;
1236 }
1237 case LONG_ARRAY: {
1238 long[] valueLongArray = null;
1239 if (valueList.size() > 0) {
1240 valueLongArray = new long[valueList.size()];
1241 for (int i = 0; i < valueList.size(); i++) {
1242 try {
1243 valueLongArray[i] = Long.parseLong(valueList.get(i));
1244 } catch (NumberFormatException nfe) {
1245 // Not a valid long
1246 errPw.println(
1247 tag + "Unable to parse " + valueList.get(i) + " as a long");
1248 return null;
1249 }
1250 }
1251 }
1252 bundle.putLongArray(key, valueLongArray);
1253 break;
1254 }
1255 case STRING: {
1256 String value = null;
1257 if (valueList.size() > 0) {
1258 value = valueList.get(0);
1259 }
1260 bundle.putString(key, value);
1261 break;
1262 }
1263 case STRING_ARRAY: {
1264 String[] valueStringArray = null;
1265 if (valueList.size() > 0) {
1266 valueStringArray = new String[valueList.size()];
1267 valueList.toArray(valueStringArray);
1268 }
1269 bundle.putStringArray(key, valueStringArray);
1270 break;
1271 }
1272 }
1273 return bundle;
1274 }
Shuo Qian489d9282020-07-09 11:30:03 -07001275
1276 private int handleEndBlockSuppressionCommand() {
1277 if (!checkShellUid()) {
1278 return -1;
1279 }
1280
1281 if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) {
1282 BlockedNumberContract.SystemContract.endBlockSuppression(mContext);
1283 }
1284 return 0;
1285 }
Hui Wang641e81c2020-10-12 12:14:23 -07001286
1287 private int handleGbaCommand() {
1288 String arg = getNextArg();
1289 if (arg == null) {
1290 onHelpGba();
1291 return 0;
1292 }
1293
1294 switch (arg) {
1295 case GBA_SET_SERVICE: {
1296 return handleGbaSetServiceCommand();
1297 }
1298 case GBA_GET_SERVICE: {
1299 return handleGbaGetServiceCommand();
1300 }
1301 case GBA_SET_RELEASE_TIME: {
1302 return handleGbaSetReleaseCommand();
1303 }
1304 case GBA_GET_RELEASE_TIME: {
1305 return handleGbaGetReleaseCommand();
1306 }
1307 }
1308
1309 return -1;
1310 }
1311
1312 private int getSubId(String cmd) {
1313 int slotId = getDefaultSlot();
1314 String opt = getNextOption();
1315 if (opt != null && opt.equals("-s")) {
1316 try {
1317 slotId = Integer.parseInt(getNextArgRequired());
1318 } catch (NumberFormatException e) {
1319 getErrPrintWriter().println(cmd + " requires an integer as a SLOT_ID.");
1320 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1321 }
1322 }
1323 int[] subIds = SubscriptionManager.getSubId(slotId);
1324 return subIds[0];
1325 }
1326
1327 private int handleGbaSetServiceCommand() {
1328 int subId = getSubId("gba set-service");
1329 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1330 return -1;
1331 }
1332
1333 String packageName = getNextArg();
1334 try {
1335 if (packageName == null) {
1336 packageName = "";
1337 }
1338 boolean result = mInterface.setBoundGbaServiceOverride(subId, packageName);
1339 if (VDBG) {
1340 Log.v(LOG_TAG, "gba set-service -s " + subId + " "
1341 + packageName + ", result=" + result);
1342 }
1343 getOutPrintWriter().println(result);
1344 } catch (RemoteException e) {
1345 Log.w(LOG_TAG, "gba set-service " + subId + " "
1346 + packageName + ", error" + e.getMessage());
1347 getErrPrintWriter().println("Exception: " + e.getMessage());
1348 return -1;
1349 }
1350 return 0;
1351 }
1352
1353 private int handleGbaGetServiceCommand() {
1354 String result;
1355
1356 int subId = getSubId("gba get-service");
1357 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1358 return -1;
1359 }
1360
1361 try {
1362 result = mInterface.getBoundGbaService(subId);
1363 } catch (RemoteException e) {
1364 return -1;
1365 }
1366 if (VDBG) {
1367 Log.v(LOG_TAG, "gba get-service -s " + subId + ", returned: " + result);
1368 }
1369 getOutPrintWriter().println(result);
1370 return 0;
1371 }
1372
1373 private int handleGbaSetReleaseCommand() {
1374 //the release time value could be -1
1375 int subId = getRemainingArgsCount() > 1 ? getSubId("gba set-release")
1376 : SubscriptionManager.getDefaultSubscriptionId();
1377 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1378 return -1;
1379 }
1380
1381 String intervalStr = getNextArg();
1382 if (intervalStr == null) {
1383 return -1;
1384 }
1385
1386 try {
1387 int interval = Integer.parseInt(intervalStr);
1388 boolean result = mInterface.setGbaReleaseTimeOverride(subId, interval);
1389 if (VDBG) {
1390 Log.v(LOG_TAG, "gba set-release -s " + subId + " "
1391 + intervalStr + ", result=" + result);
1392 }
1393 getOutPrintWriter().println(result);
1394 } catch (NumberFormatException | RemoteException e) {
1395 Log.w(LOG_TAG, "gba set-release -s " + subId + " "
1396 + intervalStr + ", error" + e.getMessage());
1397 getErrPrintWriter().println("Exception: " + e.getMessage());
1398 return -1;
1399 }
1400 return 0;
1401 }
1402
1403 private int handleGbaGetReleaseCommand() {
1404 int subId = getSubId("gba get-release");
1405 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1406 return -1;
1407 }
1408
1409 int result = 0;
1410 try {
1411 result = mInterface.getGbaReleaseTime(subId);
1412 } catch (RemoteException e) {
1413 return -1;
1414 }
1415 if (VDBG) {
1416 Log.v(LOG_TAG, "gba get-release -s " + subId + ", returned: " + result);
1417 }
1418 getOutPrintWriter().println(result);
1419 return 0;
1420 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001421}