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