Move Telecom shell commands to TelecomShellCommand

1) Move existing telecom shell commands into TelecomShellCommand
2) Make this new file available to the old Telecom commands binary

By moving shell commands to TelecomServiceImpl, we are seeing a
~10X improvement in speed when using shell commands for CTS.

Bug: 327310548
Test: atest CtsTelecomTestCases, manual shell command testing
Change-Id: Ic1d9de208cf65d058784437bf244d5279b676b9c
diff --git a/Android.bp b/Android.bp
index 68a8e39..94654a6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11,6 +11,14 @@
     out: ["com/android/server/telecom/TelecomStatsLog.java"],
 }
 
+filegroup {
+    name: "telecom-shell-commands-src",
+    srcs: [
+        "src/com/android/server/telecom/TelecomShellCommand.java",
+    ],
+    path: "src",
+}
+
 android_library {
     name: "TelecomLib",
     manifest: "AndroidManifestLib.xml",
@@ -33,7 +41,6 @@
     platform_apis: true,
 }
 
-
 // Build the Telecom service.
 android_app {
     name: "Telecom",
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index f3d91f1..780db19 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -53,8 +53,11 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.OutcomeReceiver;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.provider.BlockedNumberContract;
 import android.provider.Settings;
@@ -72,12 +75,14 @@
 import android.util.EventLog;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telecom.ICallControl;
 import com.android.internal.telecom.ICallEventCallback;
 import com.android.internal.telecom.ITelecomService;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.modules.utils.BasicShellCommandHandler;
 import com.android.server.telecom.components.UserCallIntentProcessorFactory;
 import com.android.server.telecom.flags.FeatureFlags;
 import com.android.server.telecom.settings.BlockedNumbersActivity;
@@ -2092,6 +2097,14 @@
             }
         }
 
+        @Override
+        public int handleShellCommand(@NonNull ParcelFileDescriptor in,
+                @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
+                @NonNull String[] args) {
+            return new TelecomShellCommand(this, mContext).exec(this,
+                    in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args);
+        }
+
         /**
          * Print all feature flag configurations that Telecom is using for debugging purposes.
          */
