1 /* 2 * Copyright (C) 2014 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.commands.telecom; 18 19 import android.app.ActivityThread; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.net.Uri; 23 import android.os.IUserManager; 24 import android.os.Looper; 25 import android.os.Process; 26 import android.os.RemoteException; 27 import android.os.ServiceManager; 28 import android.os.UserHandle; 29 import android.sysprop.TelephonyProperties; 30 import android.telecom.Log; 31 import android.telecom.PhoneAccount; 32 import android.telecom.PhoneAccountHandle; 33 import android.telephony.TelephonyManager; 34 import android.text.TextUtils; 35 36 import com.android.internal.os.BaseCommand; 37 import com.android.internal.telecom.ITelecomService; 38 39 import java.io.PrintStream; 40 import java.util.Arrays; 41 import java.util.stream.Collectors; 42 43 public final class Telecom extends BaseCommand { 44 45 /** 46 * Command-line entry point. 47 * 48 * @param args The command-line arguments 49 */ main(String[] args)50 public static void main(String[] args) { 51 // Initialize the telephony module. 52 // TODO: Do it in zygote and RuntimeInit. b/148897549 53 ActivityThread.initializeMainlineModules(); 54 55 (new Telecom()).run(args); 56 } 57 private static final String CALLING_PACKAGE = Telecom.class.getPackageName(); 58 private static final String COMMAND_SET_PHONE_ACCOUNT_ENABLED = "set-phone-account-enabled"; 59 private static final String COMMAND_SET_PHONE_ACCOUNT_DISABLED = "set-phone-account-disabled"; 60 private static final String COMMAND_REGISTER_PHONE_ACCOUNT = "register-phone-account"; 61 private static final String COMMAND_SET_USER_SELECTED_OUTGOING_PHONE_ACCOUNT = 62 "set-user-selected-outgoing-phone-account"; 63 private static final String COMMAND_REGISTER_SIM_PHONE_ACCOUNT = "register-sim-phone-account"; 64 private static final String COMMAND_SET_TEST_CALL_REDIRECTION_APP = "set-test-call-redirection-app"; 65 private static final String COMMAND_SET_TEST_CALL_SCREENING_APP = "set-test-call-screening-app"; 66 private static final String COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP = 67 "add-or-remove-call-companion-app"; 68 private static final String COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT = 69 "set-phone-acct-suggestion-component"; 70 private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account"; 71 private static final String COMMAND_SET_CALL_DIAGNOSTIC_SERVICE = "set-call-diagnostic-service"; 72 private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer"; 73 private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer"; 74 private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression"; 75 private static final String COMMAND_CLEANUP_STUCK_CALLS = "cleanup-stuck-calls"; 76 private static final String COMMAND_CLEANUP_ORPHAN_PHONE_ACCOUNTS = 77 "cleanup-orphan-phone-accounts"; 78 private static final String COMMAND_RESET_CAR_MODE = "reset-car-mode"; 79 80 /** 81 * Change the system dialer package name if a package name was specified, 82 * Example: adb shell telecom set-system-dialer <PACKAGE> 83 * 84 * Restore it to the default if if argument is "default" or no argument is passed. 85 * Example: adb shell telecom set-system-dialer default 86 */ 87 private static final String COMMAND_SET_SYSTEM_DIALER = "set-system-dialer"; 88 private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer"; 89 private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers"; 90 private static final String COMMAND_SET_SIM_COUNT = "set-sim-count"; 91 private static final String COMMAND_GET_SIM_CONFIG = "get-sim-config"; 92 private static final String COMMAND_GET_MAX_PHONES = "get-max-phones"; 93 private static final String COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER = 94 "set-test-emergency-phone-account-package-filter"; 95 /** 96 * Command used to emit a distinct "mark" in the logs. 97 */ 98 private static final String COMMAND_LOG_MARK = "log-mark"; 99 100 private ComponentName mComponent; 101 private String mAccountId; 102 private ITelecomService mTelecomService; 103 private TelephonyManager mTelephonyManager; 104 private IUserManager mUserManager; 105 106 @Override onShowUsage(PrintStream out)107 public void onShowUsage(PrintStream out) { 108 out.println("usage: telecom [subcommand] [options]\n" 109 + "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n" 110 + "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n" 111 + "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n" 112 + "usage: telecom register-sim-phone-account [-e] <COMPONENT> <ID> <USER_SN>" 113 + " <LABEL>: registers a PhoneAccount with CAPABILITY_SIM_SUBSCRIPTION" 114 + " and optionally CAPABILITY_PLACE_EMERGENCY_CALLS if \"-e\" is provided\n" 115 + "usage: telecom set-user-selected-outgoing-phone-account [-e] <COMPONENT> <ID> " 116 + "<USER_SN>\n" 117 + "usage: telecom set-test-call-redirection-app <PACKAGE>\n" 118 + "usage: telecom set-test-call-screening-app <PACKAGE>\n" 119 + "usage: telecom set-phone-acct-suggestion-component <COMPONENT>\n" 120 + "usage: telecom add-or-remove-call-companion-app <PACKAGE> <1/0>\n" 121 + "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN>" 122 + " <LABEL> <ADDRESS>\n" 123 + "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n" 124 + "usage: telecom set-call-diagnostic-service <PACKAGE>\n" 125 + "usage: telecom set-default-dialer <PACKAGE>\n" 126 + "usage: telecom get-default-dialer\n" 127 + "usage: telecom get-system-dialer\n" 128 + "usage: telecom wait-on-handlers\n" 129 + "usage: telecom set-sim-count <COUNT>\n" 130 + "usage: telecom get-sim-config\n" 131 + "usage: telecom get-max-phones\n" 132 + "usage: telecom stop-block-suppression: Stop suppressing the blocked number" 133 + " provider after a call to emergency services.\n" 134 + "usage: telecom cleanup-stuck-calls: Clear any disconnected calls that have" 135 + " gotten wedged in Telecom.\n" 136 + "usage: telecom cleanup-orphan-phone-accounts: remove any phone accounts that" 137 + " no longer have a valid UserHandle or accounts that no longer belongs to an" 138 + " installed package.\n" 139 + "usage: telecom set-emer-phone-account-filter <PACKAGE>\n" 140 + "\n" 141 + "telecom set-phone-account-enabled: Enables the given phone account, if it has" 142 + " already been registered with Telecom.\n" 143 + "\n" 144 + "telecom set-phone-account-disabled: Disables the given phone account, if it" 145 + " has already been registered with telecom.\n" 146 + "\n" 147 + "telecom set-call-diagnostic-service: overrides call diagnostic service.\n" 148 + "telecom set-default-dialer: Sets the override default dialer to the given" 149 + " component; this will override whatever the dialer role is set to.\n" 150 + "\n" 151 + "telecom get-default-dialer: Displays the current default dialer.\n" 152 + "\n" 153 + "telecom get-system-dialer: Displays the current system dialer.\n" 154 + "telecom set-system-dialer: Set the override system dialer to the given" 155 + " component. To remove the override, send \"default\"\n" 156 + "\n" 157 + "telecom wait-on-handlers: Wait until all handlers finish their work.\n" 158 + "\n" 159 + "telecom set-sim-count: Set num SIMs (2 for DSDS, 1 for single SIM." 160 + " This may restart the device.\n" 161 + "\n" 162 + "telecom get-sim-config: Get the mSIM config string. \"DSDS\" for DSDS mode," 163 + " or \"\" for single SIM\n" 164 + "\n" 165 + "telecom get-max-phones: Get the max supported phones from the modem.\n" 166 + "telecom set-test-emergency-phone-account-package-filter <PACKAGE>: sets a" 167 + " package name that will be used for test emergency calls. To clear," 168 + " send an empty package name. Real emergency calls will still be placed" 169 + " over Telephony.\n" 170 + "telecom log-mark <MESSAGE>: emits a message into the telecom logs. Useful for " 171 + "testers to indicate where in the logs various test steps take place.\n" 172 ); 173 } 174 175 @Override onRun()176 public void onRun() throws Exception { 177 mTelecomService = ITelecomService.Stub.asInterface( 178 ServiceManager.getService(Context.TELECOM_SERVICE)); 179 if (mTelecomService == null) { 180 Log.w(this, "onRun: Can't access telecom manager."); 181 showError("Error: Could not access the Telecom Manager. Is the system running?"); 182 return; 183 } 184 185 Looper.prepareMainLooper(); 186 Context context = ActivityThread.systemMain().getSystemContext(); 187 mTelephonyManager = context.getSystemService(TelephonyManager.class); 188 if (mTelephonyManager == null) { 189 Log.w(this, "onRun: Can't access telephony service."); 190 showError("Error: Could not access the Telephony Service. Is the system running?"); 191 return; 192 } 193 194 mUserManager = IUserManager.Stub 195 .asInterface(ServiceManager.getService(Context.USER_SERVICE)); 196 if (mUserManager == null) { 197 Log.w(this, "onRun: Can't access user manager."); 198 showError("Error: Could not access the User Manager. Is the system running?"); 199 return; 200 } 201 Log.i(this, "onRun: parsing command."); 202 String command = nextArgRequired(); 203 switch (command) { 204 case COMMAND_SET_PHONE_ACCOUNT_ENABLED: 205 runSetPhoneAccountEnabled(true); 206 break; 207 case COMMAND_SET_PHONE_ACCOUNT_DISABLED: 208 runSetPhoneAccountEnabled(false); 209 break; 210 case COMMAND_REGISTER_PHONE_ACCOUNT: 211 runRegisterPhoneAccount(); 212 break; 213 case COMMAND_SET_TEST_CALL_REDIRECTION_APP: 214 runSetTestCallRedirectionApp(); 215 break; 216 case COMMAND_SET_TEST_CALL_SCREENING_APP: 217 runSetTestCallScreeningApp(); 218 break; 219 case COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP: 220 runAddOrRemoveCallCompanionApp(); 221 break; 222 case COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT: 223 runSetTestPhoneAcctSuggestionComponent(); 224 break; 225 case COMMAND_SET_CALL_DIAGNOSTIC_SERVICE: 226 runSetCallDiagnosticService(); 227 break; 228 case COMMAND_REGISTER_SIM_PHONE_ACCOUNT: 229 runRegisterSimPhoneAccount(); 230 break; 231 case COMMAND_SET_USER_SELECTED_OUTGOING_PHONE_ACCOUNT: 232 runSetUserSelectedOutgoingPhoneAccount(); 233 break; 234 case COMMAND_UNREGISTER_PHONE_ACCOUNT: 235 runUnregisterPhoneAccount(); 236 break; 237 case COMMAND_STOP_BLOCK_SUPPRESSION: 238 runStopBlockSuppression(); 239 break; 240 case COMMAND_CLEANUP_STUCK_CALLS: 241 runCleanupStuckCalls(); 242 break; 243 case COMMAND_CLEANUP_ORPHAN_PHONE_ACCOUNTS: 244 runCleanupOrphanPhoneAccounts(); 245 break; 246 case COMMAND_RESET_CAR_MODE: 247 runResetCarMode(); 248 break; 249 case COMMAND_SET_DEFAULT_DIALER: 250 runSetDefaultDialer(); 251 break; 252 case COMMAND_GET_DEFAULT_DIALER: 253 runGetDefaultDialer(); 254 break; 255 case COMMAND_SET_SYSTEM_DIALER: 256 runSetSystemDialer(); 257 break; 258 case COMMAND_GET_SYSTEM_DIALER: 259 runGetSystemDialer(); 260 break; 261 case COMMAND_WAIT_ON_HANDLERS: 262 runWaitOnHandler(); 263 break; 264 case COMMAND_SET_SIM_COUNT: 265 runSetSimCount(); 266 break; 267 case COMMAND_GET_SIM_CONFIG: 268 runGetSimConfig(); 269 break; 270 case COMMAND_GET_MAX_PHONES: 271 runGetMaxPhones(); 272 break; 273 case COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER: 274 runSetEmergencyPhoneAccountPackageFilter(); 275 break; 276 case COMMAND_LOG_MARK: 277 runLogMark(); 278 break; 279 default: 280 Log.w(this, "onRun: unknown command: %s", command); 281 throw new IllegalArgumentException ("unknown command '" + command + "'"); 282 } 283 } 284 runSetPhoneAccountEnabled(boolean enabled)285 private void runSetPhoneAccountEnabled(boolean enabled) throws RemoteException { 286 final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs(); 287 final boolean success = mTelecomService.enablePhoneAccount(handle, enabled); 288 if (success) { 289 System.out.println("Success - " + handle + (enabled ? " enabled." : " disabled.")); 290 } else { 291 System.out.println("Error - is " + handle + " a valid PhoneAccount?"); 292 } 293 } 294 runRegisterPhoneAccount()295 private void runRegisterPhoneAccount() throws RemoteException { 296 final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs(); 297 final String label = nextArgRequired(); 298 PhoneAccount account = PhoneAccount.builder(handle, label) 299 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER).build(); 300 mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE); 301 System.out.println("Success - " + handle + " registered."); 302 } 303 runRegisterSimPhoneAccount()304 private void runRegisterSimPhoneAccount() throws RemoteException { 305 boolean isEmergencyAccount = false; 306 String opt; 307 while ((opt = nextOption()) != null) { 308 switch (opt) { 309 case "-e": { 310 isEmergencyAccount = true; 311 break; 312 } 313 } 314 } 315 final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs(); 316 final String label = nextArgRequired(); 317 final String address = nextArgRequired(); 318 int capabilities = PhoneAccount.CAPABILITY_CALL_PROVIDER 319 | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION 320 | (isEmergencyAccount ? PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS : 0); 321 PhoneAccount account = PhoneAccount.builder( 322 handle, label) 323 .setAddress(Uri.parse(address)) 324 .setSubscriptionAddress(Uri.parse(address)) 325 .setCapabilities(capabilities) 326 .setShortDescription(label) 327 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 328 .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) 329 .build(); 330 mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE); 331 System.out.println("Success - " + handle + " registered."); 332 } 333 runSetTestCallRedirectionApp()334 private void runSetTestCallRedirectionApp() throws RemoteException { 335 final String packageName = nextArg(); 336 mTelecomService.setTestDefaultCallRedirectionApp(packageName); 337 } 338 runSetTestCallScreeningApp()339 private void runSetTestCallScreeningApp() throws RemoteException { 340 final String packageName = nextArg(); 341 mTelecomService.setTestDefaultCallScreeningApp(packageName); 342 } 343 runAddOrRemoveCallCompanionApp()344 private void runAddOrRemoveCallCompanionApp() throws RemoteException { 345 final String packageName = nextArgRequired(); 346 String isAdded = nextArgRequired(); 347 boolean isAddedBool = "1".equals(isAdded); 348 mTelecomService.addOrRemoveTestCallCompanionApp(packageName, isAddedBool); 349 } 350 runSetCallDiagnosticService()351 private void runSetCallDiagnosticService() throws RemoteException { 352 String packageName = nextArg(); 353 if ("default".equals(packageName)) packageName = null; 354 mTelecomService.setTestCallDiagnosticService(packageName); 355 System.out.println("Success - " + packageName + " set as call diagnostic service."); 356 } 357 runSetTestPhoneAcctSuggestionComponent()358 private void runSetTestPhoneAcctSuggestionComponent() throws RemoteException { 359 final String componentName = nextArg(); 360 mTelecomService.setTestPhoneAcctSuggestionComponent(componentName); 361 } 362 runSetUserSelectedOutgoingPhoneAccount()363 private void runSetUserSelectedOutgoingPhoneAccount() throws RemoteException { 364 Log.i(this, "runSetUserSelectedOutgoingPhoneAccount"); 365 final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs(); 366 mTelecomService.setUserSelectedOutgoingPhoneAccount(handle); 367 System.out.println("Success - " + handle + " set as default outgoing account."); 368 } 369 runUnregisterPhoneAccount()370 private void runUnregisterPhoneAccount() throws RemoteException { 371 final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs(); 372 mTelecomService.unregisterPhoneAccount(handle, CALLING_PACKAGE); 373 System.out.println("Success - " + handle + " unregistered."); 374 } 375 runStopBlockSuppression()376 private void runStopBlockSuppression() throws RemoteException { 377 mTelecomService.stopBlockSuppression(); 378 } 379 runCleanupStuckCalls()380 private void runCleanupStuckCalls() throws RemoteException { 381 mTelecomService.cleanupStuckCalls(); 382 } 383 runCleanupOrphanPhoneAccounts()384 private void runCleanupOrphanPhoneAccounts() throws RemoteException { 385 System.out.println("Success - cleaned up " + mTelecomService.cleanupOrphanPhoneAccounts() 386 + " phone accounts."); 387 } 388 runResetCarMode()389 private void runResetCarMode() throws RemoteException { 390 mTelecomService.resetCarMode(); 391 } 392 runSetDefaultDialer()393 private void runSetDefaultDialer() throws RemoteException { 394 String packageName = nextArg(); 395 if ("default".equals(packageName)) packageName = null; 396 mTelecomService.setTestDefaultDialer(packageName); 397 System.out.println("Success - " + packageName + " set as override default dialer."); 398 } 399 runSetSystemDialer()400 private void runSetSystemDialer() throws RemoteException { 401 final String flatComponentName = nextArg(); 402 final ComponentName componentName = (flatComponentName.equals("default") 403 ? null : parseComponentName(flatComponentName)); 404 mTelecomService.setSystemDialer(componentName); 405 System.out.println("Success - " + componentName + " set as override system dialer."); 406 } 407 runGetDefaultDialer()408 private void runGetDefaultDialer() throws RemoteException { 409 System.out.println(mTelecomService.getDefaultDialerPackage(CALLING_PACKAGE)); 410 } 411 runGetSystemDialer()412 private void runGetSystemDialer() throws RemoteException { 413 System.out.println(mTelecomService.getSystemDialerPackage(CALLING_PACKAGE)); 414 } 415 runWaitOnHandler()416 private void runWaitOnHandler() throws RemoteException { 417 418 } 419 runSetSimCount()420 private void runSetSimCount() throws RemoteException { 421 if (!callerIsRoot()) { 422 System.out.println("set-sim-count requires adb root"); 423 return; 424 } 425 int numSims = Integer.parseInt(nextArgRequired()); 426 System.out.println("Setting sim count to " + numSims + ". Device may reboot"); 427 mTelephonyManager.switchMultiSimConfig(numSims); 428 } 429 430 /** 431 * Prints the mSIM config to the console. 432 * "DSDS" for a phone in DSDS mode 433 * "" (empty string) for a phone in SS mode 434 */ runGetSimConfig()435 private void runGetSimConfig() throws RemoteException { 436 System.out.println(TelephonyProperties.multi_sim_config().orElse("")); 437 } 438 runGetMaxPhones()439 private void runGetMaxPhones() throws RemoteException { 440 // how many logical modems can be potentially active simultaneously 441 System.out.println(mTelephonyManager.getSupportedModemCount()); 442 } 443 runSetEmergencyPhoneAccountPackageFilter()444 private void runSetEmergencyPhoneAccountPackageFilter() throws RemoteException { 445 String packageName = mArgs.getNextArg(); 446 if (TextUtils.isEmpty(packageName)) { 447 mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(null); 448 System.out.println("Success - filter cleared"); 449 } else { 450 mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(packageName); 451 System.out.println("Success = filter set to " + packageName); 452 } 453 454 } 455 runLogMark()456 private void runLogMark() throws RemoteException { 457 String message = Arrays.stream(mArgs.peekRemainingArgs()).collect(Collectors.joining(" ")); 458 mTelecomService.requestLogMark(message); 459 } 460 getPhoneAccountHandleFromArgs()461 private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException { 462 if (TextUtils.isEmpty(mArgs.peekNextArg())) { 463 return null; 464 } 465 final ComponentName component = parseComponentName(nextArgRequired()); 466 final String accountId = nextArgRequired(); 467 final String userSnInStr = nextArgRequired(); 468 UserHandle userHandle; 469 try { 470 final int userSn = Integer.parseInt(userSnInStr); 471 userHandle = UserHandle.of(mUserManager.getUserHandle(userSn)); 472 } catch (NumberFormatException ex) { 473 Log.w(this, "getPhoneAccountHandleFromArgs - invalid user %s", userSnInStr); 474 throw new IllegalArgumentException ("Invalid user serial number " + userSnInStr); 475 } 476 return new PhoneAccountHandle(component, accountId, userHandle); 477 } 478 callerIsRoot()479 private boolean callerIsRoot() { 480 return Process.ROOT_UID == Process.myUid(); 481 } 482 parseComponentName(String component)483 private ComponentName parseComponentName(String component) { 484 ComponentName cn = ComponentName.unflattenFromString(component); 485 if (cn == null) { 486 throw new IllegalArgumentException ("Invalid component " + component); 487 } 488 return cn; 489 } 490 } 491