1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.phone; 18 19 import android.content.Context; 20 import android.os.BasicShellCommandHandler; 21 import android.os.Binder; 22 import android.os.PersistableBundle; 23 import android.os.Process; 24 import android.os.RemoteException; 25 import android.provider.BlockedNumberContract; 26 import android.telephony.CarrierConfigManager; 27 import android.telephony.SubscriptionManager; 28 import android.telephony.emergency.EmergencyNumber; 29 import android.telephony.ims.feature.ImsFeature; 30 import android.util.Log; 31 32 import com.android.internal.telephony.ITelephony; 33 import com.android.internal.telephony.Phone; 34 import com.android.internal.telephony.PhoneFactory; 35 import com.android.internal.telephony.emergency.EmergencyNumberTracker; 36 import com.android.internal.telephony.util.TelephonyUtils; 37 38 import java.io.PrintWriter; 39 import java.util.ArrayList; 40 import java.util.HashMap; 41 import java.util.List; 42 import java.util.Map; 43 import java.util.TreeSet; 44 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 51 public class TelephonyShellCommand extends BasicShellCommandHandler { 52 53 private static final String LOG_TAG = "TelephonyShellCommand"; 54 // Don't commit with this true. 55 private static final boolean VDBG = true; 56 private static final int DEFAULT_PHONE_ID = 0; 57 58 private static final String IMS_SUBCOMMAND = "ims"; 59 private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify"; 60 private static final String EMERGENCY_CALLBACK_MODE = "emergency-callback-mode"; 61 private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode"; 62 private static final String END_BLOCK_SUPPRESSION = "end-block-suppression"; 63 private static final String CARRIER_CONFIG_SUBCOMMAND = "cc"; 64 private static final String DATA_TEST_MODE = "data"; 65 private static final String DATA_ENABLE = "enable"; 66 private static final String DATA_DISABLE = "disable"; 67 68 private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service"; 69 private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service"; 70 private static final String IMS_ENABLE = "enable"; 71 private static final String IMS_DISABLE = "disable"; 72 // 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"; 76 77 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package"; 78 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call"; 79 80 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 84 // Take advantage of existing methods that already contain permissions checks when possible. 85 private final ITelephony mInterface; 86 87 private SubscriptionManager mSubscriptionManager; 88 private CarrierConfigManager mCarrierConfigManager; 89 private Context mContext; 90 91 private enum CcType { 92 BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING, 93 STRING_ARRAY, UNKNOWN 94 } 95 96 private class CcOptionParseResult { 97 public int mSubId; 98 public boolean mPersistent; 99 } 100 101 // 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 TelephonyShellCommand(ITelephony binder, Context context)134 public TelephonyShellCommand(ITelephony binder, Context context) { 135 mInterface = binder; 136 mCarrierConfigManager = 137 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE); 138 mSubscriptionManager = (SubscriptionManager) 139 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 140 mContext = context; 141 } 142 143 @Override onCommand(String cmd)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 } 153 case NUMBER_VERIFICATION_SUBCOMMAND: 154 return handleNumberVerificationCommand(); 155 case EMERGENCY_CALLBACK_MODE: 156 return handleEmergencyCallbackModeCommand(); 157 case EMERGENCY_NUMBER_TEST_MODE: 158 return handleEmergencyNumberTestModeCommand(); 159 case CARRIER_CONFIG_SUBCOMMAND: { 160 return handleCcCommand(); 161 } 162 case DATA_TEST_MODE: 163 return handleDataTestModeCommand(); 164 case END_BLOCK_SUPPRESSION: 165 return handleEndBlockSuppressionCommand(); 166 default: { 167 return handleDefaultCommands(cmd); 168 } 169 } 170 } 171 172 @Override onHelp()173 public void onHelp() { 174 PrintWriter pw = getOutPrintWriter(); 175 pw.println("Telephony Commands:"); 176 pw.println(" help"); 177 pw.println(" Print this help text."); 178 pw.println(" ims"); 179 pw.println(" IMS Commands."); 180 pw.println(" emergency-number-test-mode"); 181 pw.println(" Emergency Number Test Mode Commands."); 182 pw.println(" end-block-suppression"); 183 pw.println(" End Block Suppression command."); 184 pw.println(" data"); 185 pw.println(" Data Test Mode Commands."); 186 pw.println(" cc"); 187 pw.println(" Carrier Config Commands."); 188 onHelpIms(); 189 onHelpEmergencyNumber(); 190 onHelpEndBlockSupperssion(); 191 onHelpDataTestMode(); 192 onHelpCc(); 193 } 194 onHelpIms()195 private void onHelpIms() { 196 PrintWriter pw = getOutPrintWriter(); 197 pw.println("IMS Commands:"); 198 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME"); 199 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound"); 200 pw.println(" ImsService. Options are:"); 201 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option"); 202 pw.println(" is specified, it will choose the default voice SIM slot."); 203 pw.println(" -c: Override the ImsService defined in the carrier configuration."); 204 pw.println(" -d: Override the ImsService defined in the device overlay."); 205 pw.println(" -f: Set the feature that this override if for, if no option is"); 206 pw.println(" specified, the new package name will be used for all features."); 207 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]"); 208 pw.println(" Gets the package name of the currently defined ImsService."); 209 pw.println(" Options are:"); 210 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option"); 211 pw.println(" is specified, it will choose the default voice SIM slot."); 212 pw.println(" -c: The ImsService defined as the carrier configured ImsService."); 213 pw.println(" -c: The ImsService defined as the device default ImsService."); 214 pw.println(" -f: The feature type that the query will be requested for. If none is"); 215 pw.println(" specified, the returned package name will correspond to MMTEL."); 216 pw.println(" ims enable [-s SLOT_ID]"); 217 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot"); 218 pw.println(" if none is specified."); 219 pw.println(" ims disable [-s SLOT_ID]"); 220 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM"); 221 pw.println(" slot if none is specified."); 222 pw.println(" ims conference-event-package [enable/disable]"); 223 pw.println(" enables or disables handling or network conference event package data."); 224 } 225 onHelpNumberVerification()226 private void onHelpNumberVerification() { 227 PrintWriter pw = getOutPrintWriter(); 228 pw.println("Number verification commands"); 229 pw.println(" numverify override-package PACKAGE_NAME;"); 230 pw.println(" Set the authorized package for number verification."); 231 pw.println(" Leave the package name blank to reset."); 232 pw.println(" numverify fake-call NUMBER;"); 233 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be"); 234 pw.println(" 1 if the call would have been intercepted, 0 otherwise."); 235 } 236 onHelpDataTestMode()237 private void onHelpDataTestMode() { 238 PrintWriter pw = getOutPrintWriter(); 239 pw.println("Mobile Data Test Mode Commands:"); 240 pw.println(" data enable: enable mobile data connectivity"); 241 pw.println(" data disable: disable mobile data connectivity"); 242 } 243 onHelpEmergencyNumber()244 private void onHelpEmergencyNumber() { 245 PrintWriter pw = getOutPrintWriter(); 246 pw.println("Emergency Number Test Mode Commands:"); 247 pw.println(" emergency-number-test-mode "); 248 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in" 249 + " the test mode"); 250 pw.println(" -a <emergency number address>: add an emergency number address for the" 251 + " test mode, only allows '0'-'9', '*', '#' or '+'."); 252 pw.println(" -c: clear the emergency number list in the test mode."); 253 pw.println(" -r <emergency number address>: remove an existing emergency number" 254 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'."); 255 pw.println(" -p: get the full emergency number list in the test mode."); 256 } 257 onHelpEndBlockSupperssion()258 private void onHelpEndBlockSupperssion() { 259 PrintWriter pw = getOutPrintWriter(); 260 pw.println("End Block Suppression command:"); 261 pw.println(" end-block-suppression: disable suppressing blocking by contact"); 262 pw.println(" with emergency services."); 263 } 264 onHelpCc()265 private void onHelpCc() { 266 PrintWriter pw = getOutPrintWriter(); 267 pw.println("Carrier Config Commands:"); 268 pw.println(" cc get-value [-s SLOT_ID] [KEY]"); 269 pw.println(" Print carrier config values."); 270 pw.println(" Options are:"); 271 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); 272 pw.println(" is specified, it will choose the default voice SIM slot."); 273 pw.println(" KEY: The key to the carrier config value to print. All values are printed"); 274 pw.println(" if KEY is not specified."); 275 pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]"); 276 pw.println(" Set carrier config KEY to NEW_VALUE."); 277 pw.println(" Options are:"); 278 pw.println(" -s: The SIM slot ID to set carrier config value for. If no option"); 279 pw.println(" is specified, it will choose the default voice SIM slot."); 280 pw.println(" -p: Value will be stored persistent"); 281 pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be"); 282 pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with"); 283 pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\""); 284 pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\""); 285 pw.println(" cc clear-values [-s SLOT_ID]"); 286 pw.println(" Clear all carrier override values that has previously been set"); 287 pw.println(" with set-value"); 288 pw.println(" Options are:"); 289 pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option"); 290 pw.println(" is specified, it will choose the default voice SIM slot."); 291 } 292 handleImsCommand()293 private int handleImsCommand() { 294 String arg = getNextArg(); 295 if (arg == null) { 296 onHelpIms(); 297 return 0; 298 } 299 300 switch (arg) { 301 case IMS_SET_CARRIER_SERVICE: { 302 return handleImsSetServiceCommand(); 303 } 304 case IMS_GET_CARRIER_SERVICE: { 305 return handleImsGetServiceCommand(); 306 } 307 case IMS_ENABLE: { 308 return handleEnableIms(); 309 } 310 case IMS_DISABLE: { 311 return handleDisableIms(); 312 } 313 case IMS_CEP: { 314 return handleCepChange(); 315 } 316 } 317 318 return -1; 319 } 320 handleDataTestModeCommand()321 private int handleDataTestModeCommand() { 322 PrintWriter errPw = getErrPrintWriter(); 323 String arg = getNextArgRequired(); 324 if (arg == null) { 325 onHelpDataTestMode(); 326 return 0; 327 } 328 switch (arg) { 329 case DATA_ENABLE: { 330 try { 331 mInterface.enableDataConnectivity(); 332 } catch (RemoteException ex) { 333 Log.w(LOG_TAG, "data enable, error " + ex.getMessage()); 334 errPw.println("Exception: " + ex.getMessage()); 335 return -1; 336 } 337 break; 338 } 339 case DATA_DISABLE: { 340 try { 341 mInterface.disableDataConnectivity(); 342 } catch (RemoteException ex) { 343 Log.w(LOG_TAG, "data disable, error " + ex.getMessage()); 344 errPw.println("Exception: " + ex.getMessage()); 345 return -1; 346 } 347 break; 348 } 349 default: 350 onHelpDataTestMode(); 351 break; 352 } 353 return 0; 354 } 355 handleEmergencyCallbackModeCommand()356 private int handleEmergencyCallbackModeCommand() { 357 PrintWriter errPw = getErrPrintWriter(); 358 try { 359 mInterface.startEmergencyCallbackMode(); 360 Log.d(LOG_TAG, "handleEmergencyCallbackModeCommand: triggered"); 361 } catch (RemoteException ex) { 362 Log.w(LOG_TAG, "emergency-callback-mode error: " + ex.getMessage()); 363 errPw.println("Exception: " + ex.getMessage()); 364 return -1; 365 } 366 return 0; 367 } 368 handleEmergencyNumberTestModeCommand()369 private int handleEmergencyNumberTestModeCommand() { 370 PrintWriter errPw = getErrPrintWriter(); 371 String opt = getNextOption(); 372 if (opt == null) { 373 onHelpEmergencyNumber(); 374 return 0; 375 } 376 377 switch (opt) { 378 case "-a": { 379 String emergencyNumberCmd = getNextArgRequired(); 380 if (emergencyNumberCmd == null 381 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) { 382 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs" 383 + " to be specified after -a in the command "); 384 return -1; 385 } 386 try { 387 mInterface.updateEmergencyNumberListTestMode( 388 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE, 389 new EmergencyNumber(emergencyNumberCmd, "", "", 390 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, 391 new ArrayList<String>(), 392 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST, 393 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN)); 394 } catch (RemoteException ex) { 395 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd 396 + ", error " + ex.getMessage()); 397 errPw.println("Exception: " + ex.getMessage()); 398 return -1; 399 } 400 break; 401 } 402 case "-c": { 403 try { 404 mInterface.updateEmergencyNumberListTestMode( 405 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null); 406 } catch (RemoteException ex) { 407 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage()); 408 errPw.println("Exception: " + ex.getMessage()); 409 return -1; 410 } 411 break; 412 } 413 case "-r": { 414 String emergencyNumberCmd = getNextArgRequired(); 415 if (emergencyNumberCmd == null 416 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) { 417 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs" 418 + " to be specified after -r in the command "); 419 return -1; 420 } 421 try { 422 mInterface.updateEmergencyNumberListTestMode( 423 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE, 424 new EmergencyNumber(emergencyNumberCmd, "", "", 425 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, 426 new ArrayList<String>(), 427 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST, 428 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN)); 429 } catch (RemoteException ex) { 430 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd 431 + ", error " + ex.getMessage()); 432 errPw.println("Exception: " + ex.getMessage()); 433 return -1; 434 } 435 break; 436 } 437 case "-p": { 438 try { 439 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode()); 440 } catch (RemoteException ex) { 441 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage()); 442 errPw.println("Exception: " + ex.getMessage()); 443 return -1; 444 } 445 break; 446 } 447 default: 448 onHelpEmergencyNumber(); 449 break; 450 } 451 return 0; 452 } 453 handleNumberVerificationCommand()454 private int handleNumberVerificationCommand() { 455 String arg = getNextArg(); 456 if (arg == null) { 457 onHelpNumberVerification(); 458 return 0; 459 } 460 461 if (!checkShellUid()) { 462 return -1; 463 } 464 465 switch (arg) { 466 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: { 467 NumberVerificationManager.overrideAuthorizedPackage(getNextArg()); 468 return 0; 469 } 470 case NUMBER_VERIFICATION_FAKE_CALL: { 471 boolean val = NumberVerificationManager.getInstance() 472 .checkIncomingCall(getNextArg()); 473 getOutPrintWriter().println(val ? "1" : "0"); 474 return 0; 475 } 476 } 477 478 return -1; 479 } 480 481 // ims set-ims-service handleImsSetServiceCommand()482 private int handleImsSetServiceCommand() { 483 PrintWriter errPw = getErrPrintWriter(); 484 int slotId = getDefaultSlot(); 485 Boolean isCarrierService = null; 486 List<Integer> featuresList = new ArrayList<>(); 487 488 String opt; 489 while ((opt = getNextOption()) != null) { 490 switch (opt) { 491 case "-s": { 492 try { 493 slotId = Integer.parseInt(getNextArgRequired()); 494 } catch (NumberFormatException e) { 495 errPw.println("ims set-ims-service requires an integer as a SLOT_ID."); 496 return -1; 497 } 498 break; 499 } 500 case "-c": { 501 isCarrierService = true; 502 break; 503 } 504 case "-d": { 505 isCarrierService = false; 506 break; 507 } 508 case "-f": { 509 String featureString = getNextArgRequired(); 510 String[] features = featureString.split(","); 511 for (int i = 0; i < features.length; i++) { 512 try { 513 Integer result = Integer.parseInt(features[i]); 514 if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL 515 || result >= ImsFeature.FEATURE_MAX) { 516 errPw.println("ims set-ims-service -f " + result 517 + " is an invalid feature."); 518 return -1; 519 } 520 featuresList.add(result); 521 } catch (NumberFormatException e) { 522 errPw.println("ims set-ims-service -f tried to parse " + features[i] 523 + " as an integer."); 524 return -1; 525 } 526 } 527 } 528 } 529 } 530 // Mandatory param, either -c or -d 531 if (isCarrierService == null) { 532 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set."); 533 return -1; 534 } 535 536 String packageName = getNextArg(); 537 538 try { 539 if (packageName == null) { 540 packageName = ""; 541 } 542 int[] featureArray = new int[featuresList.size()]; 543 for (int i = 0; i < featuresList.size(); i++) { 544 featureArray[i] = featuresList.get(i); 545 } 546 boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService, 547 featureArray, packageName); 548 if (VDBG) { 549 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " " 550 + (isCarrierService ? "-c " : "-d ") 551 + "-f " + featuresList + " " 552 + packageName + ", result=" + result); 553 } 554 getOutPrintWriter().println(result); 555 } catch (RemoteException e) { 556 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " " 557 + (isCarrierService ? "-c " : "-d ") 558 + "-f " + featuresList + " " 559 + packageName + ", error" + e.getMessage()); 560 errPw.println("Exception: " + e.getMessage()); 561 return -1; 562 } 563 return 0; 564 } 565 566 // ims get-ims-service handleImsGetServiceCommand()567 private int handleImsGetServiceCommand() { 568 PrintWriter errPw = getErrPrintWriter(); 569 int slotId = getDefaultSlot(); 570 Boolean isCarrierService = null; 571 Integer featureType = ImsFeature.FEATURE_MMTEL; 572 573 String opt; 574 while ((opt = getNextOption()) != null) { 575 switch (opt) { 576 case "-s": { 577 try { 578 slotId = Integer.parseInt(getNextArgRequired()); 579 } catch (NumberFormatException e) { 580 errPw.println("ims set-ims-service requires an integer as a SLOT_ID."); 581 return -1; 582 } 583 break; 584 } 585 case "-c": { 586 isCarrierService = true; 587 break; 588 } 589 case "-d": { 590 isCarrierService = false; 591 break; 592 } 593 case "-f": { 594 try { 595 featureType = Integer.parseInt(getNextArg()); 596 } catch (NumberFormatException e) { 597 errPw.println("ims get-ims-service -f requires valid integer as feature."); 598 return -1; 599 } 600 if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL 601 || featureType >= ImsFeature.FEATURE_MAX) { 602 errPw.println("ims get-ims-service -f invalid feature."); 603 return -1; 604 } 605 } 606 } 607 } 608 // Mandatory param, either -c or -d 609 if (isCarrierService == null) { 610 errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set."); 611 return -1; 612 } 613 614 String result; 615 try { 616 result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType); 617 } catch (RemoteException e) { 618 return -1; 619 } 620 if (VDBG) { 621 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " " 622 + (isCarrierService ? "-c " : "-d ") 623 + (featureType != null ? ("-f " + featureType) : "") + " , returned: " 624 + result); 625 } 626 getOutPrintWriter().println(result); 627 return 0; 628 } 629 handleEnableIms()630 private int handleEnableIms() { 631 int slotId = getDefaultSlot(); 632 String opt; 633 while ((opt = getNextOption()) != null) { 634 switch (opt) { 635 case "-s": { 636 try { 637 slotId = Integer.parseInt(getNextArgRequired()); 638 } catch (NumberFormatException e) { 639 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID."); 640 return -1; 641 } 642 break; 643 } 644 } 645 } 646 try { 647 mInterface.enableIms(slotId); 648 } catch (RemoteException e) { 649 return -1; 650 } 651 if (VDBG) { 652 Log.v(LOG_TAG, "ims enable -s " + slotId); 653 } 654 return 0; 655 } 656 handleDisableIms()657 private int handleDisableIms() { 658 int slotId = getDefaultSlot(); 659 String opt; 660 while ((opt = getNextOption()) != null) { 661 switch (opt) { 662 case "-s": { 663 try { 664 slotId = Integer.parseInt(getNextArgRequired()); 665 } catch (NumberFormatException e) { 666 getErrPrintWriter().println( 667 "ims disable requires an integer as a SLOT_ID."); 668 return -1; 669 } 670 break; 671 } 672 } 673 } 674 try { 675 mInterface.disableIms(slotId); 676 } catch (RemoteException e) { 677 return -1; 678 } 679 if (VDBG) { 680 Log.v(LOG_TAG, "ims disable -s " + slotId); 681 } 682 return 0; 683 } 684 handleCepChange()685 private int handleCepChange() { 686 Log.i(LOG_TAG, "handleCepChange"); 687 String opt = getNextArg(); 688 if (opt == null) { 689 return -1; 690 } 691 boolean isCepEnabled = opt.equals("enable"); 692 693 try { 694 mInterface.setCepEnabled(isCepEnabled); 695 } catch (RemoteException e) { 696 return -1; 697 } 698 return 0; 699 } 700 getDefaultSlot()701 private int getDefaultSlot() { 702 int slotId = SubscriptionManager.getDefaultVoicePhoneId(); 703 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX 704 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) { 705 // If there is no default, default to slot 0. 706 slotId = DEFAULT_PHONE_ID; 707 } 708 return slotId; 709 } 710 711 // Parse options related to Carrier Config Commands. parseCcOptions(String tag, boolean allowOptionPersistent)712 private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) { 713 PrintWriter errPw = getErrPrintWriter(); 714 CcOptionParseResult result = new CcOptionParseResult(); 715 result.mSubId = SubscriptionManager.getDefaultSubscriptionId(); 716 result.mPersistent = false; 717 718 String opt; 719 while ((opt = getNextOption()) != null) { 720 switch (opt) { 721 case "-s": { 722 try { 723 result.mSubId = slotStringToSubId(tag, getNextArgRequired()); 724 if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) { 725 errPw.println(tag + "No valid subscription found."); 726 return null; 727 } 728 729 } catch (IllegalArgumentException e) { 730 // Missing slot id 731 errPw.println(tag + "SLOT_ID expected after -s."); 732 return null; 733 } 734 break; 735 } 736 case "-p": { 737 if (allowOptionPersistent) { 738 result.mPersistent = true; 739 } else { 740 errPw.println(tag + "Unexpected option " + opt); 741 return null; 742 } 743 break; 744 } 745 default: { 746 errPw.println(tag + "Unknown option " + opt); 747 return null; 748 } 749 } 750 } 751 return result; 752 } 753 slotStringToSubId(String tag, String slotString)754 private int slotStringToSubId(String tag, String slotString) { 755 int slotId = -1; 756 try { 757 slotId = Integer.parseInt(slotString); 758 } catch (NumberFormatException e) { 759 getErrPrintWriter().println(tag + slotString + " is not a valid number for SLOT_ID."); 760 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 761 } 762 763 if (!SubscriptionManager.isValidPhoneId(slotId)) { 764 getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID."); 765 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 766 } 767 768 Phone phone = PhoneFactory.getPhone(slotId); 769 if (phone == null) { 770 getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + "."); 771 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 772 } 773 return phone.getSubId(); 774 } 775 checkShellUid()776 private boolean checkShellUid() { 777 // adb can run as root or as shell, depending on whether the device is rooted. 778 return Binder.getCallingUid() == Process.SHELL_UID 779 || Binder.getCallingUid() == Process.ROOT_UID; 780 } 781 handleCcCommand()782 private int handleCcCommand() { 783 // Verify that the user is allowed to run the command. Only allowed in rooted device in a 784 // non user build. 785 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { 786 getErrPrintWriter().println("cc: Permission denied."); 787 return -1; 788 } 789 790 String arg = getNextArg(); 791 if (arg == null) { 792 onHelpCc(); 793 return 0; 794 } 795 796 switch (arg) { 797 case CC_GET_VALUE: { 798 return handleCcGetValue(); 799 } 800 case CC_SET_VALUE: { 801 return handleCcSetValue(); 802 } 803 case CC_CLEAR_VALUES: { 804 return handleCcClearValues(); 805 } 806 default: { 807 getErrPrintWriter().println("cc: Unknown argument: " + arg); 808 } 809 } 810 return -1; 811 } 812 813 // cc get-value handleCcGetValue()814 private int handleCcGetValue() { 815 PrintWriter errPw = getErrPrintWriter(); 816 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": "; 817 String key = null; 818 819 // Parse all options 820 CcOptionParseResult options = parseCcOptions(tag, false); 821 if (options == null) { 822 return -1; 823 } 824 825 // Get bundle containing all carrier configuration values. 826 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId); 827 if (bundle == null) { 828 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); 829 return -1; 830 } 831 832 // Get the key. 833 key = getNextArg(); 834 if (key != null) { 835 // A key was provided. Verify if it is a valid key 836 if (!bundle.containsKey(key)) { 837 errPw.println(tag + key + " is not a valid key."); 838 return -1; 839 } 840 841 // Print the carrier config value for key. 842 getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle)); 843 } else { 844 // No key provided. Show all values. 845 // Iterate over a sorted list of all carrier config keys and print them. 846 TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet()); 847 for (String k : sortedSet) { 848 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle)); 849 } 850 } 851 return 0; 852 } 853 854 // cc set-value handleCcSetValue()855 private int handleCcSetValue() { 856 PrintWriter errPw = getErrPrintWriter(); 857 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": "; 858 859 // Parse all options 860 CcOptionParseResult options = parseCcOptions(tag, true); 861 if (options == null) { 862 return -1; 863 } 864 865 // Get bundle containing all current carrier configuration values. 866 PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId); 867 if (originalValues == null) { 868 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); 869 return -1; 870 } 871 872 // Get the key. 873 String key = getNextArg(); 874 if (key == null || key.equals("")) { 875 errPw.println(tag + "KEY is missing"); 876 return -1; 877 } 878 879 // Verify if the key is valid 880 if (!originalValues.containsKey(key)) { 881 errPw.println(tag + key + " is not a valid key."); 882 return -1; 883 } 884 885 // Remaining arguments is a list of new values. Add them all into an ArrayList. 886 ArrayList<String> valueList = new ArrayList<String>(); 887 while (peekNextArg() != null) { 888 valueList.add(getNextArg()); 889 } 890 891 // Find the type of the carrier config value 892 CcType type = getType(tag, key, originalValues); 893 if (type == CcType.UNKNOWN) { 894 errPw.println(tag + "ERROR: Not possible to override key with unknown type."); 895 return -1; 896 } 897 898 // Create an override bundle containing the key and value that should be overriden. 899 PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList); 900 if (overrideBundle == null) { 901 return -1; 902 } 903 904 // Override the value 905 mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent); 906 907 // Find bundle containing all new carrier configuration values after the override. 908 PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId); 909 if (newValues == null) { 910 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); 911 return -1; 912 } 913 914 // Print the original and new value. 915 String originalValueString = ccValueToString(key, type, originalValues); 916 String newValueString = ccValueToString(key, type, newValues); 917 getOutPrintWriter().println("Previous value: \n" + originalValueString); 918 getOutPrintWriter().println("New value: \n" + newValueString); 919 920 return 0; 921 } 922 923 // cc clear-values handleCcClearValues()924 private int handleCcClearValues() { 925 PrintWriter errPw = getErrPrintWriter(); 926 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": "; 927 928 // Parse all options 929 CcOptionParseResult options = parseCcOptions(tag, false); 930 if (options == null) { 931 return -1; 932 } 933 934 // Clear all values that has previously been set. 935 mCarrierConfigManager.overrideConfig(options.mSubId, null, true); 936 getOutPrintWriter() 937 .println("All previously set carrier config override values has been cleared"); 938 return 0; 939 } 940 getType(String tag, String key, PersistableBundle bundle)941 private CcType getType(String tag, String key, PersistableBundle bundle) { 942 // Find the type by checking the type of the current value stored in the bundle. 943 Object value = bundle.get(key); 944 945 if (CC_TYPE_MAP.containsKey(key)) { 946 return CC_TYPE_MAP.get(key); 947 } else if (value != null) { 948 if (value instanceof Boolean) { 949 return CcType.BOOLEAN; 950 } else if (value instanceof Double) { 951 return CcType.DOUBLE; 952 } else if (value instanceof double[]) { 953 return CcType.DOUBLE_ARRAY; 954 } else if (value instanceof Integer) { 955 return CcType.INT; 956 } else if (value instanceof int[]) { 957 return CcType.INT_ARRAY; 958 } else if (value instanceof Long) { 959 return CcType.LONG; 960 } else if (value instanceof long[]) { 961 return CcType.LONG_ARRAY; 962 } else if (value instanceof String) { 963 return CcType.STRING; 964 } else if (value instanceof String[]) { 965 return CcType.STRING_ARRAY; 966 } 967 } else { 968 // Current value was null and can therefore not be used in order to find the type. 969 // Check the name of the key to infer the type. This check is not needed for primitive 970 // data types (boolean, double, int and long), since they can not be null. 971 if (key.endsWith("double_array")) { 972 return CcType.DOUBLE_ARRAY; 973 } 974 if (key.endsWith("int_array")) { 975 return CcType.INT_ARRAY; 976 } 977 if (key.endsWith("long_array")) { 978 return CcType.LONG_ARRAY; 979 } 980 if (key.endsWith("string")) { 981 return CcType.STRING; 982 } 983 if (key.endsWith("string_array") || key.endsWith("strings")) { 984 return CcType.STRING_ARRAY; 985 } 986 } 987 988 // Not possible to infer the type by looking at the current value or the key. 989 PrintWriter errPw = getErrPrintWriter(); 990 errPw.println(tag + "ERROR: " + key + " has unknown type."); 991 return CcType.UNKNOWN; 992 } 993 ccValueToString(String key, CcType type, PersistableBundle bundle)994 private String ccValueToString(String key, CcType type, PersistableBundle bundle) { 995 String result; 996 StringBuilder valueString = new StringBuilder(); 997 String typeString = type.toString(); 998 Object value = bundle.get(key); 999 1000 if (value == null) { 1001 valueString.append("null"); 1002 } else { 1003 switch (type) { 1004 case DOUBLE_ARRAY: { 1005 // Format the string representation of the int array as value1 value2...... 1006 double[] valueArray = (double[]) value; 1007 for (int i = 0; i < valueArray.length; i++) { 1008 if (i != 0) { 1009 valueString.append(" "); 1010 } 1011 valueString.append(valueArray[i]); 1012 } 1013 break; 1014 } 1015 case INT_ARRAY: { 1016 // Format the string representation of the int array as value1 value2...... 1017 int[] valueArray = (int[]) value; 1018 for (int i = 0; i < valueArray.length; i++) { 1019 if (i != 0) { 1020 valueString.append(" "); 1021 } 1022 valueString.append(valueArray[i]); 1023 } 1024 break; 1025 } 1026 case LONG_ARRAY: { 1027 // Format the string representation of the int array as value1 value2...... 1028 long[] valueArray = (long[]) value; 1029 for (int i = 0; i < valueArray.length; i++) { 1030 if (i != 0) { 1031 valueString.append(" "); 1032 } 1033 valueString.append(valueArray[i]); 1034 } 1035 break; 1036 } 1037 case STRING: { 1038 valueString.append("\"" + value.toString() + "\""); 1039 break; 1040 } 1041 case STRING_ARRAY: { 1042 // Format the string representation of the string array as "value1" "value2".... 1043 String[] valueArray = (String[]) value; 1044 for (int i = 0; i < valueArray.length; i++) { 1045 if (i != 0) { 1046 valueString.append(" "); 1047 } 1048 if (valueArray[i] != null) { 1049 valueString.append("\"" + valueArray[i] + "\""); 1050 } else { 1051 valueString.append("null"); 1052 } 1053 } 1054 break; 1055 } 1056 default: { 1057 valueString.append(value.toString()); 1058 } 1059 } 1060 } 1061 return String.format("%-70s %-15s %s", key, typeString, valueString); 1062 } 1063 getOverrideBundle(String tag, CcType type, String key, ArrayList<String> valueList)1064 private PersistableBundle getOverrideBundle(String tag, CcType type, String key, 1065 ArrayList<String> valueList) { 1066 PrintWriter errPw = getErrPrintWriter(); 1067 PersistableBundle bundle = new PersistableBundle(); 1068 1069 // First verify that a valid number of values has been provided for the type. 1070 switch (type) { 1071 case BOOLEAN: 1072 case DOUBLE: 1073 case INT: 1074 case LONG: { 1075 if (valueList.size() != 1) { 1076 errPw.println(tag + "Expected 1 value for type " + type 1077 + ". Found: " + valueList.size()); 1078 return null; 1079 } 1080 break; 1081 } 1082 case STRING: { 1083 if (valueList.size() > 1) { 1084 errPw.println(tag + "Expected 0 or 1 values for type " + type 1085 + ". Found: " + valueList.size()); 1086 return null; 1087 } 1088 break; 1089 } 1090 } 1091 1092 // Parse the value according to type and add it to the Bundle. 1093 switch (type) { 1094 case BOOLEAN: { 1095 if ("true".equalsIgnoreCase(valueList.get(0))) { 1096 bundle.putBoolean(key, true); 1097 } else if ("false".equalsIgnoreCase(valueList.get(0))) { 1098 bundle.putBoolean(key, false); 1099 } else { 1100 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type); 1101 return null; 1102 } 1103 break; 1104 } 1105 case DOUBLE: { 1106 try { 1107 bundle.putDouble(key, Double.parseDouble(valueList.get(0))); 1108 } catch (NumberFormatException nfe) { 1109 // Not a valid double 1110 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type); 1111 return null; 1112 } 1113 break; 1114 } 1115 case DOUBLE_ARRAY: { 1116 double[] valueDoubleArray = null; 1117 if (valueList.size() > 0) { 1118 valueDoubleArray = new double[valueList.size()]; 1119 for (int i = 0; i < valueList.size(); i++) { 1120 try { 1121 valueDoubleArray[i] = Double.parseDouble(valueList.get(i)); 1122 } catch (NumberFormatException nfe) { 1123 // Not a valid double 1124 errPw.println( 1125 tag + "Unable to parse " + valueList.get(i) + " as a double."); 1126 return null; 1127 } 1128 } 1129 } 1130 bundle.putDoubleArray(key, valueDoubleArray); 1131 break; 1132 } 1133 case INT: { 1134 try { 1135 bundle.putInt(key, Integer.parseInt(valueList.get(0))); 1136 } catch (NumberFormatException nfe) { 1137 // Not a valid integer 1138 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type); 1139 return null; 1140 } 1141 break; 1142 } 1143 case INT_ARRAY: { 1144 int[] valueIntArray = null; 1145 if (valueList.size() > 0) { 1146 valueIntArray = new int[valueList.size()]; 1147 for (int i = 0; i < valueList.size(); i++) { 1148 try { 1149 valueIntArray[i] = Integer.parseInt(valueList.get(i)); 1150 } catch (NumberFormatException nfe) { 1151 // Not a valid integer 1152 errPw.println(tag 1153 + "Unable to parse " + valueList.get(i) + " as an integer."); 1154 return null; 1155 } 1156 } 1157 } 1158 bundle.putIntArray(key, valueIntArray); 1159 break; 1160 } 1161 case LONG: { 1162 try { 1163 bundle.putLong(key, Long.parseLong(valueList.get(0))); 1164 } catch (NumberFormatException nfe) { 1165 // Not a valid long 1166 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type); 1167 return null; 1168 } 1169 break; 1170 } 1171 case LONG_ARRAY: { 1172 long[] valueLongArray = null; 1173 if (valueList.size() > 0) { 1174 valueLongArray = new long[valueList.size()]; 1175 for (int i = 0; i < valueList.size(); i++) { 1176 try { 1177 valueLongArray[i] = Long.parseLong(valueList.get(i)); 1178 } catch (NumberFormatException nfe) { 1179 // Not a valid long 1180 errPw.println( 1181 tag + "Unable to parse " + valueList.get(i) + " as a long"); 1182 return null; 1183 } 1184 } 1185 } 1186 bundle.putLongArray(key, valueLongArray); 1187 break; 1188 } 1189 case STRING: { 1190 String value = null; 1191 if (valueList.size() > 0) { 1192 value = valueList.get(0); 1193 } 1194 bundle.putString(key, value); 1195 break; 1196 } 1197 case STRING_ARRAY: { 1198 String[] valueStringArray = null; 1199 if (valueList.size() > 0) { 1200 valueStringArray = new String[valueList.size()]; 1201 valueList.toArray(valueStringArray); 1202 } 1203 bundle.putStringArray(key, valueStringArray); 1204 break; 1205 } 1206 } 1207 return bundle; 1208 } 1209 handleEndBlockSuppressionCommand()1210 private int handleEndBlockSuppressionCommand() { 1211 if (!checkShellUid()) { 1212 return -1; 1213 } 1214 1215 if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) { 1216 BlockedNumberContract.SystemContract.endBlockSuppression(mContext); 1217 } 1218 return 0; 1219 } 1220 } 1221