diff --git a/src/com/android/server/telecom/TelecomShellCommand.java b/src/com/android/server/telecom/TelecomShellCommand.java
new file mode 100644
index 0000000..557002c
--- /dev/null
+++ b/src/com/android/server/telecom/TelecomShellCommand.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.sysprop.TelephonyProperties;
+import android.telecom.Log;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.android.internal.telecom.ITelecomService;
+import com.android.modules.utils.BasicShellCommandHandler;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+/**
+ * Implements shell commands sent to telecom using the "adb shell cmd telecom..." command from shell
+ * or CTS.
+ */
+public class TelecomShellCommand extends BasicShellCommandHandler {
+    private static final String CALLING_PACKAGE = TelecomShellCommand.class.getPackageName();
+    private static final String COMMAND_SET_PHONE_ACCOUNT_ENABLED = "set-phone-account-enabled";
+    private static final String COMMAND_SET_PHONE_ACCOUNT_DISABLED = "set-phone-account-disabled";
+    private static final String COMMAND_REGISTER_PHONE_ACCOUNT = "register-phone-account";
+    private static final String COMMAND_SET_USER_SELECTED_OUTGOING_PHONE_ACCOUNT =
+            "set-user-selected-outgoing-phone-account";
+    private static final String COMMAND_REGISTER_SIM_PHONE_ACCOUNT = "register-sim-phone-account";
+    private static final String COMMAND_SET_TEST_CALL_REDIRECTION_APP =
+            "set-test-call-redirection-app";
+    private static final String COMMAND_SET_TEST_CALL_SCREENING_APP = "set-test-call-screening-app";
+    private static final String COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP =
+            "add-or-remove-call-companion-app";
+    private static final String COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT =
+            "set-phone-acct-suggestion-component";
+    private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
+    private static final String COMMAND_SET_CALL_DIAGNOSTIC_SERVICE = "set-call-diagnostic-service";
+    private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
+    private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
+    private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression";
+    private static final String COMMAND_CLEANUP_STUCK_CALLS = "cleanup-stuck-calls";
+    private static final String COMMAND_CLEANUP_ORPHAN_PHONE_ACCOUNTS =
+            "cleanup-orphan-phone-accounts";
+    private static final String COMMAND_RESET_CAR_MODE = "reset-car-mode";
+    private static final String COMMAND_IS_NON_IN_CALL_SERVICE_BOUND =
+            "is-non-ui-in-call-service-bound";
+
+    /**
+     * Change the system dialer package name if a package name was specified,
+     * Example: adb shell telecom set-system-dialer <PACKAGE>
+     *
+     * Restore it to the default if if argument is "default" or no argument is passed.
+     * Example: adb shell telecom set-system-dialer default
+     */
+    private static final String COMMAND_SET_SYSTEM_DIALER = "set-system-dialer";
+    private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer";
+    private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers";
+    private static final String COMMAND_SET_SIM_COUNT = "set-sim-count";
+    private static final String COMMAND_GET_SIM_CONFIG = "get-sim-config";
+    private static final String COMMAND_GET_MAX_PHONES = "get-max-phones";
+    private static final String COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER =
+            "set-test-emergency-phone-account-package-filter";
+    /**
+     * Command used to emit a distinct "mark" in the logs.
+     */
+    private static final String COMMAND_LOG_MARK = "log-mark";
+
+    private final Context mContext;
+    private final ITelecomService mTelecomService;
+    private TelephonyManager mTelephonyManager;
+    private UserManager mUserManager;
+
+    public TelecomShellCommand(ITelecomService binder, Context context) {
+        mTelecomService = binder;
+        mContext = context;
+    }
+
+    @Override
+    public int onCommand(String command) {
+        if (command == null || command.isEmpty()) {
+            onHelp();
+            return 0;
+        }
+        try {
+            switch (command) {
+                case COMMAND_SET_PHONE_ACCOUNT_ENABLED:
+                    runSetPhoneAccountEnabled(true);
+                    break;
+                case COMMAND_SET_PHONE_ACCOUNT_DISABLED:
+                    runSetPhoneAccountEnabled(false);
+                    break;
+                case COMMAND_REGISTER_PHONE_ACCOUNT:
+                    runRegisterPhoneAccount();
+                    break;
+                case COMMAND_SET_TEST_CALL_REDIRECTION_APP:
+                    runSetTestCallRedirectionApp();
+                    break;
+                case COMMAND_SET_TEST_CALL_SCREENING_APP:
+                    runSetTestCallScreeningApp();
+                    break;
+                case COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP:
+                    runAddOrRemoveCallCompanionApp();
+                    break;
+                case COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT:
+                    runSetTestPhoneAcctSuggestionComponent();
+                    break;
+                case COMMAND_SET_CALL_DIAGNOSTIC_SERVICE:
+                    runSetCallDiagnosticService();
+                    break;
+                case COMMAND_REGISTER_SIM_PHONE_ACCOUNT:
+                    runRegisterSimPhoneAccount();
+                    break;
+                case COMMAND_SET_USER_SELECTED_OUTGOING_PHONE_ACCOUNT:
+                    runSetUserSelectedOutgoingPhoneAccount();
+                    break;
+                case COMMAND_UNREGISTER_PHONE_ACCOUNT:
+                    runUnregisterPhoneAccount();
+                    break;
+                case COMMAND_STOP_BLOCK_SUPPRESSION:
+                    runStopBlockSuppression();
+                    break;
+                case COMMAND_CLEANUP_STUCK_CALLS:
+                    runCleanupStuckCalls();
+                    break;
+                case COMMAND_CLEANUP_ORPHAN_PHONE_ACCOUNTS:
+                    runCleanupOrphanPhoneAccounts();
+                    break;
+                case COMMAND_RESET_CAR_MODE:
+                    runResetCarMode();
+                    break;
+                case COMMAND_SET_DEFAULT_DIALER:
+                    runSetDefaultDialer();
+                    break;
+                case COMMAND_GET_DEFAULT_DIALER:
+                    runGetDefaultDialer();
+                    break;
+                case COMMAND_SET_SYSTEM_DIALER:
+                    runSetSystemDialer();
+                    break;
+                case COMMAND_GET_SYSTEM_DIALER:
+                    runGetSystemDialer();
+                    break;
+                case COMMAND_WAIT_ON_HANDLERS:
+                    runWaitOnHandler();
+                    break;
+                case COMMAND_SET_SIM_COUNT:
+                    runSetSimCount();
+                    break;
+                case COMMAND_GET_SIM_CONFIG:
+                    runGetSimConfig();
+                    break;
+                case COMMAND_GET_MAX_PHONES:
+                    runGetMaxPhones();
+                    break;
+                case COMMAND_IS_NON_IN_CALL_SERVICE_BOUND:
+                    runIsNonUiInCallServiceBound();
+                    break;
+                case COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER:
+                    runSetEmergencyPhoneAccountPackageFilter();
+                    break;
+                case COMMAND_LOG_MARK:
+                    runLogMark();
+                    break;
+                default:
+                    return handleDefaultCommands(command);
+            }
+        } catch (Exception e) {
+            getErrPrintWriter().println("Command["+ command + "]: Error: " + e);
+            return -1;
+        }
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        getOutPrintWriter().println("usage: telecom [subcommand] [options]\n"
+                + "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n"
+                + "usage: telecom register-sim-phone-account [-e] <COMPONENT> <ID> <USER_SN>"
+                + " <LABEL>: registers a PhoneAccount with CAPABILITY_SIM_SUBSCRIPTION"
+                + " and optionally CAPABILITY_PLACE_EMERGENCY_CALLS if \"-e\" is provided\n"
+                + "usage: telecom set-user-selected-outgoing-phone-account [-e] <COMPONENT> <ID> "
+                + "<USER_SN>\n"
+                + "usage: telecom set-test-call-redirection-app <PACKAGE>\n"
+                + "usage: telecom set-test-call-screening-app <PACKAGE>\n"
+                + "usage: telecom set-phone-acct-suggestion-component <COMPONENT>\n"
+                + "usage: telecom add-or-remove-call-companion-app <PACKAGE> <1/0>\n"
+                + "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN>"
+                + " <LABEL> <ADDRESS>\n"
+                + "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom set-call-diagnostic-service <PACKAGE>\n"
+                + "usage: telecom set-default-dialer <PACKAGE>\n"
+                + "usage: telecom get-default-dialer\n"
+                + "usage: telecom get-system-dialer\n"
+                + "usage: telecom wait-on-handlers\n"
+                + "usage: telecom set-sim-count <COUNT>\n"
+                + "usage: telecom get-sim-config\n"
+                + "usage: telecom get-max-phones\n"
+                + "usage: telecom stop-block-suppression: Stop suppressing the blocked number"
+                + " provider after a call to emergency services.\n"
+                + "usage: telecom cleanup-stuck-calls: Clear any disconnected calls that have"
+                + " gotten wedged in Telecom.\n"
+                + "usage: telecom cleanup-orphan-phone-accounts: remove any phone accounts that"
+                + " no longer have a valid UserHandle or accounts that no longer belongs to an"
+                + " installed package.\n"
+                + "usage: telecom set-emer-phone-account-filter <PACKAGE>\n"
+                + "\n"
+                + "telecom set-phone-account-enabled: Enables the given phone account, if it has"
+                + " already been registered with Telecom.\n"
+                + "\n"
+                + "telecom set-phone-account-disabled: Disables the given phone account, if it"
+                + " has already been registered with telecom.\n"
+                + "\n"
+                + "telecom set-call-diagnostic-service: overrides call diagnostic service.\n"
+                + "telecom set-default-dialer: Sets the override default dialer to the given"
+                + " component; this will override whatever the dialer role is set to.\n"
+                + "\n"
+                + "telecom get-default-dialer: Displays the current default dialer.\n"
+                + "\n"
+                + "telecom get-system-dialer: Displays the current system dialer.\n"
+                + "telecom set-system-dialer: Set the override system dialer to the given"
+                + " component. To remove the override, send \"default\"\n"
+                + "\n"
+                + "telecom wait-on-handlers: Wait until all handlers finish their work.\n"
+                + "\n"
+                + "telecom set-sim-count: Set num SIMs (2 for DSDS, 1 for single SIM."
+                + " This may restart the device.\n"
+                + "\n"
+                + "telecom get-sim-config: Get the mSIM config string. \"DSDS\" for DSDS mode,"
+                + " or \"\" for single SIM\n"
+                + "\n"
+                + "telecom get-max-phones: Get the max supported phones from the modem.\n"
+                + "telecom set-test-emergency-phone-account-package-filter <PACKAGE>: sets a"
+                + " package name that will be used for test emergency calls. To clear,"
+                + " send an empty package name. Real emergency calls will still be placed"
+                + " over Telephony.\n"
+                + "telecom log-mark <MESSAGE>: emits a message into the telecom logs.  Useful for "
+                + "testers to indicate where in the logs various test steps take place.\n"
+                + "telecom is-non-ui-in-call-service-bound <PACKAGE>: queries a particular "
+                + "non-ui-InCallService in InCallController to determine if it is bound \n"
+        );
+    }
+    private void runSetPhoneAccountEnabled(boolean enabled) throws RemoteException {
+        final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+        final boolean success =  mTelecomService.enablePhoneAccount(handle, enabled);
+        if (success) {
+            getOutPrintWriter().println("Success - " + handle
+                    + (enabled ? " enabled." : " disabled."));
+        } else {
+            getOutPrintWriter().println("Error - is " + handle + " a valid PhoneAccount?");
+        }
+    }
+
+    private void runRegisterPhoneAccount() throws RemoteException {
+        final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+        final String label = getNextArgRequired();
+        PhoneAccount account = PhoneAccount.builder(handle, label)
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER).build();
+        mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE);
+        getOutPrintWriter().println("Success - " + handle + " registered.");
+    }
+
+    private void runRegisterSimPhoneAccount() throws RemoteException {
+        boolean isEmergencyAccount = false;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-e": {
+                    isEmergencyAccount = true;
+                    break;
+                }
+            }
+        }
+        final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+        final String label = getNextArgRequired();
+        final String address = getNextArgRequired();
+        int capabilities = PhoneAccount.CAPABILITY_CALL_PROVIDER
+                | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
+                | (isEmergencyAccount ? PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS : 0);
+        PhoneAccount account = PhoneAccount.builder(
+                        handle, label)
+                .setAddress(Uri.parse(address))
+                .setSubscriptionAddress(Uri.parse(address))
+                .setCapabilities(capabilities)
+                .setShortDescription(label)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+                .build();
+        mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE);
+        getOutPrintWriter().println("Success - " + handle + " registered.");
+    }
+
+    private void runSetTestCallRedirectionApp() throws RemoteException {
+        final String packageName = getNextArg();
+        mTelecomService.setTestDefaultCallRedirectionApp(packageName);
+    }
+
+    private void runSetTestCallScreeningApp() throws RemoteException {
+        final String packageName = getNextArg();
+        mTelecomService.setTestDefaultCallScreeningApp(packageName);
+    }
+
+    private void runAddOrRemoveCallCompanionApp() throws RemoteException {
+        final String packageName = getNextArgRequired();
+        String isAdded = getNextArgRequired();
+        boolean isAddedBool = "1".equals(isAdded);
+        mTelecomService.addOrRemoveTestCallCompanionApp(packageName, isAddedBool);
+    }
+
+    private void runSetCallDiagnosticService() throws RemoteException {
+        String packageName = getNextArg();
+        if ("default".equals(packageName)) packageName = null;
+        mTelecomService.setTestCallDiagnosticService(packageName);
+        getOutPrintWriter().println("Success - " + packageName
+                + " set as call diagnostic service.");
+    }
+
+    private void runSetTestPhoneAcctSuggestionComponent() throws RemoteException {
+        final String componentName = getNextArg();
+        mTelecomService.setTestPhoneAcctSuggestionComponent(componentName);
+    }
+
+    private void runSetUserSelectedOutgoingPhoneAccount() throws RemoteException {
+        Log.i(this, "runSetUserSelectedOutgoingPhoneAccount");
+        final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+        mTelecomService.setUserSelectedOutgoingPhoneAccount(handle);
+        getOutPrintWriter().println("Success - " + handle + " set as default outgoing account.");
+    }
+
+    private void runUnregisterPhoneAccount() throws RemoteException {
+        final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+        mTelecomService.unregisterPhoneAccount(handle, CALLING_PACKAGE);
+        getOutPrintWriter().println("Success - " + handle + " unregistered.");
+    }
+
+    private void runStopBlockSuppression() throws RemoteException {
+        mTelecomService.stopBlockSuppression();
+    }
+
+    private void runCleanupStuckCalls() throws RemoteException {
+        mTelecomService.cleanupStuckCalls();
+    }
+
+    private void runCleanupOrphanPhoneAccounts() throws RemoteException {
+        getOutPrintWriter().println("Success - cleaned up "
+                + mTelecomService.cleanupOrphanPhoneAccounts()
+                + "  phone accounts.");
+    }
+
+    private void runResetCarMode() throws RemoteException {
+        mTelecomService.resetCarMode();
+    }
+
+    private void runSetDefaultDialer() throws RemoteException {
+        String packageName = getNextArg();
+        if ("default".equals(packageName)) packageName = null;
+        mTelecomService.setTestDefaultDialer(packageName);
+        getOutPrintWriter().println("Success - " + packageName
+                + " set as override default dialer.");
+    }
+
+    private void runSetSystemDialer() throws RemoteException {
+        final String flatComponentName = getNextArg();
+        final ComponentName componentName = (flatComponentName.equals("default")
+                ? null : parseComponentName(flatComponentName));
+        mTelecomService.setSystemDialer(componentName);
+        getOutPrintWriter().println("Success - " + componentName + " set as override system dialer.");
+    }
+
+    private void runGetDefaultDialer() throws RemoteException {
+        getOutPrintWriter().println(mTelecomService.getDefaultDialerPackage(CALLING_PACKAGE));
+    }
+
+    private void runGetSystemDialer() throws RemoteException {
+        getOutPrintWriter().println(mTelecomService.getSystemDialerPackage(CALLING_PACKAGE));
+    }
+
+    private void runWaitOnHandler() throws RemoteException {
+
+    }
+
+    private void runSetSimCount() throws RemoteException {
+        if (!callerIsRoot()) {
+            getOutPrintWriter().println("set-sim-count requires adb root");
+            return;
+        }
+        int numSims = Integer.parseInt(getNextArgRequired());
+        getOutPrintWriter().println("Setting sim count to " + numSims + ". Device may reboot");
+        getTelephonyManager().switchMultiSimConfig(numSims);
+    }
+
+    /**
+     * prints out whether a particular non-ui InCallServices is bound in a call
+     */
+    public void runIsNonUiInCallServiceBound() throws RemoteException {
+        if (TextUtils.isEmpty(peekNextArg())) {
+            getOutPrintWriter().println("No Argument passed. Please pass a <PACKAGE_NAME> to "
+                    + "lookup.");
+        } else {
+            getOutPrintWriter().println(
+                    String.valueOf(mTelecomService.isNonUiInCallServiceBound(getNextArg())));
+        }
+    }
+
+    /**
+     * Prints the mSIM config to the console.
+     * "DSDS" for a phone in DSDS mode
+     * "" (empty string) for a phone in SS mode
+     */
+    private void runGetSimConfig() throws RemoteException {
+        getOutPrintWriter().println(TelephonyProperties.multi_sim_config().orElse(""));
+    }
+
+    private void runGetMaxPhones() throws RemoteException {
+        // how many logical modems can be potentially active simultaneously
+        getOutPrintWriter().println(getTelephonyManager().getSupportedModemCount());
+    }
+
+    private void runSetEmergencyPhoneAccountPackageFilter() throws RemoteException {
+        String packageName = getNextArg();
+        if (TextUtils.isEmpty(packageName)) {
+            mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(null);
+            getOutPrintWriter().println("Success - filter cleared");
+        } else {
+            mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(packageName);
+            getOutPrintWriter().println("Success = filter set to " + packageName);
+        }
+
+    }
+
+    private void runLogMark() throws RemoteException {
+        String message = Arrays.stream(peekRemainingArgs()).collect(Collectors.joining(" "));
+        mTelecomService.requestLogMark(message);
+    }
+
+    private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException {
+        if (TextUtils.isEmpty(peekNextArg())) {
+            return null;
+        }
+        final ComponentName component = parseComponentName(getNextArgRequired());
+        final String accountId = getNextArgRequired();
+        final String userSnInStr = getNextArgRequired();
+        UserHandle userHandle;
+        try {
+            final int userSn = Integer.parseInt(userSnInStr);
+            userHandle = UserHandle.of(getUserManager().getUserHandle(userSn));
+        } catch (NumberFormatException ex) {
+            Log.w(this, "getPhoneAccountHandleFromArgs - invalid user %s", userSnInStr);
+            throw new IllegalArgumentException ("Invalid user serial number " + userSnInStr);
+        }
+        return new PhoneAccountHandle(component, accountId, userHandle);
+    }
+
+    private boolean callerIsRoot() {
+        return Process.ROOT_UID == Process.myUid();
+    }
+
+    private ComponentName parseComponentName(String component) {
+        ComponentName cn = ComponentName.unflattenFromString(component);
+        if (cn == null) {
+            throw new IllegalArgumentException ("Invalid component " + component);
+        }
+        return cn;
+    }
+
+    private TelephonyManager getTelephonyManager() throws IllegalStateException {
+        if (mTelephonyManager == null) {
+            mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+        }
+        if (mTelephonyManager == null) {
+            Log.w(this, "getTelephonyManager: Can't access telephony service.");
+            throw new IllegalStateException("Could not access the Telephony Service. Is the system "
+                    + "running?");
+        }
+        return mTelephonyManager;
+    }
+
+    private UserManager getUserManager() throws IllegalStateException {
+        if (mUserManager == null) {
+            mUserManager = mContext.getSystemService(UserManager.class);
+        }
+        if (mUserManager == null) {
+            Log.w(this, "getUserManager: Can't access UserManager service.");
+            throw new IllegalStateException("Could not access the UserManager Service. Is the "
+                    + "system running?");
+        }
+        return mUserManager;
+    }
+}