1 /*
2  * Copyright (C) 2022 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 package com.android.car;
17 
18 import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS;
19 import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME;
20 import static android.car.Car.PERMISSION_CAR_POWER;
21 import static android.car.Car.PERMISSION_CONTROL_CAR_POWER_POLICY;
22 import static android.car.Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG;
23 import static android.car.Car.PERMISSION_USE_CAR_WATCHDOG;
24 import static android.car.VehicleAreaSeat.SEAT_UNKNOWN;
25 import static android.car.settings.CarSettings.Global.FORCED_DAY_NIGHT_MODE;
26 import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED;
27 import static android.hardware.automotive.vehicle.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER;
28 import static android.hardware.automotive.vehicle.UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS;
29 import static android.hardware.automotive.vehicle.UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER;
30 import static android.hardware.automotive.vehicle.UserIdentificationAssociationType.CUSTOM_1;
31 import static android.hardware.automotive.vehicle.UserIdentificationAssociationType.CUSTOM_2;
32 import static android.hardware.automotive.vehicle.UserIdentificationAssociationType.CUSTOM_3;
33 import static android.hardware.automotive.vehicle.UserIdentificationAssociationType.CUSTOM_4;
34 import static android.hardware.automotive.vehicle.UserIdentificationAssociationType.KEY_FOB;
35 import static android.media.AudioManager.FLAG_SHOW_UI;
36 
37 import static com.android.car.CarServiceUtils.toIntArray;
38 import static com.android.car.hal.property.HalPropertyDebugUtils.toAreaIdString;
39 import static com.android.car.hal.property.HalPropertyDebugUtils.toPropertyIdString;
40 import static com.android.car.hal.property.HalPropertyDebugUtils.toPropertyId;
41 import static com.android.car.power.PolicyReader.POWER_STATE_ON;
42 import static com.android.car.power.PolicyReader.POWER_STATE_WAIT_FOR_VHAL;
43 
44 import android.annotation.NonNull;
45 import android.annotation.Nullable;
46 import android.annotation.UserIdInt;
47 import android.app.ActivityManager;
48 import android.app.ActivityOptions;
49 import android.app.UiModeManager;
50 import android.car.Car;
51 import android.car.CarOccupantZoneManager;
52 import android.car.CarVersion;
53 import android.car.SyncResultCallback;
54 import android.car.VehiclePropertyIds;
55 import android.car.builtin.content.pm.PackageManagerHelper;
56 import android.car.builtin.display.DisplayManagerHelper;
57 import android.car.builtin.input.InputManagerHelper;
58 import android.car.builtin.os.BuildHelper;
59 import android.car.builtin.os.UserManagerHelper;
60 import android.car.builtin.util.Slogf;
61 import android.car.builtin.widget.LockPatternHelper;
62 import android.car.content.pm.CarPackageManager;
63 import android.car.drivingstate.CarUxRestrictions;
64 import android.car.feature.Flags;
65 import android.car.input.CarInputManager;
66 import android.car.input.CustomInputEvent;
67 import android.car.input.RotaryEvent;
68 import android.car.media.IAudioZonesMirrorStatusCallback;
69 import android.car.telemetry.CarTelemetryManager;
70 import android.car.telemetry.TelemetryProto.TelemetryError;
71 import android.car.user.CarUserManager;
72 import android.car.user.UserCreationRequest;
73 import android.car.user.UserCreationResult;
74 import android.car.user.UserIdentificationAssociationResponse;
75 import android.car.user.UserRemovalRequest;
76 import android.car.user.UserRemovalResult;
77 import android.car.user.UserSwitchRequest;
78 import android.car.user.UserSwitchResult;
79 import android.car.util.concurrent.AsyncFuture;
80 import android.car.watchdog.CarWatchdogManager;
81 import android.car.watchdog.IoOveruseConfiguration;
82 import android.car.watchdog.PerStateBytes;
83 import android.car.watchdog.ResourceOveruseConfiguration;
84 import android.content.ComponentName;
85 import android.content.Context;
86 import android.content.Intent;
87 import android.content.ServiceConnection;
88 import android.content.pm.PackageManager;
89 import android.hardware.automotive.vehicle.CreateUserRequest;
90 import android.hardware.automotive.vehicle.CreateUserStatus;
91 import android.hardware.automotive.vehicle.InitialUserInfoResponse;
92 import android.hardware.automotive.vehicle.InitialUserInfoResponseAction;
93 import android.hardware.automotive.vehicle.RemoveUserRequest;
94 import android.hardware.automotive.vehicle.SwitchUserMessageType;
95 import android.hardware.automotive.vehicle.SwitchUserRequest;
96 import android.hardware.automotive.vehicle.SwitchUserStatus;
97 import android.hardware.automotive.vehicle.UserIdentificationAssociation;
98 import android.hardware.automotive.vehicle.UserIdentificationAssociationValue;
99 import android.hardware.automotive.vehicle.UserIdentificationGetRequest;
100 import android.hardware.automotive.vehicle.UserIdentificationResponse;
101 import android.hardware.automotive.vehicle.UserIdentificationSetAssociation;
102 import android.hardware.automotive.vehicle.UserIdentificationSetRequest;
103 import android.hardware.automotive.vehicle.UserInfo;
104 import android.hardware.automotive.vehicle.UsersInfo;
105 import android.hardware.automotive.vehicle.VehicleArea;
106 import android.hardware.automotive.vehicle.VehicleDisplay;
107 import android.hardware.automotive.vehicle.VehicleGear;
108 import android.hardware.automotive.vehicle.VehiclePropError;
109 import android.hardware.display.DisplayManager;
110 import android.hardware.input.InputManager;
111 import android.os.Binder;
112 import android.os.FileUtils;
113 import android.os.IBinder;
114 import android.os.NewUserRequest;
115 import android.os.NewUserResponse;
116 import android.os.PersistableBundle;
117 import android.os.Process;
118 import android.os.RemoteException;
119 import android.os.ServiceSpecificException;
120 import android.os.SystemClock;
121 import android.os.UserHandle;
122 import android.os.UserManager;
123 import android.provider.Settings;
124 import android.text.TextUtils;
125 import android.util.ArrayMap;
126 import android.util.SparseArray;
127 import android.view.Display;
128 import android.view.InputDevice;
129 import android.view.KeyEvent;
130 import android.view.MotionEvent;
131 
132 import com.android.car.am.FixedActivityService;
133 import com.android.car.audio.CarAudioService;
134 import com.android.car.evs.CarEvsService;
135 import com.android.car.garagemode.GarageModeService;
136 import com.android.car.hal.HalCallback;
137 import com.android.car.hal.HalPropConfig;
138 import com.android.car.hal.HalPropValue;
139 import com.android.car.hal.InputHalService;
140 import com.android.car.hal.PowerHalService;
141 import com.android.car.hal.UserHalHelper;
142 import com.android.car.hal.UserHalService;
143 import com.android.car.hal.VehicleHal;
144 import com.android.car.internal.util.DebugUtils;
145 import com.android.car.internal.util.IndentingPrintWriter;
146 import com.android.car.pm.CarPackageManagerService;
147 import com.android.car.power.CarPowerManagementService;
148 import com.android.car.systeminterface.SystemInterface;
149 import com.android.car.telemetry.CarTelemetryService;
150 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
151 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
152 import com.android.car.telemetry.util.IoUtils;
153 import com.android.car.user.CarUserService;
154 import com.android.car.user.UserHandleHelper;
155 import com.android.car.watchdog.CarWatchdogService;
156 import com.android.internal.util.Preconditions;
157 import com.android.modules.utils.BasicShellCommandHandler;
158 
159 import java.io.BufferedInputStream;
160 import java.io.ByteArrayOutputStream;
161 import java.io.File;
162 import java.io.FileInputStream;
163 import java.io.IOException;
164 import java.time.Duration;
165 import java.util.ArrayList;
166 import java.util.Arrays;
167 import java.util.Collections;
168 import java.util.List;
169 import java.util.Locale;
170 import java.util.Map;
171 import java.util.Objects;
172 import java.util.concurrent.CountDownLatch;
173 import java.util.concurrent.ExecutionException;
174 import java.util.concurrent.Executor;
175 import java.util.concurrent.Executors;
176 import java.util.concurrent.TimeUnit;
177 import java.util.concurrent.TimeoutException;
178 import java.util.concurrent.atomic.AtomicBoolean;
179 import java.util.concurrent.atomic.AtomicInteger;
180 import java.util.concurrent.atomic.AtomicLong;
181 
182 final class CarShellCommand extends BasicShellCommandHandler {
183 
184     private static final String NO_INITIAL_USER = "N/A";
185 
186     private static final String TAG = CarLog.tagFor(CarShellCommand.class);
187     private static final boolean VERBOSE = false;
188 
189     private static final String COMMAND_HELP = "-h";
190     private static final String COMMAND_DAY_NIGHT_MODE = "day-night-mode";
191     private static final String COMMAND_INJECT_VHAL_EVENT = "inject-vhal-event";
192     private static final String COMMAND_INJECT_ERROR_EVENT = "inject-error-event";
193     private static final String COMMAND_INJECT_CONTINUOUS_EVENT = "inject-continuous-events";
194     private static final String COMMAND_ENABLE_UXR = "enable-uxr";
195     private static final String COMMAND_GARAGE_MODE = "garage-mode";
196     private static final String COMMAND_GET_DO_ACTIVITIES = "get-do-activities";
197     private static final String COMMAND_GET_CARPROPERTYCONFIG = "get-carpropertyconfig";
198     private static final String COMMAND_GET_PROPERTY_VALUE = "get-property-value";
199     private static final String COMMAND_SET_PROPERTY_VALUE = "set-property-value";
200     private static final String COMMAND_PROJECTION_AP_TETHERING = "projection-tethering";
201     private static final String COMMAND_PROJECTION_AP_STABLE_CONFIG =
202             "projection-stable-lohs-config";
203     private static final String COMMAND_PROJECTION_UI_MODE = "projection-ui-mode";
204     private static final String COMMAND_RESUME = "resume";
205     private static final String COMMAND_SUSPEND = "suspend";
206     private static final String COMMAND_HIBERNATE = "hibernate";
207     private static final String COMMAND_SET_DISPLAY_STATE = "set-display-state";
208     private static final String PARAM_SIMULATE = "--simulate";
209     private static final String PARAM_REAL = "--real";
210     private static final String PARAM_AUTO = "--auto";
211     private static final String PARAM_SKIP_GARAGEMODE = "--skip-garagemode";
212     private static final String PARAM_REBOOT = "--reboot";
213     private static final String PARAM_WAKEUP_AFTER = "--wakeup-after";
214     private static final String PARAM_CANCEL_AFTER = "--cancel-after";
215     private static final String PARAM_FREE_MEMORY = "--free-memory";
216     private static final String COMMAND_SET_UID_TO_ZONE = "set-audio-zone-for-uid";
217     private static final String COMMAND_RESET_VOLUME_CONTEXT = "reset-selected-volume-context";
218     private static final String COMMAND_SET_MUTE_CAR_VOLUME_GROUP = "set-mute-car-volume-group";
219     private static final String COMMAND_SET_GROUP_VOLUME = "set-group-volume";
220     private static final String COMMAND_SET_AUDIO_MIRROR = "set-audio-mirror";
221     private static final String COMMAND_UNSET_AUDIO_MIRROR = "unset-audio-mirror";
222     private static final String COMMAND_START_FIXED_ACTIVITY_MODE = "start-fixed-activity-mode";
223     private static final String COMMAND_STOP_FIXED_ACTIVITY_MODE = "stop-fixed-activity-mode";
224     private static final String COMMAND_ENABLE_FEATURE = "enable-feature";
225     private static final String COMMAND_DISABLE_FEATURE = "disable-feature";
226     private static final String COMMAND_INJECT_KEY = "inject-key";
227     private static final String COMMAND_INJECT_MOTION = "inject-motion";
228     private static final String COMMAND_INJECT_ROTARY = "inject-rotary";
229     private static final String COMMAND_INJECT_CUSTOM_INPUT = "inject-custom-input";
230     private static final String COMMAND_CHECK_LOCK_IS_SECURE = "check-lock-is-secure";
231     private static final String COMMAND_CHECK_FAKE_VHAL = "check-fake-vhal";
232     private static final String COMMAND_GET_INITIAL_USER_INFO = "get-initial-user-info";
233     private static final String COMMAND_SWITCH_USER = "switch-user";
234     private static final String COMMAND_LOGOUT_USER = "logout-user";
235     private static final String COMMAND_REMOVE_USER = "remove-user";
236     private static final String COMMAND_CREATE_USER = "create-user";
237     private static final String COMMAND_GET_INITIAL_USER = "get-initial-user";
238     private static final String COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE =
239             "set-occupant-zone-for-user";
240     private static final String COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE =
241             "reset-user-in-occupant-zone";
242     private static final String COMMAND_GET_USER_AUTH_ASSOCIATION =
243             "get-user-auth-association";
244     private static final String COMMAND_SET_USER_AUTH_ASSOCIATION =
245             "set-user-auth-association";
246     private static final String COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE =
247             "set-start-bg-users-on-garage-mode";
248     private static final String COMMAND_DEFINE_POWER_POLICY = "define-power-policy";
249     private static final String COMMAND_APPLY_POWER_POLICY = "apply-power-policy";
250     private static final String COMMAND_DEFINE_POWER_POLICY_GROUP = "define-power-policy-group";
251     private static final String COMMAND_SET_POWER_POLICY_GROUP = "set-power-policy-group";
252     private static final String COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY =
253             "apply-cts-verifier-power-off-policy";
254     private static final String COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY =
255             "apply-cts-verifier-power-on-policy";
256     private static final String COMMAND_POWER_OFF = "power-off";
257     private static final String COMMAND_SILENT_MODE = "silent-mode";
258     // Used with COMMAND_SILENT_MODE for forced silent: "forced-silent"
259     private static final String SILENT_MODE_FORCED_SILENT =
260             CarPowerManagementService.SILENT_MODE_FORCED_SILENT;
261     // Used with COMMAND_SILENT_MODE for forced non silent: "forced-non-silent"
262     private static final String SILENT_MODE_FORCED_NON_SILENT =
263             CarPowerManagementService.SILENT_MODE_FORCED_NON_SILENT;
264     // Used with COMMAND_SILENT_MODE for non forced silent mode: "non-forced-silent-mode"
265     private static final String SILENT_MODE_NON_FORCED =
266             CarPowerManagementService.SILENT_MODE_NON_FORCED;
267 
268     private static final String COMMAND_EMULATE_DRIVING_STATE = "emulate-driving-state";
269     private static final String DRIVING_STATE_DRIVE = "drive";
270     private static final String DRIVING_STATE_PARK = "park";
271     private static final String DRIVING_STATE_REVERSE = "reverse";
272     private static final String DRIVING_STATE_NEUTRAL = "neutral";
273 
274     private static final String COMMAND_SET_REARVIEW_CAMERA_ID = "set-rearview-camera-id";
275     private static final String COMMAND_GET_REARVIEW_CAMERA_ID = "get-rearview-camera-id";
276     private static final String COMMAND_SET_CAMERA_ID = "set-camera-id";
277     private static final String COMMAND_GET_CAMERA_ID = "get-camera-id";
278     private static final String COMMAND_ENABLE_CAMERA_SERVICE_TYPE = "enable-camera-service-type";
279     private static final String COMMAND_CHECK_CAMERA_SERVICE_TYPE_ENABLED =
280             "check-camera-service-type-enabled";
281 
282     private static final String COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE =
283             "watchdog-control-package-killable-state";
284     private static final String COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES =
285             "watchdog-io-set-3p-foreground-bytes";
286     private static final String COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES =
287             "watchdog-io-get-3p-foreground-bytes";
288     private static final String COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK =
289             "watchdog-control-health-check";
290     private static final String COMMAND_WATCHDOG_RESOURCE_OVERUSE_KILL =
291             "watchdog-resource-overuse-kill";
292 
293     private static final String COMMAND_DRIVING_SAFETY_SET_REGION =
294             "set-drivingsafety-region";
295 
296     private static final String COMMAND_TELEMETRY = "telemetry";
297     private static final String COMMAND_CONTROL_COMPONENT_ENABLED_STATE =
298             "control-component-enabled-state";
299 
300     private static final String COMMAND_LIST_VHAL_PROPS = "list-vhal-props";
301     private static final String COMMAND_GET_VHAL_BACKEND = "get-vhal-backend";
302 
303     private static final String COMMAND_TEST_ECHO_REVERSE_BYTES = "test-echo-reverse-bytes";
304 
305     private static final String COMMAND_GET_TARGET_CAR_VERSION = "get-target-car-version";
306 
307     private static final String COMMAND_SET_PROCESS_GROUP = "set-process-group";
308     private static final String COMMAND_GET_PROCESS_GROUP = "get-process-group";
309     private static final String COMMAND_SET_PROCESS_PROFILE = "set-process-profile";
310 
311     private static final String COMMAND_GET_DISPLAY_BY_USER = "get-display-by-user";
312     private static final String COMMAND_GET_USER_BY_DISPLAY = "get-user-by-display";
313     private static final String COMMAND_GENERATE_TEST_VENDOR_CONFIGS = "gen-test-vendor-configs";
314     private static final String COMMAND_RESTORE_TEST_VENDOR_CONFIGS = "restore-vendor-configs";
315 
316 
317     private static final String COMMAND_GET_CURRENT_UX_RESTRICTIONS = "get-current-ux-restrictions";
318     private static final String COMMAND_SET_CURRENT_UXR_MODE = "set-current-uxr-mode";
319     private static final String COMMAND_GET_CURRENT_UXR_MODE = "get-current-uxr-mode";
320     private static final String COMMAND_GET_SUPPORTED_UXR_MODES = "get-supported-uxr-modes";
321     private static final String COMMAND_GET_UXR_CONFIG = "get-uxr-config";
322     private static final String COMMAND_GET_INPUT_AND_DISPLAY_INFO = "get-input-and-display-info";
323     private static final String COMMAND_ADD_INPUT_DESCRIPTOR_ASSOCIATION_TO_DISPLAY_UNIQUE_ID =
324             "add-input-descriptor-association-to-display-unique-id";
325     private static final String COMMAND_REMOVE_INPUT_DESCRIPTOR_ASSOCIATION =
326             "remove-input-descriptor-association";
327 
328     private static final String[] CREATE_OR_MANAGE_USERS_PERMISSIONS = new String[] {
329             android.Manifest.permission.CREATE_USERS,
330             android.Manifest.permission.MANAGE_USERS
331     };
332 
333     private static final String[] CREATE_OR_MANAGE_OR_QUERY_USERS_PERMISSIONS = new String[] {
334             android.Manifest.permission.CREATE_USERS,
335             android.Manifest.permission.MANAGE_USERS,
336             android.Manifest.permission.QUERY_USERS
337     };
338 
339     // List of commands allowed in user build. All these command should be protected with
340     // a permission. K: command, V: required permissions (must have at least 1).
341     // Only commands with permission already granted to shell user should be allowed.
342     // Commands that can affect safety should be never allowed in user build.
343     //
344     // This map is looked up first, then USER_BUILD_COMMAND_TO_PERMISSION_MAP
345     private static final ArrayMap<String, String[]> USER_BUILD_COMMAND_TO_PERMISSIONS_MAP;
346     static {
347         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP = new ArrayMap<>(8);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_INITIAL_USER_INFO, CREATE_OR_MANAGE_USERS_PERMISSIONS)348         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_INITIAL_USER_INFO,
349                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SWITCH_USER, CREATE_OR_MANAGE_USERS_PERMISSIONS)350         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SWITCH_USER,
351                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_LOGOUT_USER, CREATE_OR_MANAGE_USERS_PERMISSIONS)352         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_LOGOUT_USER,
353                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_REMOVE_USER, CREATE_OR_MANAGE_USERS_PERMISSIONS)354         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_REMOVE_USER,
355                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_CREATE_USER, CREATE_OR_MANAGE_USERS_PERMISSIONS)356         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_CREATE_USER,
357                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_USER_AUTH_ASSOCIATION, CREATE_OR_MANAGE_USERS_PERMISSIONS)358         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_USER_AUTH_ASSOCIATION,
359                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SET_USER_AUTH_ASSOCIATION, CREATE_OR_MANAGE_USERS_PERMISSIONS)360         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SET_USER_AUTH_ASSOCIATION,
361                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE, CREATE_OR_MANAGE_USERS_PERMISSIONS)362         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE,
363                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_DISPLAY_BY_USER, CREATE_OR_MANAGE_OR_QUERY_USERS_PERMISSIONS)364         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_DISPLAY_BY_USER,
365                 CREATE_OR_MANAGE_OR_QUERY_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_USER_BY_DISPLAY, CREATE_OR_MANAGE_OR_QUERY_USERS_PERMISSIONS)366         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_USER_BY_DISPLAY,
367                 CREATE_OR_MANAGE_OR_QUERY_USERS_PERMISSIONS);
368     }
369 
370     // List of commands allowed in user build. All these command should be protected with
371     // a permission. K: command, V: required permission.
372     // Only commands with permission already granted to shell user should be allowed.
373     // Commands that can affect safety should be never allowed in user build.
374     private static final ArrayMap<String, String> USER_BUILD_COMMAND_TO_PERMISSION_MAP;
375     static {
376         USER_BUILD_COMMAND_TO_PERMISSION_MAP = new ArrayMap<>(27);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GARAGE_MODE, PERMISSION_CAR_POWER)377         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GARAGE_MODE, PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_RESUME, PERMISSION_CAR_POWER)378         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_RESUME, PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SUSPEND, PERMISSION_CAR_POWER)379         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SUSPEND, PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_HIBERNATE, PERMISSION_CAR_POWER)380         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_HIBERNATE, PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_DISPLAY_STATE, PERMISSION_CAR_POWER)381         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_DISPLAY_STATE, PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_POWER_OFF, PERMISSION_CAR_POWER)382         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_POWER_OFF, PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DEFINE_POWER_POLICY, PERMISSION_CAR_POWER)383         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DEFINE_POWER_POLICY, PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_POWER_POLICY, PERMISSION_CONTROL_CAR_POWER_POLICY)384         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_POWER_POLICY,
385                 PERMISSION_CONTROL_CAR_POWER_POLICY);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DEFINE_POWER_POLICY_GROUP, PERMISSION_CAR_POWER)386         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DEFINE_POWER_POLICY_GROUP,
387                 PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_POWER_POLICY_GROUP, PERMISSION_CONTROL_CAR_POWER_POLICY)388         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_POWER_POLICY_GROUP,
389                 PERMISSION_CONTROL_CAR_POWER_POLICY);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY, PERMISSION_CONTROL_CAR_POWER_POLICY)390         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY,
391                 PERMISSION_CONTROL_CAR_POWER_POLICY);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY, PERMISSION_CONTROL_CAR_POWER_POLICY)392         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY,
393                 PERMISSION_CONTROL_CAR_POWER_POLICY);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SILENT_MODE, PERMISSION_CAR_POWER)394         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SILENT_MODE, PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_INITIAL_USER, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)395         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_INITIAL_USER,
396                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DAY_NIGHT_MODE, android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)397         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DAY_NIGHT_MODE,
398                 android.Manifest.permission.MODIFY_DAY_NIGHT_MODE);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_RESET_VOLUME_CONTEXT, PERMISSION_CAR_CONTROL_AUDIO_VOLUME)399         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_RESET_VOLUME_CONTEXT,
400                 PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_MUTE_CAR_VOLUME_GROUP, PERMISSION_CAR_CONTROL_AUDIO_VOLUME)401         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_MUTE_CAR_VOLUME_GROUP,
402                 PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_GROUP_VOLUME, PERMISSION_CAR_CONTROL_AUDIO_VOLUME)403         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_GROUP_VOLUME,
404                 PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_AUDIO_MIRROR, PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)405         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_AUDIO_MIRROR,
406                 PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_UNSET_AUDIO_MIRROR, PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)407         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_UNSET_AUDIO_MIRROR,
408                 PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_KEY, android.Manifest.permission.INJECT_EVENTS)409         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_KEY,
410                 android.Manifest.permission.INJECT_EVENTS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_MOTION, android.Manifest.permission.INJECT_EVENTS)411         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_MOTION,
412                 android.Manifest.permission.INJECT_EVENTS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_ROTARY, android.Manifest.permission.INJECT_EVENTS)413         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_ROTARY,
414                 android.Manifest.permission.INJECT_EVENTS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE, PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG)415         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE,
416                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES, PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG)417         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES,
418                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES, PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG)419         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES,
420                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK, PERMISSION_USE_CAR_WATCHDOG)421         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK,
422                 PERMISSION_USE_CAR_WATCHDOG);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_RESOURCE_OVERUSE_KILL, PERMISSION_USE_CAR_WATCHDOG)423         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_RESOURCE_OVERUSE_KILL,
424                 PERMISSION_USE_CAR_WATCHDOG);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_CONTROL_COMPONENT_ENABLED_STATE, android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE)425         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_CONTROL_COMPONENT_ENABLED_STATE,
426                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
427         // borrow the permission to pass assertHasAtLeastOnePermission() for a user build
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_CHECK_LOCK_IS_SECURE, android.Manifest.permission.INJECT_EVENTS)428         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_CHECK_LOCK_IS_SECURE,
429                 android.Manifest.permission.INJECT_EVENTS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_TEST_ECHO_REVERSE_BYTES, android.car.Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL)430         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_TEST_ECHO_REVERSE_BYTES,
431                 android.car.Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_TARGET_CAR_VERSION, android.Manifest.permission.QUERY_ALL_PACKAGES)432         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_TARGET_CAR_VERSION,
433                 android.Manifest.permission.QUERY_ALL_PACKAGES);
434     }
435 
436     private static final String PARAM_DAY_MODE = "day";
437     private static final String PARAM_NIGHT_MODE = "night";
438     private static final String PARAM_SENSOR_MODE = "sensor";
439     private static final String PARAM_VEHICLE_PROPERTY_GLOBAL_AREA_ID = "0";
440     private static final String PARAM_INJECT_EVENT_DEFAULT_RATE = "10";
441     private static final String PARAM_INJECT_EVENT_DEFAULT_DURATION = "60";
442     private static final String PARAM_ALL_PROPERTIES_OR_AREA_IDS = "-1";
443     private static final String PARAM_ON_MODE = "on";
444     private static final String PARAM_OFF_MODE = "off";
445     private static final String PARAM_QUERY_MODE = "query";
446     private static final String PARAM_REBOOT_AFTER_GARAGEMODE = "reboot";
447     private static final String PARAM_MUTE = "mute";
448     private static final String PARAM_UNMUTE = "unmute";
449 
450 
451     private static final int RESULT_OK = 0;
452     private static final int RESULT_ERROR = -1; // Arbitrary value, any non-0 is fine
453 
454     private static final int DEFAULT_HAL_TIMEOUT_MS = 1_000;
455 
456     private static final int DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS = 60_000;
457 
458     private static final int INVALID_USER_AUTH_TYPE_OR_VALUE = -1;
459 
460     private static final SparseArray<String> VALID_USER_AUTH_TYPES;
461     private static final String VALID_USER_AUTH_TYPES_HELP;
462 
463     private static final SparseArray<String> VALID_USER_AUTH_SET_VALUES;
464     private static final String VALID_USER_AUTH_SET_VALUES_HELP;
465 
466     private static final ArrayMap<String, Integer> CUSTOM_INPUT_FUNCTION_ARGS;
467 
468     private static final int DEFAULT_DEVICE_ID = 0;
469     private static final float DEFAULT_PRESSURE = 1.0f;
470     private static final float NO_PRESSURE = 0.0f;
471     private static final float DEFAULT_SIZE = 1.0f;
472     private static final int DEFAULT_META_STATE = 0;
473     private static final float DEFAULT_PRECISION_X = 1.0f;
474     private static final float DEFAULT_PRECISION_Y = 1.0f;
475     private static final int DEFAULT_EDGE_FLAGS = 0;
476     private static final int DEFAULT_BUTTON_STATE = 0;
477     private static final int DEFAULT_FLAGS = 0;
478 
479     private static final ArrayMap<String, Integer> MOTION_EVENT_SOURCES;
480 
481     static {
482         VALID_USER_AUTH_TYPES = new SparseArray<>(5);
VALID_USER_AUTH_TYPES.put(KEY_FOB, "KEY_FOB")483         VALID_USER_AUTH_TYPES.put(KEY_FOB, "KEY_FOB");
VALID_USER_AUTH_TYPES.put(CUSTOM_1, "CUSTOM_1")484         VALID_USER_AUTH_TYPES.put(CUSTOM_1, "CUSTOM_1");
VALID_USER_AUTH_TYPES.put(CUSTOM_2, "CUSTOM_2")485         VALID_USER_AUTH_TYPES.put(CUSTOM_2, "CUSTOM_2");
VALID_USER_AUTH_TYPES.put(CUSTOM_3, "CUSTOM_3")486         VALID_USER_AUTH_TYPES.put(CUSTOM_3, "CUSTOM_3");
VALID_USER_AUTH_TYPES.put(CUSTOM_4, "CUSTOM_4")487         VALID_USER_AUTH_TYPES.put(CUSTOM_4, "CUSTOM_4");
488         VALID_USER_AUTH_TYPES_HELP = getHelpString("types", VALID_USER_AUTH_TYPES);
489 
490         VALID_USER_AUTH_SET_VALUES = new SparseArray<>(3);
VALID_USER_AUTH_SET_VALUES.put(ASSOCIATE_CURRENT_USER, "ASSOCIATE_CURRENT_USER")491         VALID_USER_AUTH_SET_VALUES.put(ASSOCIATE_CURRENT_USER, "ASSOCIATE_CURRENT_USER");
VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_CURRENT_USER, "DISASSOCIATE_CURRENT_USER")492         VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_CURRENT_USER, "DISASSOCIATE_CURRENT_USER");
VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_ALL_USERS, "DISASSOCIATE_ALL_USERS")493         VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_ALL_USERS, "DISASSOCIATE_ALL_USERS");
494         VALID_USER_AUTH_SET_VALUES_HELP = getHelpString("values", VALID_USER_AUTH_SET_VALUES);
495 
496         CUSTOM_INPUT_FUNCTION_ARGS = new ArrayMap<>(10);
497         CUSTOM_INPUT_FUNCTION_ARGS.put("f1", CustomInputEvent.INPUT_CODE_F1);
498         CUSTOM_INPUT_FUNCTION_ARGS.put("f2", CustomInputEvent.INPUT_CODE_F2);
499         CUSTOM_INPUT_FUNCTION_ARGS.put("f3", CustomInputEvent.INPUT_CODE_F3);
500         CUSTOM_INPUT_FUNCTION_ARGS.put("f4", CustomInputEvent.INPUT_CODE_F4);
501         CUSTOM_INPUT_FUNCTION_ARGS.put("f5", CustomInputEvent.INPUT_CODE_F5);
502         CUSTOM_INPUT_FUNCTION_ARGS.put("f6", CustomInputEvent.INPUT_CODE_F6);
503         CUSTOM_INPUT_FUNCTION_ARGS.put("f7", CustomInputEvent.INPUT_CODE_F7);
504         CUSTOM_INPUT_FUNCTION_ARGS.put("f8", CustomInputEvent.INPUT_CODE_F8);
505         CUSTOM_INPUT_FUNCTION_ARGS.put("f9", CustomInputEvent.INPUT_CODE_F9);
506         CUSTOM_INPUT_FUNCTION_ARGS.put("f10", CustomInputEvent.INPUT_CODE_F10);
507 
508         MOTION_EVENT_SOURCES = new ArrayMap<>(10);
509         MOTION_EVENT_SOURCES.put("keyboard", InputDevice.SOURCE_KEYBOARD);
510         MOTION_EVENT_SOURCES.put("dpad", InputDevice.SOURCE_DPAD);
511         MOTION_EVENT_SOURCES.put("gamepad", InputDevice.SOURCE_GAMEPAD);
512         MOTION_EVENT_SOURCES.put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN);
513         MOTION_EVENT_SOURCES.put("mouse", InputDevice.SOURCE_MOUSE);
514         MOTION_EVENT_SOURCES.put("stylus", InputDevice.SOURCE_STYLUS);
515         MOTION_EVENT_SOURCES.put("trackball", InputDevice.SOURCE_TRACKBALL);
516         MOTION_EVENT_SOURCES.put("touchpad", InputDevice.SOURCE_TOUCHPAD);
517         MOTION_EVENT_SOURCES.put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION);
518         MOTION_EVENT_SOURCES.put("joystick", InputDevice.SOURCE_JOYSTICK);
519     }
520 
521     // CarTelemetryManager may not send result back if there are not results for the given
522     // metrics config.
523     private static final Duration TELEMETRY_RESULT_WAIT_TIMEOUT = Duration.ofSeconds(5);
524 
getHelpString(String name, SparseArray<String> values)525     private static String getHelpString(String name, SparseArray<String> values) {
526         StringBuilder help = new StringBuilder("Valid ").append(name).append(" are: ");
527         int size = values.size();
528         for (int i = 0; i < size; i++) {
529             help.append(values.valueAt(i));
530             if (i != size - 1) {
531                 help.append(", ");
532             }
533         }
534         return help.append('.').toString();
535     }
536 
537     private final Context mContext;
538     private final VehicleHal mHal;
539     private final CarAudioService mCarAudioService;
540     private final CarPackageManagerService mCarPackageManagerService;
541     private final CarProjectionService mCarProjectionService;
542     private final CarPowerManagementService mCarPowerManagementService;
543     private final FixedActivityService mFixedActivityService;
544     private final CarFeatureController mFeatureController;
545     private final CarInputService mCarInputService;
546     private final CarNightService mCarNightService;
547     private final SystemInterface mSystemInterface;
548     private final GarageModeService mGarageModeService;
549     private final CarUserService mCarUserService;
550     private final CarOccupantZoneService mCarOccupantZoneService;
551     private final CarEvsService mCarEvsService;
552     private final CarWatchdogService mCarWatchdogService;
553     private final CarTelemetryService mCarTelemetryService;
554     private final CarUxRestrictionsManagerService mCarUxRestrictionsManagerService;
555     private final Map<Class, CarSystemService> mAllServicesByClazz;
556     private long mKeyDownTime;
557     private long mMotionDownTime;
558     private ServiceConnection mScriptExecutorConn;
559     private IScriptExecutor mScriptExecutor;
560     private AudioZoneMirrorStatusCallbackImpl mMirrorStatusCallback;
561 
CarShellCommand(Context context, VehicleHal hal, CarFeatureController featureController, SystemInterface systemInterface, Map<Class, CarSystemService> allServicesByClazz)562     CarShellCommand(Context context, VehicleHal hal, CarFeatureController featureController,
563             SystemInterface systemInterface, Map<Class, CarSystemService> allServicesByClazz) {
564         mContext = context;
565         mHal = hal;
566         mFeatureController = featureController;
567         mSystemInterface = systemInterface;
568         mCarAudioService = (CarAudioService) allServicesByClazz.get(CarAudioService.class);
569         mCarPackageManagerService = (CarPackageManagerService) allServicesByClazz.get(
570                 CarPackageManagerService.class);
571         mCarProjectionService = (CarProjectionService) allServicesByClazz.get(
572                 CarProjectionService.class);
573         mCarPowerManagementService = (CarPowerManagementService) allServicesByClazz.get(
574                 CarPowerManagementService.class);
575         mFixedActivityService = (FixedActivityService) allServicesByClazz.get(
576                 FixedActivityService.class);
577         mCarInputService = (CarInputService) allServicesByClazz.get(CarInputService.class);
578         mCarNightService = (CarNightService) allServicesByClazz.get(CarNightService.class);
579         mGarageModeService = (GarageModeService) allServicesByClazz.get(GarageModeService.class);
580         mCarUserService = (CarUserService) allServicesByClazz.get(CarUserService.class);
581         mCarOccupantZoneService = (CarOccupantZoneService)
582                 allServicesByClazz.get(CarOccupantZoneService.class);
583         mCarEvsService = (CarEvsService) allServicesByClazz.get(CarEvsService.class);
584         mCarWatchdogService = (CarWatchdogService) allServicesByClazz.get(CarWatchdogService.class);
585         mCarTelemetryService = (CarTelemetryService)
586                 allServicesByClazz.get(CarTelemetryService.class);
587         mCarUxRestrictionsManagerService = (CarUxRestrictionsManagerService)
588                 allServicesByClazz.get(CarUxRestrictionsManagerService.class);
589         mAllServicesByClazz = allServicesByClazz;
590     }
591 
592     @Override
onCommand(String cmd)593     public int onCommand(String cmd) {
594         if (cmd == null) {
595             onHelp();
596             return RESULT_ERROR;
597         }
598         ArrayList<String> argsList = new ArrayList<>();
599         argsList.add(cmd);
600         String arg = null;
601         do {
602             arg = getNextArg();
603             if (arg != null) {
604                 argsList.add(arg);
605             }
606         } while (arg != null);
607         String[] args = new String[argsList.size()];
608         argsList.toArray(args);
609         try (IndentingPrintWriter pw = new IndentingPrintWriter(getOutPrintWriter())) {
610             return exec(args, pw);
611         }
612     }
613 
614     @Override
onHelp()615     public void onHelp() {
616         try (IndentingPrintWriter pw = new IndentingPrintWriter(getOutPrintWriter())) {
617             showHelp(pw);
618         }
619     }
620 
showHelp(IndentingPrintWriter pw)621     private static void showHelp(IndentingPrintWriter pw) {
622         pw.println("Car service commands:");
623         pw.println("\t-h");
624         pw.println("\t  Print this help text.");
625         pw.println("\tday-night-mode [day|night|sensor]");
626         pw.println("\t  Force into day/night mode or restore to auto.");
627         pw.println("\tinject-vhal-event <property name in SCREAMING_SNAKE_CASE or ID in Hex or "
628                 + "Decimal> [area ID] data(can be comma separated list) [-t delay_time_seconds]");
629         pw.println("\t  Inject a vehicle property for testing.");
630         pw.println("\t  delay_time_seconds: the event timestamp is increased by certain second.");
631         pw.println("\t  If not specified, it will be 0.");
632         pw.println("\tinject-error-event <PROPERTY_ID in Hex or Decimal> zone <errorCode>");
633         pw.println("\t  Inject an error event from VHAL for testing.");
634         pw.println("\tinject-continuous-events <PROPERTY_ID in Hex or Decimal> "
635                 + "data(can be comma separated list) "
636                 + "[-z zone]  [-s SampleRate in Hz] [-d time duration in seconds]");
637         pw.println("\t  Inject continuous vehicle events for testing.");
638         pw.printf("\t  If not specified, CarService will inject fake events with areaId:%s "
639                         + "at sample rate %s for %s seconds.",
640                 PARAM_VEHICLE_PROPERTY_GLOBAL_AREA_ID,
641                 PARAM_INJECT_EVENT_DEFAULT_RATE, PARAM_INJECT_EVENT_DEFAULT_DURATION);
642         pw.println("\tenable-uxr true|false");
643         pw.println("\t  Enable/Disable UX restrictions and App blocking.");
644         pw.println("\tgarage-mode [on|off|query|reboot]");
645         pw.println("\t  Force into or out of garage mode, or check status.");
646         pw.println("\t  With 'reboot', enter garage mode, then reboot when it completes.");
647         pw.println("\tget-do-activities pkgname");
648         pw.println("\t  Get Distraction Optimized activities in given package.");
649         pw.println("\tget-carpropertyconfig [property name in SCREAMING_SNAKE_CASE or ID in Hex or"
650                 + " Decimal]");
651         pw.println("\t  Get a specific CarPropertyConfig or list all CarPropertyConfigs");
652         pw.println("\tget-property-value [property name in SCREAMING_SNAKE_CASE or ID in Hex or "
653                 + "Decimal] [areaId]");
654         pw.println("\t  Get a vehicle property value by property id and areaId");
655         pw.println("\t  or list all property values for all areaId");
656         pw.printf("\t%s\n", getSetPropertyValueUsage());
657         pw.printf("\t%s\n", getSuspendCommandUsage(COMMAND_SUSPEND));
658         pw.println("\t  Suspend the system to RAM.");
659         pw.printf("\t  %s forces the device to perform suspend-to-RAM.\n", PARAM_REAL);
660         pw.printf("\t  %s simulates suspend-to-RAM instead of putting the device into deep sleep."
661                 + "\n", PARAM_SIMULATE);
662         pw.printf("\t  %s depending on the device capability, real or simulated suspend-to-RAM is "
663                 + "performed.\n", PARAM_AUTO);
664         pw.printf("\t  %s skips Garage Mode before going into sleep.\n", PARAM_SKIP_GARAGEMODE);
665         pw.printf("\t  %s [RESUME_DELAY] wakes up the device RESUME_DELAY seconds after suspend.\n",
666                 PARAM_WAKEUP_AFTER);
667         pw.printf("\t  %s [RESUME_DELAY] cancels the wake up after RESUME_DELAY seconds, if this"
668                         + " flag is set, device will not go into suspend mode and wait in shutdown"
669                         + " prepare for RESUME_DELAY seconds.\n",
670                 PARAM_CANCEL_AFTER);
671         pw.printf("\t%s\n", getSuspendCommandUsage(COMMAND_HIBERNATE));
672         pw.println("\t  Suspend the system to disk.");
673         pw.printf("\t  %s forces the device to perform suspend-to-disk.\n", PARAM_REAL);
674         pw.printf("\t  %s simulates suspend-to-disk instead of putting the device into "
675                 + "hibernation.\n", PARAM_SIMULATE);
676         pw.printf("\t  %s depending on the device capability, real or simulated suspend-to-disk is "
677                 + "performed.\n", PARAM_AUTO);
678         pw.printf("\t  %s skips Garage Mode before going into hibernation.\n",
679                 PARAM_SKIP_GARAGEMODE);
680         pw.printf("\t  %s frees cached apps memory before simulating hibernation.\n",
681                 PARAM_FREE_MEMORY);
682         pw.println("\tresume");
683         pw.println("\t  Wake the system up after a simulated suspension/hibernation.");
684         pw.println("\tset-display-state [displayId] [true|false]");
685         pw.println("\t  Turn on or off the individual display.");
686         pw.println("\tprojection-tethering [true|false]");
687         pw.println("\t  Whether tethering should be used when creating access point for"
688                 + " wireless projection");
689         pw.println("\t--metrics");
690         pw.println("\t  When used with dumpsys, only metrics will be in the dumpsys output.");
691         pw.printf("\t%s [zoneid] [uid]\n", COMMAND_SET_UID_TO_ZONE);
692         pw.println("\t  Maps the audio zoneid to uid.");
693         pw.printf("\t%s\n", COMMAND_RESET_VOLUME_CONTEXT);
694         pw.println("\t  Resets the last selected volume context for volume changes.");
695         pw.printf("\t%s [zoneId] [groupId] [%s\\%s]\n", COMMAND_SET_MUTE_CAR_VOLUME_GROUP,
696                 PARAM_MUTE, PARAM_UNMUTE);
697         pw.printf("\t  %s\\%s groupId in zoneId\n", PARAM_MUTE, PARAM_UNMUTE);
698         pw.printf("\t%s [zoneId] [groupId] [volume]\n", COMMAND_SET_GROUP_VOLUME);
699         pw.println("\t  sets the group volume for [groupId] in [zoneId] to %volume,");
700         pw.println("\t  [volume] must be an integer between 0 to 100");
701         pw.printf("\t%s [zoneId1] [zoneId2]\n", COMMAND_SET_AUDIO_MIRROR);
702         pw.println("\t  sets audio mirror for zones [zoneId1] and [zoneId2],");
703         pw.println("\t  [zoneId#] must be a valid zone id ");
704         pw.printf("\t%s [value] [--requestId]\n", COMMAND_UNSET_AUDIO_MIRROR);
705         pw.println("\t  unsets audio mirror for zone [value],");
706         pw.println("\t  [value] must be a valid zone id");
707         pw.println("\t  use --requestId to disable a request id instead");
708         pw.println("\tstart-fixed-activity displayId packageName activityName");
709         pw.println("\t  Start an Activity the specified display as fixed mode");
710         pw.println("\tstop-fixed-mode displayId");
711         pw.println("\t  Stop fixed Activity mode for the given display. "
712                 + "The Activity will not be restarted upon crash.");
713         pw.println("\tenable-feature featureName");
714         pw.println("\t  Enable the requested feature. Change will happen after reboot.");
715         pw.println("\t  This requires root/su.");
716         pw.println("\tdisable-feature featureName");
717         pw.println("\t  Disable the requested feature. Change will happen after reboot");
718         pw.println("\t  This requires root/su.");
719         pw.println("\tinject-key [-d display] [-s seat] [-t down_delay_ms | -a down|up] key_code");
720         pw.println("\t  inject key down and/or up event to car service");
721         pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
722         pw.println("\t  seat: int seat value defined in VeihicleAreaSeat. 0 for unknown,");
723         pw.println("\t      0x0001 for row1 left, 0x0002 for row1 center, 0x0004 for row1 right,");
724         pw.println("\t      0x0010 for row2 left, 0x0020 for row2 center, 0x0040 for row2 right,");
725         pw.println("\t      0x0100 for row3 left, 0x0200 for row3 center, 0x0400 for row3 right.");
726         pw.println("\t      If not specified, it will be driver seat.");
727         pw.println("\t  down_delay_ms: delay from down to up key event. If not specified,");
728         pw.println("\t                 it will be 0");
729         pw.println("\t  key_code: int key code defined in android KeyEvent");
730         pw.println("\t  If -a isn't specified, both down and up will be injected.");
731         pw.println("\tinject-motion [-d display] [-s seat] [--source source] [-t down_delay_ms] "
732                 + "[-a action] [-c count] [-p pointer_id0 pointer_id1...] x0 y0 x1 y1 ...");
733         pw.println("\t  inject motion down or up or move or cancel event to car service");
734         pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
735         pw.println("\t  seat: int seat value defined in VeihicleAreaSeat. 0 for unknown,");
736         pw.println("\t      0x0001 for row1 left, 0x0002 for row1 center, 0x0004 for row1 right,");
737         pw.println("\t      0x0010 for row2 left, 0x0020 for row2 center, 0x0040 for row2 right,");
738         pw.println("\t      0x0100 for row3 left, 0x0200 for row3 center, 0x0400 for row3 right.");
739         pw.println("\t      If not specified, it will be driver seat.");
740         pw.println("\t  source: string source value for motion event.");
741         pw.println("\t          If not specified, it will be touchscreen");
742         pw.println("\t          The sources are:");
743         pw.println("\t              touchnavigation");
744         pw.println("\t              touchscreen");
745         pw.println("\t              joystick");
746         pw.println("\t              stylus");
747         pw.println("\t              touchpad");
748         pw.println("\t              gamepad");
749         pw.println("\t              dpad");
750         pw.println("\t              mouse");
751         pw.println("\t              keyboard");
752         pw.println("\t              trackball");
753         pw.println("\t  down_delay_ms: delay from down to up motion event. If not specified,");
754         pw.println("\t      it will be 0");
755         pw.println("\t  action: the MotionEvent.ACTION_* for the event. If not specified,");
756         pw.println("\t      both down and up will be injected.");
757         pw.println("\t      This can be a string value that is down|up|move|cancel");
758         pw.println("\t      or an integer value that must equal to MotionEvent.ACTION_*.");
759         pw.println("\t  count: the count of pointers. If not specified, it will be 1.");
760         pw.println("\t      If this value is greater than 1, there must be as many pointer_id,");
761         pw.println("\t      x, y as this value.");
762         pw.println("\t  pointer_id: pointer ids of following coordinates, If not specified,");
763         pw.println("\t      they are automatically set in order from 0.");
764         pw.println("\t  x: int x coordinate in android MotionEvent");
765         pw.println("\t  y: int y coordinate in android MotionEvent");
766         pw.println("\t  Must provide the 'count' number of x, y pairs.");
767         pw.println("\tinject-rotary [-d display] [-i input_type] [-c clockwise]");
768         pw.println("\t              [-dt delta_times_ms]");
769         pw.println("\t  inject rotary input event to car service.");
770         pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
771         pw.println("\t  input_type: 10 for navigation controller input, 11 for volume");
772         pw.println("\t              controller input. If not specified, it will be 10.");
773         pw.println("\t  clockwise: true if the event is clockwise, false if the event is");
774         pw.println("\t             counter-clockwise. If not specified, it will be false.");
775         pw.println("\t  delta_times_ms: a list of delta time (current time minus event time)");
776         pw.println("\t                  in descending order. If not specified, it will be 0.");
777         pw.println("\tinject-custom-input [-d display] [-r repeatCounter] EVENT");
778         pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
779         pw.println("\t  repeatCounter: number of times the button was hit (default value is 1)");
780         pw.println("\t  EVENT: mandatory last argument. Possible values for for this flag are ");
781         pw.println("\t         F1, F2, up to F10 (functions to defined by OEM partners)");
782         pw.printf("\t%s <REQ_TYPE> [--timeout TIMEOUT_MS]\n", COMMAND_GET_INITIAL_USER_INFO);
783         pw.println("\t  Calls the Vehicle HAL to get the initial boot info, passing the given");
784         pw.println("\t  REQ_TYPE (which could be either FIRST_BOOT, FIRST_BOOT_AFTER_OTA, ");
785         pw.println("\t  COLD_BOOT, RESUME, or any numeric value that would be passed 'as-is')");
786         pw.println("\t  and an optional TIMEOUT_MS to wait for the HAL response (if not set,");
787         pw.println("\t  it will use a  default value).");
788         pw.println("\t  The --hal-only option only calls HAL, without using CarUserService.");
789 
790         pw.printf("\t%s <USER_ID> [--hal-only] [--ignore-uxr] [--timeout TIMEOUT_MS]\n",
791                 COMMAND_SWITCH_USER);
792         pw.println("\t  Switches to user USER_ID using the HAL integration.");
793         pw.println("\t  The --hal-only option only calls HAL, without switching the user,");
794         pw.println("\t  The --ignore-uxr option ignores any Ux restriction regarding user switch,");
795         pw.println("\t  while the --timeout defines how long to wait for the response.");
796 
797         pw.printf("\t%s [--timeout TIMEOUT_MS]\n", COMMAND_LOGOUT_USER);
798         pw.println("\t  Logout the current user (if the user was switched toby a device admin).");
799         pw.println("\t  The --timeout option defines how long to wait for the UserHal response.");
800 
801         pw.printf("\t%s <USER_ID> [--hal-only]\n", COMMAND_REMOVE_USER);
802         pw.println("\t  Removes user with USER_ID using the HAL integration.");
803         pw.println("\t  The --hal-only option only calls HAL, without removing the user,");
804 
805         pw.printf("\t%s [--hal-only] [--timeout TIMEOUT_MS] [--guest] [--flags FLAGS] [NAME]\n",
806                 COMMAND_CREATE_USER);
807         pw.println("\t  Creates a new user using the HAL integration.");
808         pw.println("\t  The --hal-only uses UserManager to create the user,");
809         pw.println("\t  while the --timeout defines how long to wait for the response.");
810 
811         pw.printf("\t%s\n", COMMAND_GET_INITIAL_USER);
812         pw.printf("\t  Gets the id of the initial user (or %s when it's not available)\n",
813                 NO_INITIAL_USER);
814 
815         pw.printf("\t%s [occupantZoneId] [userId]\n", COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE);
816         pw.println("\t  Maps the occupant zone id to user id.");
817         pw.printf("\t%s [occupantZoneId]\n", COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE);
818         pw.println("\t  Unmaps the user assigned to occupant zone id.");
819 
820         pw.printf("\t%s [--hal-only] [--user USER_ID] TYPE1 [..TYPE_N]\n",
821                 COMMAND_GET_USER_AUTH_ASSOCIATION);
822         pw.println("\t  Gets the N user authentication values for the N types for the given user");
823         pw.println("\t  (or current user when not specified).");
824         pw.println("\t  By defautt it calls CarUserManager, but using --hal-only will call just "
825                 + "UserHalService.");
826 
827         pw.printf("\t%s [--hal-only] [--user USER_ID] TYPE1 VALUE1 [..TYPE_N VALUE_N]\n",
828                 COMMAND_SET_USER_AUTH_ASSOCIATION);
829         pw.println("\t  Sets the N user authentication types with the N values for the given user");
830         pw.println("\t  (or current user when not specified).");
831         pw.println("\t  By default it calls CarUserManager, but using --hal-only will call just "
832                 + "UserHalService.");
833         pw.printf("\t  %s\n", VALID_USER_AUTH_TYPES_HELP);
834         pw.printf("\t  %s\n", VALID_USER_AUTH_SET_VALUES_HELP);
835 
836         pw.printf("\t%s [true|false]\n", COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE);
837         pw.println("\t  Controls backgroud user start and stop during garage mode.");
838         pw.println("\t  If false, garage mode operations (background users start at garage mode"
839                 + " entry and background users stop at garage mode exit) will be skipped.");
840 
841         pw.printf("\t  %s [%s|%s|%s|%s]\n", COMMAND_SILENT_MODE, SILENT_MODE_FORCED_SILENT,
842                 SILENT_MODE_FORCED_NON_SILENT, SILENT_MODE_NON_FORCED, PARAM_QUERY_MODE);
843         pw.println("\t  Forces silent mode silent or non-silent. With query (or no command) "
844                 + "displays the silent state");
845         pw.println("\t  and shows how many listeners are monitoring the state.");
846 
847         pw.printf("\t%s [%s|%s|%s|%s]\n", COMMAND_EMULATE_DRIVING_STATE, DRIVING_STATE_DRIVE,
848                 DRIVING_STATE_PARK, DRIVING_STATE_REVERSE, DRIVING_STATE_NEUTRAL);
849         pw.println("\t  Emulates the giving driving state.");
850 
851         pw.printf("\t%s <POLICY_ID> [--enable COMP1,COMP2,...] [--disable COMP1,COMP2,...]\n",
852                 COMMAND_DEFINE_POWER_POLICY);
853         pw.println("\t  Defines a power policy. Components not specified in --enable or --disable");
854         pw.println("\t  are unchanged when the policy is applied.");
855         pw.println("\t  Components should be comma-separated without space.");
856 
857         pw.printf("\t%s <POLICY_ID>\n", COMMAND_APPLY_POWER_POLICY);
858         pw.println("\t  Applies power policy which is defined in "
859                 + "/vendor/etc/automotive/power_policy.xml or");
860         pw.printf("\t  by %s command\n", COMMAND_DEFINE_POWER_POLICY);
861 
862         pw.printf("\t%s <POLICY_GROUP_ID> [%s:<POLICY_ID>] [%s:<POLICY_ID>]\n",
863                 COMMAND_DEFINE_POWER_POLICY_GROUP, POWER_STATE_WAIT_FOR_VHAL, POWER_STATE_ON);
864         pw.println("\t  Defines a power policy group. The policy ID must be defined in advance.");
865 
866         pw.printf("\t%s <POLICY_GROUP_ID>\n", COMMAND_SET_POWER_POLICY_GROUP);
867         pw.println("\t  Sets power policy group which is defined in "
868                 + "/vendor/etc/automotive/power_policy.xml ");
869         pw.printf("\t  or by %s command\n", COMMAND_DEFINE_POWER_POLICY_GROUP);
870 
871         pw.printf("\t%s\n", COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY);
872         pw.println("\t  Define and apply the cts_verifier_off power policy with "
873                 + "--disable WIFI,LOCATION,BLUETOOTH");
874 
875         pw.printf("\t%s\n", COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY);
876         pw.println("\t  Define and apply the cts_verifier_on power policy with "
877                 + "--enable WIFI,LOCATION,BLUETOOTH");
878 
879         pw.printf("\t%s [%s] [%s]\n", COMMAND_POWER_OFF, PARAM_SKIP_GARAGEMODE, PARAM_REBOOT);
880         pw.println("\t  Powers off the car.");
881 
882         pw.printf("\t%s <REARVIEW_CAMERA_ID>\n", COMMAND_SET_REARVIEW_CAMERA_ID);
883         pw.println("\t  Configures a target camera device CarEvsService to use.");
884         pw.println("\t  If CAMEAR_ID is \"default\", this command will configure CarEvsService ");
885         pw.println("\t  to use its default camera device.");
886 
887         pw.printf("\t%s\n", COMMAND_GET_REARVIEW_CAMERA_ID);
888         pw.println("\t  Gets the name of the camera device CarEvsService is using for " +
889                 "the rearview.");
890 
891         pw.printf("\t%s <SERVICE_TYPE> <CAMERA_ID>\n", COMMAND_SET_CAMERA_ID);
892         pw.println("\t Configures a target camera device CarEvsService will use for a specified ");
893         pw.println("\t service type.");
894         pw.println("\t Possible SERVICE_TYPEs are REARVIEW, FRONTVIEW, LEFTVIEW, RIGHTVIEW, ");
895         pw.println("\t DRIVERVIEW, FRONT_PASSENGERSVIEW, REAR_PASSENGERSVIEW, or USER_DEFINED");
896         pw.println("\t (* of CarEvsManager.SERVICE_TYPE_* to specify a service type).");
897 
898         pw.printf("\t%s <SERVICE_TYPE>\n", COMMAND_GET_CAMERA_ID);
899         pw.println("\t Gets the name of the camera device that is assigned to a specified ");
900         pw.println("\t service type.");
901         pw.println("\t Possible SERVICE_TYPEs are REARVIEW, FRONTVIEW, LEFTVIEW, RIGHTVIEW, ");
902         pw.println("\t DRIVERVIEW, FRONT_PASSENGERSVIEW, REAR_PASSENGERSVIEW, or USER_DEFINED");
903         pw.println("\t (* of CarEvsManager.SERVICE_TYPE_* to specify a service type).");
904 
905         pw.printf("\t%s <SERVICE_TYPE> <CAMERA_ID>\n", COMMAND_ENABLE_CAMERA_SERVICE_TYPE);
906         pw.println("\t Enables a specified service type with a camera associated with a given ");
907         pw.println("\t camera id.");
908         pw.println("\t Use * of CarEvsManager.SERVICE_TYPE_* to specify a service type.");
909 
910         pw.printf("\t%s <SERVICE_TYPE>\n", COMMAND_CHECK_CAMERA_SERVICE_TYPE_ENABLED);
911         pw.println("\t Checks whether or not a given service type is enabled.");
912         pw.println("\t Use * of CarEvsManager.SERVICE_TYPE_* to specify a service type.");
913 
914         pw.printf("\t%s true|false <PACKAGE_NAME>\n",
915                 COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE);
916         pw.println("\t  Marks PACKAGE_NAME as killable or not killable on resource overuse ");
917 
918         pw.printf("\t%s <FOREGROUND_MODE_BYTES>\n", COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES);
919         pw.println("\t  Sets third-party apps foreground I/O overuse threshold");
920 
921         pw.printf("\t%s\n", COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES);
922         pw.println("\t  Gets third-party apps foreground I/O overuse threshold");
923 
924         pw.printf("\t%s enable|disable\n", COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK);
925         pw.println("\t  Enables/disables car watchdog process health check.");
926 
927         pw.printf("\t%s <PACKAGE_NAME> [--user USER_ID]\n", COMMAND_WATCHDOG_RESOURCE_OVERUSE_KILL);
928         pw.println("\t  Kills PACKAGE_NAME due to resource overuse.");
929 
930         pw.printf("\t%s [REGION_STRING]", COMMAND_DRIVING_SAFETY_SET_REGION);
931         pw.println("\t  Set driving safety region.");
932         pw.println("\t  Skipping REGION_STRING leads into resetting to all regions");
933 
934         pw.printf("\t%s <subcommand>", COMMAND_TELEMETRY);
935         pw.println("\t  Telemetry commands.");
936         pw.println("\t  Provide -h to see the list of sub-commands.");
937 
938         pw.printf("\t%s get|default|enable|disable_until_used <PACKAGE_NAME>\n",
939                 COMMAND_CONTROL_COMPONENT_ENABLED_STATE);
940         pw.println("\t  Gets the current EnabledState, or changes the Application EnabledState"
941                 + " to DEFAULT, ENABLED or DISABLED_UNTIL_USED.");
942         pw.printf("\t%s [user]\n", COMMAND_CHECK_LOCK_IS_SECURE);
943         pw.println("\t  check if the current or given user has a lock to secure");
944         pw.printf("\t%s", COMMAND_LIST_VHAL_PROPS);
945         pw.println("\t  list all supported property IDS by vehicle HAL");
946         pw.printf("\t%s", COMMAND_GET_VHAL_BACKEND);
947         pw.println("\t  list whether we are connected to AIDL or HIDL vehicle HAL backend");
948         pw.printf("\t%s <PROP_ID> <REQUEST_SIZE>", COMMAND_TEST_ECHO_REVERSE_BYTES);
949         pw.println("\t  test the ECHO_REVERSE_BYTES property. PROP_ID is the ID (int) for "
950                 + "ECHO_REVERSE_BYTES, REQUEST_SIZE is how many byteValues in the request. "
951                 + "This command can be used for testing LargeParcelable by passing large request.");
952 
953         pw.printf("\t%s [--user USER] <APP1> [APPN]", COMMAND_GET_TARGET_CAR_VERSION);
954         pw.println("\t  Gets the target API version (major and minor) defined by the given apps "
955                 + "for the given user (or current user when --user is not set).");
956 
957         pw.printf("\t%s <PID> <CPU_GROUP_ID>", COMMAND_SET_PROCESS_GROUP);
958         pw.println("\t Change CPU group of a process. Check android.os.Process.setProcessGroup "
959                 + "for details on the parameters.");
960         pw.printf("\t%s <PID>", COMMAND_GET_PROCESS_GROUP);
961         pw.println("\t Get the CPU group of a process. Check android.os.Process.getProcessGroup "
962                 + "for details on the parameters.");
963         pw.printf("\t%s <PID> <UID> <CPU_PROFILE>", COMMAND_SET_PROCESS_PROFILE);
964         pw.println("\t Change CPU profile (=CPUSet) of a process. Check "
965                 + "android.os.Process.setProcessProfile for details on the parameters.");
966 
967         pw.printf("\t%s <USER>", COMMAND_GET_DISPLAY_BY_USER);
968         pw.println("\t Gets the display associated to the given user");
969         pw.printf("\t%s <DISPLAY>", COMMAND_GET_USER_BY_DISPLAY);
970         pw.println("\t Gets the user associated with the given display");
971 
972         pw.printf("\t%s <DISPLAY>", COMMAND_GET_CURRENT_UX_RESTRICTIONS);
973         pw.println("\t Gets the current UX restriction on given display. If no display is "
974                 + "provided, return current UX restrictions on default display.");
975         pw.printf("\t%s <mode>", COMMAND_SET_CURRENT_UXR_MODE);
976         pw.println("\t Sets current mode for UX restrictions.");
977         pw.printf("\t%s", COMMAND_GET_CURRENT_UXR_MODE);
978         pw.println("\t Gets current mode for UX restrictions.");
979         pw.printf("\t%s", COMMAND_GET_SUPPORTED_UXR_MODES);
980         pw.println("\t Gets all supported UX restrictions modes.");
981         pw.printf("\t%s", COMMAND_GET_UXR_CONFIG);
982         pw.println("\t Gets UX restrictions configuration.");
983         pw.printf("\t%s", COMMAND_GET_INPUT_AND_DISPLAY_INFO);
984         pw.println("\t Gets input devices & their descriptor; and gets display devices & their "
985                 + "uniqueId");
986         pw.printf("\t%s <input descriptor> <display unique id>",
987                 COMMAND_ADD_INPUT_DESCRIPTOR_ASSOCIATION_TO_DISPLAY_UNIQUE_ID);
988         pw.println("\t Add association of the input device to the particular display by using "
989                 + "input descriptor.");
990         pw.printf("\t%s <input descriptor>", COMMAND_REMOVE_INPUT_DESCRIPTOR_ASSOCIATION);
991         pw.println("\t Remove association of the input device descriptor to any display.");
992     }
993 
showInvalidArguments(IndentingPrintWriter pw)994     private static int showInvalidArguments(IndentingPrintWriter pw) {
995         pw.println("Incorrect number of arguments.");
996         showHelp(pw);
997         return RESULT_ERROR;
998     }
999 
runSetZoneIdForUid(String zoneString, String uidString)1000     private void runSetZoneIdForUid(String zoneString, String uidString) {
1001         int uid = Integer.parseInt(uidString);
1002         int zoneId = Integer.parseInt(zoneString);
1003         mCarAudioService.setZoneIdForUid(zoneId, uid);
1004     }
1005 
runSetMuteCarVolumeGroup(String zoneString, String groupIdString, String muteString)1006     private void runSetMuteCarVolumeGroup(String zoneString, String groupIdString,
1007             String muteString) {
1008         int groupId = Integer.parseInt(groupIdString);
1009         int zoneId = Integer.parseInt(zoneString);
1010         if (!PARAM_MUTE.equalsIgnoreCase(muteString)
1011                 && !PARAM_UNMUTE.equalsIgnoreCase(muteString)) {
1012             throw new IllegalArgumentException("Failed to set volume group mute for "
1013                     + groupIdString + " in zone " + zoneString
1014                     + ", bad mute argument: " + muteString);
1015         }
1016         boolean muteState = PARAM_MUTE.equalsIgnoreCase(muteString);
1017         mCarAudioService.setVolumeGroupMute(zoneId, groupId, muteState, FLAG_SHOW_UI);
1018     }
1019 
1020 
runSetGroupVolume(String zoneIdString, String groupIdString, String volumeString)1021     private void runSetGroupVolume(String zoneIdString, String groupIdString, String volumeString) {
1022         int groupId = Integer.parseInt(groupIdString);
1023         int zoneId = Integer.parseInt(zoneIdString);
1024         int percentVolume = Integer.parseInt(volumeString);
1025         Preconditions.checkArgumentInRange(percentVolume, 0, 100,
1026                 "%volume for group " + groupIdString + " in zone " + zoneIdString);
1027         int minIndex = mCarAudioService.getGroupMinVolume(zoneId, groupId);
1028         int maxIndex = mCarAudioService.getGroupMaxVolume(zoneId, groupId);
1029         int index = minIndex
1030                 + (int) ((float) (maxIndex - minIndex) * ((float) percentVolume / 100.0f));
1031         mCarAudioService.setGroupVolume(zoneId, groupId, index, FLAG_SHOW_UI);
1032     }
1033 
runSetAudioMirror(String zoneId1String, String zoneId2String, IndentingPrintWriter writer)1034     private void runSetAudioMirror(String zoneId1String, String zoneId2String,
1035             IndentingPrintWriter writer) {
1036         int zoneId1 = Integer.parseInt(zoneId1String);
1037         int zoneId2 = Integer.parseInt(zoneId2String);
1038 
1039         if (mMirrorStatusCallback == null) {
1040             mMirrorStatusCallback = new AudioZoneMirrorStatusCallbackImpl();
1041             boolean registered = mCarAudioService.registerAudioZonesMirrorStatusCallback(
1042                     mMirrorStatusCallback);
1043             if (!registered) {
1044                 writer.printf("Could not register audio mirror status callback for zones %s %s\n",
1045                         zoneId1String, zoneId2String);
1046                 mMirrorStatusCallback = null;
1047                 return;
1048             }
1049         }
1050         mMirrorStatusCallback.reset();
1051 
1052         mCarAudioService.enableMirrorForAudioZones(new int[] {zoneId1, zoneId2});
1053         boolean called;
1054         try {
1055             called = mMirrorStatusCallback.waitForCallback();
1056         } catch (Exception e) {
1057             Slogf.e(TAG, e, "runSetAudioMirror wait for callback failed for zones %s %s",
1058                     zoneId1String, zoneId2String);
1059             return;
1060         }
1061 
1062         if (!called) {
1063             writer.printf("Did not receive mirror status callback for zones %s %s\n",
1064                     zoneId1String, zoneId2String);
1065             return;
1066         }
1067 
1068         writer.printf("Received mirror status callback for zones %s %s\n", zoneId1String,
1069                 zoneId2String);
1070         writer.increaseIndent();
1071         for (int c = 0; c < mMirrorStatusCallback.mZoneIds.length; c++) {
1072             writer.printf("Received zone[%d] %d\n", c , mMirrorStatusCallback.mZoneIds[c]);
1073         }
1074         writer.printf("Received status %d\n", mMirrorStatusCallback.mStatus);
1075         writer.decreaseIndent();
1076     }
1077 
runUnsetAudioMirror(String[] args, IndentingPrintWriter writer)1078     private void runUnsetAudioMirror(String[] args, IndentingPrintWriter writer) {
1079         boolean useConfig = false;
1080         for (int i = 2; i < args.length; i++) {
1081             String arg = args[i];
1082             switch (arg) {
1083                 case "--requestId":
1084                     useConfig = true;
1085                     break;
1086                 default:
1087                     writer.println("Invalid option at index " + i + ": " + arg);
1088                     return;
1089             }
1090         }
1091         String inputString = args[1];
1092         if (mMirrorStatusCallback == null) {
1093             mMirrorStatusCallback = new AudioZoneMirrorStatusCallbackImpl();
1094             boolean registered = mCarAudioService.registerAudioZonesMirrorStatusCallback(
1095                     mMirrorStatusCallback);
1096             if (!registered) {
1097                 mMirrorStatusCallback = null;
1098                 return;
1099             }
1100         }
1101         mMirrorStatusCallback.reset();
1102 
1103         if (useConfig) {
1104             long requestId = Long.parseLong(inputString);
1105             mCarAudioService.disableAudioMirror(requestId);
1106         } else {
1107             int zoneId = Integer.parseInt(inputString);
1108             mCarAudioService.disableAudioMirrorForZone(zoneId);
1109         }
1110 
1111         boolean called;
1112         try {
1113             called = mMirrorStatusCallback.waitForCallback();
1114         } catch (Exception e) {
1115             Slogf.e(TAG, e, "runUnsetAudioMirror wait for callback failed for zones %s",
1116                     inputString);
1117             return;
1118         }
1119 
1120         if (!called) {
1121             writer.printf("Did not receive mirror status callback for zones %s\n", inputString);
1122             return;
1123         }
1124 
1125         writer.printf("Received mirror status callback for zones %s\n", inputString);
1126         writer.increaseIndent();
1127         for (int c = 0; c < mMirrorStatusCallback.mZoneIds.length; c++) {
1128             writer.printf("Received zone[%d] %d\n", c , mMirrorStatusCallback.mZoneIds[c]);
1129         }
1130         writer.printf("Received status %d\n", mMirrorStatusCallback.mStatus);
1131         writer.decreaseIndent();
1132 
1133         mCarAudioService.unregisterAudioZonesMirrorStatusCallback(mMirrorStatusCallback);
1134     }
1135 
runResetSelectedVolumeContext()1136     private void runResetSelectedVolumeContext() {
1137         mCarAudioService.resetSelectedVolumeContext();
1138     }
1139 
runSetOccupantZoneIdForUserId(String occupantZoneIdString, String userIdString)1140     private void runSetOccupantZoneIdForUserId(String occupantZoneIdString,
1141             String userIdString) {
1142         int userId = Integer.parseInt(userIdString);
1143         int occupantZoneId = Integer.parseInt(occupantZoneIdString);
1144         if (!mCarOccupantZoneService.assignProfileUserToOccupantZone(occupantZoneId, userId)) {
1145             throw new IllegalStateException("Failed to set userId " + userId + " to occupantZoneId "
1146                     + occupantZoneIdString);
1147         }
1148     }
1149 
runResetOccupantZoneId(String occupantZoneIdString)1150     private void runResetOccupantZoneId(String occupantZoneIdString) {
1151         int occupantZoneId = Integer.parseInt(occupantZoneIdString);
1152         if (!mCarOccupantZoneService
1153                 .assignProfileUserToOccupantZone(occupantZoneId, UserManagerHelper.USER_NULL)) {
1154             throw new IllegalStateException("Failed to reset occupantZoneId "
1155                     + occupantZoneIdString);
1156         }
1157     }
1158 
assertHasAtLeastOnePermission(String cmd, String[] requiredPermissions)1159     private void assertHasAtLeastOnePermission(String cmd, String[] requiredPermissions) {
1160         for (String requiredPermission : requiredPermissions) {
1161             if (CarServiceUtils.hasPermission(mContext, requiredPermission)) return;
1162         }
1163         if (requiredPermissions.length == 1) {
1164             throw new SecurityException("The command '" + cmd + "' requires permission:"
1165                     + requiredPermissions[0]);
1166         }
1167         throw new SecurityException(
1168                 "The command " + cmd + " requires one of the following permissions:"
1169                         + Arrays.toString(requiredPermissions));
1170     }
1171 
exec(String[] args, IndentingPrintWriter writer)1172     int exec(String[] args, IndentingPrintWriter writer) {
1173         String cmd = args[0];
1174         String[] requiredPermissions = USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.get(cmd);
1175         if (requiredPermissions == null) {
1176             String requiredPermission = USER_BUILD_COMMAND_TO_PERMISSION_MAP.get(cmd);
1177             if (requiredPermission != null) {
1178                 requiredPermissions = new String[] { requiredPermission };
1179             }
1180 
1181         }
1182         if (VERBOSE) {
1183             Slogf.v(TAG, "cmd: " + cmd + ", requiredPermissions: "
1184                     + Arrays.toString(requiredPermissions));
1185         }
1186         if (BuildHelper.isUserBuild() && requiredPermissions == null) {
1187             throw new SecurityException("The command '" + cmd + "' requires non-user build");
1188         }
1189         if (requiredPermissions != null) {
1190             assertHasAtLeastOnePermission(cmd, requiredPermissions);
1191         }
1192 
1193         switch (cmd) {
1194             case COMMAND_HELP:
1195                 showHelp(writer);
1196                 break;
1197             case COMMAND_DAY_NIGHT_MODE: {
1198                 String value = args.length < 2 ? "" : args[1];
1199                 forceDayNightMode(value, writer);
1200                 break;
1201             }
1202             case COMMAND_GARAGE_MODE: {
1203                 String value = args.length < 2 ? "" : args[1];
1204                 forceGarageMode(value, writer);
1205                 break;
1206             }
1207             case COMMAND_INJECT_VHAL_EVENT:
1208                 injectVhalEvent(args, writer);
1209                 break;
1210             case COMMAND_INJECT_CONTINUOUS_EVENT:
1211                 injectContinuousEvents(args, writer);
1212                 break;
1213             case COMMAND_INJECT_ERROR_EVENT:
1214                 injectErrorEvent(args, writer);
1215                 break;
1216             case COMMAND_ENABLE_UXR:
1217                 if (args.length != 2) {
1218                     return showInvalidArguments(writer);
1219                 }
1220                 boolean enableBlocking = Boolean.valueOf(args[1]);
1221                 if (mCarPackageManagerService != null) {
1222                     // Need to clear the binder identity if calling process is root since
1223                     // signature will not match with that of car service.
1224                     final long identity = Binder.clearCallingIdentity();
1225                     try {
1226                         mCarPackageManagerService.setEnableActivityBlocking(enableBlocking);
1227                     } finally {
1228                         Binder.restoreCallingIdentity(identity);
1229                     }
1230                 }
1231                 break;
1232             case COMMAND_GET_DO_ACTIVITIES:
1233                 if (args.length != 2) {
1234                     return showInvalidArguments(writer);
1235                 }
1236                 String pkgName = args[1].toLowerCase(Locale.US);
1237                 if (mCarPackageManagerService != null) {
1238                     String[] doActivities =
1239                             mCarPackageManagerService.getDistractionOptimizedActivities(
1240                                     pkgName);
1241                     if (doActivities != null) {
1242                         writer.println("DO Activities for " + pkgName);
1243                         for (String a : doActivities) {
1244                             writer.println(a);
1245                         }
1246                     } else {
1247                         writer.println("No DO Activities for " + pkgName);
1248                     }
1249                 }
1250                 break;
1251             case COMMAND_GET_CARPROPERTYCONFIG:
1252                 getCarPropertyConfig(args, writer);
1253                 break;
1254             case COMMAND_GET_PROPERTY_VALUE:
1255                 getPropertyValue(args, writer);
1256                 break;
1257             case COMMAND_GENERATE_TEST_VENDOR_CONFIGS:
1258                 try (CarTestService.NativePipe pipe = CarTestService.NativePipe.newPipe()) {
1259                     mHal.dumpVhal(pipe.getFileDescriptor(), List.of("--genTestVendorConfigs"));
1260                     writer.print(pipe.getOutput(DEFAULT_HAL_TIMEOUT_MS));
1261                 } catch (Exception e) {
1262                     Slogf.w(TAG, "dumpVhal --genTestVendorConfigs Failed", e);
1263                     return showInvalidArguments(writer);
1264                 }
1265                 break;
1266             case COMMAND_RESTORE_TEST_VENDOR_CONFIGS:
1267                 try (CarTestService.NativePipe pipe = CarTestService.NativePipe.newPipe()) {
1268                     mHal.dumpVhal(pipe.getFileDescriptor(), List.of("--restoreVendorConfigs"));
1269                     writer.print(pipe.getOutput(DEFAULT_HAL_TIMEOUT_MS));
1270                 } catch (Exception e) {
1271                     Slogf.w(TAG, "dumpVhal --genTestVendorConfigs Failed", e);
1272                     return showInvalidArguments(writer);
1273                 }
1274                 break;
1275             case COMMAND_SET_PROPERTY_VALUE:
1276                 setPropertyValue(args, writer);
1277                 break;
1278             case COMMAND_PROJECTION_UI_MODE:
1279                 if (args.length != 2) {
1280                     return showInvalidArguments(writer);
1281                 }
1282                 mCarProjectionService.setUiMode(Integer.valueOf(args[1]));
1283                 break;
1284             case COMMAND_PROJECTION_AP_TETHERING:
1285                 if (args.length != 2) {
1286                     return showInvalidArguments(writer);
1287                 }
1288                 mCarProjectionService.setAccessPointTethering(Boolean.parseBoolean(args[1]));
1289                 break;
1290             case COMMAND_PROJECTION_AP_STABLE_CONFIG:
1291                 if (args.length != 2) {
1292                     return showInvalidArguments(writer);
1293                 }
1294                 mCarProjectionService.setStableLocalOnlyHotspotConfig(
1295                         Boolean.parseBoolean(args[1]));
1296                 break;
1297             case COMMAND_RESUME:
1298                 mCarPowerManagementService.forceSimulatedResume();
1299                 writer.println("Resume: Simulating resuming from Deep Sleep");
1300                 break;
1301             case COMMAND_SUSPEND:
1302                 // fall-through
1303             case COMMAND_HIBERNATE:
1304                 runSuspendCommand(args, writer);
1305                 break;
1306             case COMMAND_SET_DISPLAY_STATE:
1307                 if (args.length != 3) {
1308                     return showInvalidArguments(writer);
1309                 }
1310                 try {
1311                     mCarPowerManagementService.setDisplayPowerState(
1312                             Integer.valueOf(args[1]), Boolean.parseBoolean(args[2]));
1313                 } catch (Exception e) {
1314                     Slogf.w(TAG, "Invalid argument: %s %s %s", COMMAND_SET_DISPLAY_STATE, args[1],
1315                             args[2]);
1316                     return showInvalidArguments(writer);
1317                 }
1318                 break;
1319             case COMMAND_SET_UID_TO_ZONE:
1320                 if (args.length != 3) {
1321                     return showInvalidArguments(writer);
1322                 }
1323                 runSetZoneIdForUid(args[1], args[2]);
1324                 break;
1325             case COMMAND_RESET_VOLUME_CONTEXT:
1326                 if (args.length > 1) {
1327                     return showInvalidArguments(writer);
1328                 }
1329                 runResetSelectedVolumeContext();
1330                 break;
1331             case COMMAND_SET_MUTE_CAR_VOLUME_GROUP:
1332                 if (args.length != 4) {
1333                     return showInvalidArguments(writer);
1334                 }
1335                 runSetMuteCarVolumeGroup(args[1], args[2], args[3]);
1336                 break;
1337             case COMMAND_SET_GROUP_VOLUME:
1338                 if (args.length != 4) {
1339                     return showInvalidArguments(writer);
1340                 }
1341                 runSetGroupVolume(args[1], args[2], args[3]);
1342                 break;
1343             case COMMAND_SET_AUDIO_MIRROR:
1344                 if (args.length != 3) {
1345                     return showInvalidArguments(writer);
1346                 }
1347                 runSetAudioMirror(args[1], args[2], writer);
1348                 break;
1349             case COMMAND_UNSET_AUDIO_MIRROR:
1350                 if (args.length < 1) {
1351                     return showInvalidArguments(writer);
1352                 }
1353                 runUnsetAudioMirror(args, writer);
1354                 break;
1355             case COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE:
1356                 if (args.length != 3) {
1357                     return showInvalidArguments(writer);
1358                 }
1359                 runSetOccupantZoneIdForUserId(args[1], args[2]);
1360                 break;
1361             case COMMAND_SILENT_MODE: {
1362                 String value = args.length < 2 ? ""
1363                         : args.length == 2 ? args[1] : "too many arguments";
1364                 runSilentCommand(value, writer);
1365                 break;
1366             }
1367             case COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE:
1368                 if (args.length != 2) {
1369                     return showInvalidArguments(writer);
1370                 }
1371                 runResetOccupantZoneId(args[1]);
1372                 break;
1373             case COMMAND_START_FIXED_ACTIVITY_MODE:
1374                 startFixedActivity(args, writer);
1375                 break;
1376             case COMMAND_STOP_FIXED_ACTIVITY_MODE:
1377                 stopFixedMode(args, writer);
1378                 break;
1379             case COMMAND_ENABLE_FEATURE:
1380                 if (args.length != 2) {
1381                     return showInvalidArguments(writer);
1382                 }
1383                 enableDisableFeature(args, writer, /* enable= */ true);
1384                 break;
1385             case COMMAND_DISABLE_FEATURE:
1386                 if (args.length != 2) {
1387                     return showInvalidArguments(writer);
1388                 }
1389                 enableDisableFeature(args, writer, /* enable= */ false);
1390                 break;
1391             case COMMAND_INJECT_KEY:
1392                 if (args.length < 2) {
1393                     return showInvalidArguments(writer);
1394                 }
1395                 injectKey(args, writer);
1396                 break;
1397             case COMMAND_INJECT_MOTION:
1398                 if (args.length < 2) {
1399                     return showInvalidArguments(writer);
1400                 }
1401                 injectMotion(args, writer);
1402                 break;
1403             case COMMAND_INJECT_ROTARY:
1404                 if (args.length < 1) {
1405                     return showInvalidArguments(writer);
1406                 }
1407                 injectRotary(args, writer);
1408                 break;
1409             case COMMAND_INJECT_CUSTOM_INPUT:
1410                 if (args.length < 2) {
1411                     return showInvalidArguments(writer);
1412                 }
1413                 injectCustomInputEvent(args, writer);
1414                 break;
1415             case COMMAND_GET_INITIAL_USER_INFO:
1416                 getInitialUserInfo(args, writer);
1417                 break;
1418             case COMMAND_SWITCH_USER:
1419                 switchUser(args, writer);
1420                 break;
1421             case COMMAND_LOGOUT_USER:
1422                 logoutUser(args, writer);
1423                 break;
1424             case COMMAND_REMOVE_USER:
1425                 removeUser(args, writer);
1426                 break;
1427             case COMMAND_CREATE_USER:
1428                 createUser(args, writer);
1429                 break;
1430             case COMMAND_GET_INITIAL_USER:
1431                 getInitialUser(writer);
1432                 break;
1433             case COMMAND_GET_USER_AUTH_ASSOCIATION:
1434                 getUserAuthAssociation(args, writer);
1435                 break;
1436             case COMMAND_SET_USER_AUTH_ASSOCIATION:
1437                 setUserAuthAssociation(args, writer);
1438                 break;
1439             case COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE:
1440                 setStartBackgroundUsersOnGarageMode(args, writer);
1441                 break;
1442             case COMMAND_EMULATE_DRIVING_STATE:
1443                 emulateDrivingState(args, writer);
1444                 break;
1445             case COMMAND_DEFINE_POWER_POLICY:
1446                 return definePowerPolicy(args, writer);
1447             case COMMAND_APPLY_POWER_POLICY:
1448                 return applyPowerPolicy(args, writer);
1449             case COMMAND_DEFINE_POWER_POLICY_GROUP:
1450                 return definePowerPolicyGroup(args, writer);
1451             case COMMAND_SET_POWER_POLICY_GROUP:
1452                 return setPowerPolicyGroup(args, writer);
1453             case COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY:
1454                 return applyCtsVerifierPowerOffPolicy(args, writer);
1455             case COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY:
1456                 return applyCtsVerifierPowerOnPolicy(args, writer);
1457             case COMMAND_POWER_OFF:
1458                 powerOff(args, writer);
1459                 break;
1460             case COMMAND_SET_REARVIEW_CAMERA_ID:
1461                 setRearviewCameraId(args, writer);
1462                 break;
1463             case COMMAND_GET_REARVIEW_CAMERA_ID:
1464                 getRearviewCameraId(writer);
1465                 break;
1466             case COMMAND_SET_CAMERA_ID:
1467                 setCameraId(args, writer);
1468                 break;
1469             case COMMAND_GET_CAMERA_ID:
1470                 getCameraId(args, writer);
1471                 break;
1472             case COMMAND_ENABLE_CAMERA_SERVICE_TYPE:
1473                 enableCameraServiceType(args, writer);
1474                 break;
1475             case COMMAND_CHECK_CAMERA_SERVICE_TYPE_ENABLED:
1476                 checkCameraServiceTypeEnabled(args, writer);
1477                 break;
1478             case COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE:
1479                 controlWatchdogPackageKillableState(args, writer);
1480                 break;
1481             case COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES:
1482                 setWatchdogIoThirdPartyForegroundBytes(args, writer);
1483                 break;
1484             case COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES:
1485                 getWatchdogIoThirdPartyForegroundBytes(writer);
1486                 break;
1487             case COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK:
1488                 controlWatchdogProcessHealthCheck(args, writer);
1489                 break;
1490             case COMMAND_WATCHDOG_RESOURCE_OVERUSE_KILL:
1491                 performResourceOveruseKill(args, writer);
1492                 break;
1493             case COMMAND_DRIVING_SAFETY_SET_REGION:
1494                 setDrivingSafetyRegion(args, writer);
1495                 break;
1496             case COMMAND_TELEMETRY:
1497                 handleTelemetryCommands(args, writer);
1498                 break;
1499             case COMMAND_CONTROL_COMPONENT_ENABLED_STATE:
1500                 controlComponentEnabledState(args, writer);
1501                 break;
1502             case COMMAND_CHECK_LOCK_IS_SECURE:
1503                 checkLockIsSecure(args, writer);
1504                 break;
1505             case COMMAND_CHECK_FAKE_VHAL:
1506                 writer.printf("Car Service connects to FakeVehicleStub: %b\n",
1507                         mHal.isFakeModeEnabled());
1508                 break;
1509             case COMMAND_LIST_VHAL_PROPS:
1510                 listVhalProps(writer);
1511                 break;
1512             case COMMAND_GET_VHAL_BACKEND:
1513                 getVhalBackend(writer);
1514                 break;
1515             case COMMAND_TEST_ECHO_REVERSE_BYTES:
1516                 testEchoReverseBytes(args, writer);
1517                 break;
1518             case COMMAND_GET_TARGET_CAR_VERSION:
1519                 getTargetCarVersion(args, writer);
1520                 break;
1521             case COMMAND_SET_PROCESS_GROUP:
1522                 setProcessGroup(args, writer);
1523                 break;
1524             case COMMAND_GET_PROCESS_GROUP:
1525                 getProcessGroup(args, writer);
1526                 break;
1527             case COMMAND_SET_PROCESS_PROFILE:
1528                 setProcessProfile(args, writer);
1529                 break;
1530             case COMMAND_GET_DISPLAY_BY_USER:
1531                 getDisplayByUser(args, writer);
1532                 break;
1533             case COMMAND_GET_USER_BY_DISPLAY:
1534                 getUserByDisplay(args, writer);
1535                 break;
1536             case COMMAND_GET_CURRENT_UX_RESTRICTIONS:
1537                 getCurrentUxRestrictions(args, writer);
1538                 break;
1539             case COMMAND_SET_CURRENT_UXR_MODE:
1540                 setCurrentUxrMode(args, writer);
1541                 break;
1542             case COMMAND_GET_CURRENT_UXR_MODE:
1543                 getCurrentUxrMode(args, writer);
1544                 break;
1545             case COMMAND_GET_SUPPORTED_UXR_MODES:
1546                 getSupportedUxRModes(writer);
1547                 break;
1548             case COMMAND_GET_UXR_CONFIG:
1549                 getUxrConfig(writer);
1550                 break;
1551             case COMMAND_GET_INPUT_AND_DISPLAY_INFO:
1552                 getInputAndDisplayInfo(writer);
1553                 break;
1554             case COMMAND_ADD_INPUT_DESCRIPTOR_ASSOCIATION_TO_DISPLAY_UNIQUE_ID:
1555                 addInputDescriptorAssociationToDisplayUniqueId(args, writer);
1556                 break;
1557             case COMMAND_REMOVE_INPUT_DESCRIPTOR_ASSOCIATION:
1558                 removeInputDescriptorAssociation(args, writer);
1559                 break;
1560             default:
1561                 writer.println("Unknown command: \"" + cmd + "\"");
1562                 showHelp(writer);
1563                 return RESULT_ERROR;
1564         }
1565         return RESULT_OK;
1566     }
1567 
1568     private void getUxrConfig(IndentingPrintWriter writer) {
1569         writer.println(mCarUxRestrictionsManagerService.getConfigs());
1570     }
1571 
1572     private void getSupportedUxRModes(IndentingPrintWriter writer) {
1573         writer.println(mCarUxRestrictionsManagerService.getSupportedRestrictionModes());
1574     }
1575 
1576     private void getCurrentUxrMode(String[] args, IndentingPrintWriter writer) {
1577         writer.printf("Current Uxr restrictions mode: %s\n",
1578                 mCarUxRestrictionsManagerService.getRestrictionMode());
1579     }
1580 
1581     private void setCurrentUxrMode(String[] args, IndentingPrintWriter writer) {
1582         if (args.length < 2) {
1583             writer.println("Insufficient number of args");
1584             return;
1585         }
1586 
1587         String mode = args[1];
1588         mCarUxRestrictionsManagerService.setRestrictionMode(mode);
1589         writer.printf("Current Uxr restrictions mode set to: %s\n", mode);
1590     }
1591 
1592     private void getCurrentUxRestrictions(String[] args, IndentingPrintWriter writer) {
1593         int displayId = Display.DEFAULT_DISPLAY;
1594         if (args.length == 2) {
1595             displayId = Integer.parseInt(args[1]);
1596         }
1597 
1598         CarUxRestrictions restrictions = mCarUxRestrictionsManagerService
1599                 .getCurrentUxRestrictions(displayId);
1600         writer.printf("Current Restrictions:\n %s", restrictions.getActiveRestrictionsString());
1601     }
1602 
1603     private void getInputAndDisplayInfo(IndentingPrintWriter writer) {
1604         InputManager inputManager = mContext.getSystemService(InputManager.class);
1605         int[] inputDeviceIds = inputManager.getInputDeviceIds();
1606 
1607         for (int inputDeviceId : inputDeviceIds) {
1608             InputDevice device = inputManager.getInputDevice(inputDeviceId);
1609             String deviceInfo = "Input Device " + device.getId() + ": " + device.getName() + "\n"
1610                     + "\tDescriptor: " + device.getDescriptor() + "\n";
1611             writer.printf(deviceInfo);
1612         }
1613 
1614         DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
1615         Display[] displays = displayManager.getDisplays();
1616         for (Display display : displays) {
1617             String displayInfo = "Display Devices " + display.getDisplayId() + ": \n"
1618                     + "\tUniqueId: " + DisplayManagerHelper.getUniqueId(display) + " \n";
1619             writer.printf(displayInfo);
1620         }
1621     }
1622 
1623     private void addInputDescriptorAssociationToDisplayUniqueId(String[] args,
1624             IndentingPrintWriter writer) {
1625         InputManager inputManager = mContext.getSystemService(InputManager.class);
1626         if (args.length == 3) {
1627             InputManagerHelper.addUniqueIdAssociationByDescriptor(inputManager, args[1], args[2]);
1628             writer.println("Associated input " + args[1] + " with display " + args[2] + "\n");
1629         } else {
1630             writer.printf("Incorrect Usage.\nUsage: %s <inputDeviceDescriptor> <displayUniqueId>\n",
1631                     COMMAND_ADD_INPUT_DESCRIPTOR_ASSOCIATION_TO_DISPLAY_UNIQUE_ID);
1632         }
1633     }
1634 
1635     private void removeInputDescriptorAssociation(String[] args, IndentingPrintWriter writer) {
1636         InputManager inputManager = mContext.getSystemService(InputManager.class);
1637         if (args.length == 2) {
1638             InputManagerHelper.removeUniqueIdAssociationByDescriptor(inputManager, args[1]);
1639             writer.println("Input " + args[1] + " association removed.\n");
1640         } else {
1641             writer.printf("Incorrect Usage.\nUsage: %s <inputDeviceDescriptor>\n",
1642                     COMMAND_REMOVE_INPUT_DESCRIPTOR_ASSOCIATION);
1643         }
1644     }
1645 
1646     private void setStartBackgroundUsersOnGarageMode(String[] args, IndentingPrintWriter writer) {
1647         if (args.length < 2) {
1648             writer.println("Insufficient number of args");
1649             return;
1650         }
1651 
1652         boolean enabled = Boolean.parseBoolean(args[1]);
1653         Slogf.d(TAG, "setStartBackgroundUsersOnGarageMode(): "
1654                 + (enabled ? "enabled" : "disabled"));
1655         mCarUserService.setStartBackgroundUsersOnGarageMode(enabled);
1656         writer.printf("StartBackgroundUsersOnGarageMode set to %b\n", enabled);
1657     }
1658 
1659     private void startFixedActivity(String[] args, IndentingPrintWriter writer) {
1660         if (args.length != 4) {
1661             writer.println("Incorrect number of arguments");
1662             showHelp(writer);
1663             return;
1664         }
1665         int displayId;
1666         try {
1667             displayId = Integer.parseInt(args[1]);
1668         } catch (NumberFormatException e) {
1669             writer.println("Wrong display id:" + args[1]);
1670             return;
1671         }
1672         String packageName = args[2];
1673         String activityName = args[3];
1674         Intent intent = new Intent();
1675         intent.setComponent(new ComponentName(packageName, activityName));
1676         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1677         ActivityOptions options = ActivityOptions.makeBasic();
1678         options.setLaunchDisplayId(displayId);
1679         if (!mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
1680                 displayId, ActivityManager.getCurrentUser())) {
1681             writer.println("Failed to start");
1682             return;
1683         }
1684         writer.println("Succeeded");
1685     }
1686 
1687     private void stopFixedMode(String[] args, IndentingPrintWriter writer) {
1688         if (args.length != 2) {
1689             writer.println("Incorrect number of arguments");
1690             showHelp(writer);
1691             return;
1692         }
1693         int displayId;
1694         try {
1695             displayId = Integer.parseInt(args[1]);
1696         } catch (NumberFormatException e) {
1697             writer.println("Wrong display id:" + args[1]);
1698             return;
1699         }
1700         mFixedActivityService.stopFixedActivityMode(displayId);
1701     }
1702 
1703     private void enableDisableFeature(String[] args, IndentingPrintWriter writer, boolean enable) {
1704         if (Binder.getCallingUid() != Process.ROOT_UID) {
1705             writer.println("Only allowed to root/su");
1706             return;
1707         }
1708         String featureName = args[1];
1709         long id = Binder.clearCallingIdentity();
1710         // no permission check here
1711         int r;
1712         if (enable) {
1713             r = mFeatureController.enableFeature(featureName);
1714         } else {
1715             r = mFeatureController.disableFeature(featureName);
1716         }
1717         switch (r) {
1718             case Car.FEATURE_REQUEST_SUCCESS:
1719                 if (enable) {
1720                     writer.println("Enabled feature:" + featureName);
1721                 } else {
1722                     writer.println("Disabled feature:" + featureName);
1723                 }
1724                 break;
1725             case Car.FEATURE_REQUEST_ALREADY_IN_THE_STATE:
1726                 if (enable) {
1727                     writer.println("Already enabled:" + featureName);
1728                 } else {
1729                     writer.println("Already disabled:" + featureName);
1730                 }
1731                 break;
1732             case Car.FEATURE_REQUEST_MANDATORY:
1733                 writer.println("Cannot change mandatory feature:" + featureName);
1734                 break;
1735             case Car.FEATURE_REQUEST_NOT_EXISTING:
1736                 writer.println("Non-existing feature:" + featureName);
1737                 break;
1738             default:
1739                 writer.println("Unknown error:" + r);
1740                 break;
1741         }
1742         Binder.restoreCallingIdentity(id);
1743     }
1744 
1745     private static int decodeAreaId(String areaIdString) {
1746         try {
1747             return Integer.decode(areaIdString);
1748         } catch (NumberFormatException e) {
1749             throw new NumberFormatException(
1750                     "Failed to decode area ID from: " + areaIdString + " - exception: "
1751                             + e);
1752         }
1753     }
1754 
1755     private static int decodePropertyId(String propertyIdString) {
1756         if (toPropertyId(propertyIdString) != null) {
1757             return toPropertyId(propertyIdString).intValue();
1758         }
1759 
1760         try {
1761             return Integer.decode(propertyIdString);
1762         } catch (NumberFormatException e) {
1763             throw new NumberFormatException(
1764                     "Failed to decode property ID from: " + propertyIdString + " - exception: "
1765                             + e);
1766         }
1767     }
1768 
1769     private void injectKey(String[] args, IndentingPrintWriter writer) {
1770         int i = 1; // 0 is command itself
1771         int display = CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
1772         int delayMs = 0;
1773         int keyCode = KeyEvent.KEYCODE_UNKNOWN;
1774         int action = -1;
1775         int seat = SEAT_UNKNOWN;
1776         try {
1777             while (i < args.length) {
1778                 switch (args[i]) {
1779                     case "-d":
1780                         i++;
1781                         int vehicleDisplay = Integer.parseInt(args[i]);
1782                         if (!checkVehicleDisplay(vehicleDisplay, writer)) {
1783                             return;
1784                         }
1785                         display = InputHalService.convertDisplayType(vehicleDisplay);
1786                         break;
1787                     case "-t":
1788                         i++;
1789                         delayMs = Integer.parseInt(args[i]);
1790                         break;
1791                     case "-a":
1792                         i++;
1793                         if (args[i].equalsIgnoreCase("down")) {
1794                             action = KeyEvent.ACTION_DOWN;
1795                         } else if (args[i].equalsIgnoreCase("up")) {
1796                             action = KeyEvent.ACTION_UP;
1797                         } else {
1798                             throw new IllegalArgumentException("Invalid action: " + args[i]);
1799                         }
1800                         break;
1801                     case "-s":
1802                         i++;
1803                         seat = parseUnsignedInt(args[i]);
1804                         break;
1805                     default:
1806                         if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
1807                             throw new IllegalArgumentException("key_code already set:"
1808                                     + keyCode);
1809                         }
1810                         keyCode = Integer.parseInt(args[i]);
1811                 }
1812                 i++;
1813             }
1814         } catch (NumberFormatException e) {
1815             writer.println("Invalid args:" + e);
1816             showHelp(writer);
1817             return;
1818         }
1819 
1820         if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
1821             writer.println("Missing key code or invalid keycode");
1822             showHelp(writer);
1823             return;
1824         }
1825         if (delayMs < 0) {
1826             writer.println("Invalid delay:" + delayMs);
1827             showHelp(writer);
1828             return;
1829         }
1830         if (action == -1) {
1831             injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, display, seat);
1832             SystemClock.sleep(delayMs);
1833             injectKeyEvent(KeyEvent.ACTION_UP, keyCode, display, seat);
1834         } else {
1835             injectKeyEvent(action, keyCode, display, seat);
1836         }
1837         writer.println("Succeeded");
1838     }
1839 
1840     private void injectKeyEvent(int action, int keyCode, int display, int seat) {
1841         long currentTime = SystemClock.uptimeMillis();
1842         if (action == KeyEvent.ACTION_DOWN) mKeyDownTime = currentTime;
1843         long token = Binder.clearCallingIdentity();
1844         try {
1845             KeyEvent keyEvent = new KeyEvent(/* downTime= */ mKeyDownTime,
1846                             /* eventTime= */ currentTime, action, keyCode, /* repeat= */ 0);
1847             if (seat == SEAT_UNKNOWN) {
1848                 // Overwrite with the driver seat
1849                 seat = mCarOccupantZoneService.getDriverSeat();
1850             }
1851             mCarInputService.injectKeyEventForSeat(keyEvent, display, seat);
1852         } finally {
1853             Binder.restoreCallingIdentity(token);
1854         }
1855     }
1856 
1857     private void injectMotion(String[] args, IndentingPrintWriter writer) {
1858         int i = 1; // 0 is command itself
1859         int display = CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
1860         int delayMs = 0;
1861         int action = -1;
1862         int seat = SEAT_UNKNOWN;
1863         int count = 1;
1864         List<Float> coordXs = new ArrayList<>();
1865         List<Float> coordYs = new ArrayList<>();
1866         List<Integer> pointerIds = new ArrayList<>();
1867         int source = InputDevice.SOURCE_TOUCHSCREEN;
1868         try {
1869             while (i < args.length) {
1870                 switch (args[i]) {
1871                     case "-d":
1872                         i++;
1873                         int vehicleDisplay = Integer.parseInt(args[i]);
1874                         if (!checkVehicleDisplay(vehicleDisplay, writer)) {
1875                             return;
1876                         }
1877                         display = InputHalService.convertDisplayType(vehicleDisplay);
1878                         break;
1879                     case "-t":
1880                         i++;
1881                         delayMs = Integer.parseInt(args[i]);
1882                         break;
1883                     case "-a":
1884                         i++;
1885                         if (args[i].equalsIgnoreCase("down")) {
1886                             action = MotionEvent.ACTION_DOWN;
1887                         } else if (args[i].equalsIgnoreCase("up")) {
1888                             action = MotionEvent.ACTION_UP;
1889                         } else if (args[i].equalsIgnoreCase("move")) {
1890                             action = MotionEvent.ACTION_MOVE;
1891                         } else if (args[i].equalsIgnoreCase("cancel")) {
1892                             action = MotionEvent.ACTION_CANCEL;
1893                         } else {
1894                             action = parseUnsignedInt(args[i]);
1895                         }
1896                         break;
1897                     case "-s":
1898                         i++;
1899                         seat = parseUnsignedInt(args[i]);
1900                         break;
1901                     case "-c":
1902                         i++;
1903                         count = Integer.parseInt(args[i]);
1904                         break;
1905                     case "-p":
1906                         for (int j = 0; j < count; j++) {
1907                             i++;
1908                             pointerIds.add(Integer.parseInt(args[i]));
1909                         }
1910                         break;
1911                     case "--source":
1912                         i++;
1913                         if (MOTION_EVENT_SOURCES.containsKey(args[i])) {
1914                             source = MOTION_EVENT_SOURCES.get(args[i]);
1915                         }
1916                         break;
1917                     default:
1918                         int remainedArgNum = args.length - i;
1919                         if (remainedArgNum != (count * 2)) {
1920                             throw new IllegalArgumentException("Invalid coordinate: It needs "
1921                                     + count + " coordinates.");
1922                         }
1923                         while (i < args.length) {
1924                             coordXs.add(Float.parseFloat(args[i]));
1925                             i++;
1926                             coordYs.add(Float.parseFloat(args[i]));
1927                             i++;
1928                         }
1929                 }
1930                 i++;
1931             }
1932         } catch (NumberFormatException e) {
1933             writer.println("Invalid args:" + e);
1934             showHelp(writer);
1935             return;
1936         }
1937 
1938         if (delayMs < 0) {
1939             writer.println("Invalid delay:" + delayMs);
1940             showHelp(writer);
1941             return;
1942         }
1943         if (coordXs.isEmpty() || coordYs.isEmpty()) {
1944             writer.println("Missing x, y coordinate");
1945             showHelp(writer);
1946             return;
1947         }
1948         if (action == -1) {
1949             injectMotionEvent(source, MotionEvent.ACTION_DOWN, coordXs, coordYs, pointerIds,
1950                     display, seat);
1951             SystemClock.sleep(delayMs);
1952             injectMotionEvent(source, MotionEvent.ACTION_UP, coordXs, coordYs, pointerIds,
1953                     display, seat);
1954         } else {
1955             injectMotionEvent(source, action, coordXs, coordYs, pointerIds, display, seat);
1956         }
1957         writer.println("Succeeded");
1958     }
1959 
1960     // value can be a hex or decimal string.
1961     private static int parseUnsignedInt(String value) {
1962         if (value.startsWith("0x")) {
1963             return Integer.parseUnsignedInt(value.substring(2), 16);
1964         } else {
1965             return Integer.parseUnsignedInt(value);
1966         }
1967     }
1968 
1969     private static int getToolType(int inputSource) {
1970         switch(inputSource) {
1971             case InputDevice.SOURCE_MOUSE:
1972             case InputDevice.SOURCE_MOUSE_RELATIVE:
1973             case InputDevice.SOURCE_TRACKBALL:
1974                 return MotionEvent.TOOL_TYPE_MOUSE;
1975 
1976             case InputDevice.SOURCE_STYLUS:
1977             case InputDevice.SOURCE_BLUETOOTH_STYLUS:
1978                 return MotionEvent.TOOL_TYPE_STYLUS;
1979 
1980             case InputDevice.SOURCE_TOUCHPAD:
1981             case InputDevice.SOURCE_TOUCHSCREEN:
1982             case InputDevice.SOURCE_TOUCH_NAVIGATION:
1983                 return MotionEvent.TOOL_TYPE_FINGER;
1984         }
1985         return MotionEvent.TOOL_TYPE_UNKNOWN;
1986     }
1987 
1988     private static int getInputDeviceId(int inputSource) {
1989         int[] devIds = InputDevice.getDeviceIds();
1990         for (int devId : devIds) {
1991             InputDevice inputDev = InputDevice.getDevice(devId);
1992             if (inputDev.supportsSource(inputSource)) {
1993                 return devId;
1994             }
1995         }
1996         return DEFAULT_DEVICE_ID;
1997     }
1998 
1999     private void injectMotionEvent(int source, int action, List<Float> xs, List<Float> ys,
2000             List<Integer> pointerIds, int display, int seat) {
2001         long currentTime = SystemClock.uptimeMillis();
2002         if (action == MotionEvent.ACTION_DOWN) {
2003             mMotionDownTime = currentTime;
2004         }
2005         long token = Binder.clearCallingIdentity();
2006 
2007         int pointerCount = xs.size();
2008         float pressure = NO_PRESSURE;
2009         if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
2010             pressure = DEFAULT_PRESSURE;
2011         }
2012         MotionEvent.PointerProperties[] pointerProperties =
2013                 new MotionEvent.PointerProperties[pointerCount];
2014         MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
2015         int toolType = getToolType(source);
2016         for (int i = 0; i < pointerCount; i++) {
2017             pointerProperties[i] = new MotionEvent.PointerProperties();
2018             pointerProperties[i].id = pointerIds.isEmpty() ? i : pointerIds.get(i);
2019             pointerProperties[i].toolType = toolType;
2020             pointerCoords[i] = new MotionEvent.PointerCoords();
2021             pointerCoords[i].x = xs.get(i);
2022             pointerCoords[i].y = ys.get(i);
2023             pointerCoords[i].pressure = pressure;
2024             pointerCoords[i].size = DEFAULT_SIZE;
2025         }
2026 
2027         MotionEvent event = MotionEvent.obtain(
2028                     /* downTime= */ mMotionDownTime,
2029                     /* when= */ currentTime,
2030                     action,
2031                     pointerCount,
2032                     pointerProperties,
2033                     pointerCoords,
2034                     DEFAULT_META_STATE,
2035                     DEFAULT_BUTTON_STATE,
2036                     DEFAULT_PRECISION_X,
2037                     DEFAULT_PRECISION_Y,
2038                     getInputDeviceId(source),
2039                     DEFAULT_EDGE_FLAGS,
2040                     source,
2041                     DEFAULT_FLAGS
2042                 );
2043         try {
2044             if (seat == SEAT_UNKNOWN) {
2045                 // Overwrite with the driver seat
2046                 seat = mCarOccupantZoneService.getDriverSeat();
2047             }
2048             mCarInputService.injectMotionEventForSeat(event, display, seat);
2049         } finally {
2050             Binder.restoreCallingIdentity(token);
2051         }
2052     }
2053 
2054     private void injectRotary(String[] args, IndentingPrintWriter writer) {
2055         int i = 1; // 0 is command itself
2056         int display = CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
2057         int inputType = CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION;
2058         boolean clockwise = false;
2059         List<Long> deltaTimeMs = new ArrayList<>();
2060         try {
2061             while (i < args.length) {
2062                 switch (args[i]) {
2063                     case "-d":
2064                         i++;
2065                         int vehicleDisplay = Integer.parseInt(args[i]);
2066                         if (!checkVehicleDisplay(vehicleDisplay, writer)) {
2067                             return;
2068                         }
2069                         display = InputHalService.convertDisplayType(vehicleDisplay);
2070                         break;
2071                     case "-i":
2072                         i++;
2073                         inputType = Integer.parseInt(args[i]);
2074                         break;
2075                     case "-c":
2076                         i++;
2077                         clockwise = Boolean.parseBoolean(args[i]);
2078                         break;
2079                     case "-dt":
2080                         i++;
2081                         while (i < args.length) {
2082                             deltaTimeMs.add(Long.parseLong(args[i]));
2083                             i++;
2084                         }
2085                         break;
2086                     default:
2087                         writer.println("Invalid option at index " + i + ": " + args[i]);
2088                         return;
2089                 }
2090                 i++;
2091             }
2092         } catch (NumberFormatException e) {
2093             writer.println("Invalid args:" + e);
2094             showHelp(writer);
2095             return;
2096         }
2097         if (deltaTimeMs.isEmpty()) {
2098             deltaTimeMs.add(0L);
2099         }
2100         for (int j = 0; j < deltaTimeMs.size(); j++) {
2101             if (deltaTimeMs.get(j) < 0) {
2102                 writer.println("Delta time shouldn't be negative: " + deltaTimeMs.get(j));
2103                 showHelp(writer);
2104                 return;
2105             }
2106             if (j > 0 && deltaTimeMs.get(j) > deltaTimeMs.get(j - 1)) {
2107                 writer.println("Delta times should be in descending order");
2108                 showHelp(writer);
2109                 return;
2110             }
2111         }
2112         long[] uptimeMs = new long[deltaTimeMs.size()];
2113         long currentUptime = SystemClock.uptimeMillis();
2114         for (int j = 0; j < deltaTimeMs.size(); j++) {
2115             uptimeMs[j] = currentUptime - deltaTimeMs.get(j);
2116         }
2117         RotaryEvent rotaryEvent = new RotaryEvent(inputType, clockwise, uptimeMs);
2118         mCarInputService.onRotaryEvent(rotaryEvent, display);
2119         writer.println("Succeeded in injecting: " + rotaryEvent);
2120     }
2121 
2122     private void injectCustomInputEvent(String[] args, IndentingPrintWriter writer) {
2123         int display = CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
2124         int repeatCounter = 1;
2125 
2126         int argIdx = 1;
2127         for (; argIdx < args.length - 1; argIdx++) {
2128             switch (args[argIdx]) {
2129                 case "-d":
2130                     int vehicleDisplay = Integer.parseInt(args[++argIdx]);
2131                     if (!checkVehicleDisplay(vehicleDisplay, writer)) {
2132                         return;
2133                     }
2134                     display = InputHalService.convertDisplayType(vehicleDisplay);
2135                     break;
2136                 case "-r":
2137                     repeatCounter = Integer.parseInt(args[++argIdx]);
2138                     break;
2139                 default:
2140                     writer.printf("Unrecognized argument: {%s}\n", args[argIdx]);
2141                     writer.println("Pass -help to see the full list of options");
2142                     return;
2143             }
2144         }
2145 
2146         if (argIdx == args.length) {
2147             writer.println("Last mandatory argument (fn) not passed.");
2148             writer.println("Pass -help to see the full list of options");
2149             return;
2150         }
2151 
2152         // Processing the last remaining argument. Argument is expected one of the tem functions
2153         // ('f1', 'f2', ..., 'f10') or just a plain integer representing the custom input event.
2154         String eventValue = args[argIdx].toLowerCase(Locale.US);
2155         Integer inputCode;
2156         if (eventValue.startsWith("f")) {
2157             inputCode = CUSTOM_INPUT_FUNCTION_ARGS.get(eventValue);
2158             if (inputCode == null) {
2159                 writer.printf("Invalid input event value {%s}, valid values are f1, f2, ..., f10\n",
2160                         eventValue);
2161                 writer.println("Pass -help to see the full list of options");
2162                 return;
2163             }
2164         } else {
2165             inputCode = Integer.parseInt(eventValue);
2166         }
2167         CustomInputEvent event = new CustomInputEvent(inputCode, display, repeatCounter);
2168         mCarInputService.onCustomInputEvent(event);
2169         writer.printf("Succeeded in injecting {%s}\n", event);
2170     }
2171 
2172     private boolean checkVehicleDisplay(int vehicleDisplay, IndentingPrintWriter writer) {
2173         if (vehicleDisplay != VehicleDisplay.MAIN
2174                 && vehicleDisplay != VehicleDisplay.INSTRUMENT_CLUSTER) {
2175             writer.println("Invalid display:" + vehicleDisplay);
2176             showHelp(writer);
2177             return false;
2178         }
2179         return true;
2180     }
2181 
2182     private void getInitialUserInfo(String[] args, IndentingPrintWriter writer) {
2183         if (args.length < 2) {
2184             writer.println("Insufficient number of args");
2185             return;
2186         }
2187 
2188         // Gets the request type
2189         String typeArg = args[1];
2190         int requestType = UserHalHelper.parseInitialUserInfoRequestType(typeArg);
2191 
2192         int timeout = DEFAULT_HAL_TIMEOUT_MS;
2193         for (int i = 2; i < args.length; i++) {
2194             String arg = args[i];
2195             switch (arg) {
2196                 case "--timeout":
2197                     timeout = Integer.parseInt(args[++i]);
2198                     break;
2199                 default:
2200                     writer.println("Invalid option at index " + i + ": " + arg);
2201                     return;
2202 
2203             }
2204         }
2205 
2206         Slogf.d(TAG, "handleGetInitialUserInfo(): type=" + requestType + " (" + typeArg
2207                 + "), timeout=" + timeout);
2208 
2209         CountDownLatch latch = new CountDownLatch(1);
2210         HalCallback<InitialUserInfoResponse> callback = (status, resp) -> {
2211             try {
2212                 Slogf.d(TAG, "GetUserInfoResponse: status=" + status + ", resp=" + resp);
2213                 writer.printf("Call status: %s\n",
2214                         UserHalHelper.halCallbackStatusToString(status));
2215                 if (status != HalCallback.STATUS_OK) {
2216                     return;
2217                 }
2218                 writer.printf("Request id: %d\n", resp.requestId);
2219                 writer.printf("Action: %s\n", DebugUtils.constantToString(
2220                         InitialUserInfoResponseAction.class, resp.action));
2221                 if (!TextUtils.isEmpty(resp.userNameToCreate)) {
2222                     writer.printf("User name: %s\n", resp.userNameToCreate);
2223                 }
2224                 if (resp.userToSwitchOrCreate.userId != UserManagerHelper.USER_NULL) {
2225                     writer.printf("User id: %d\n", resp.userToSwitchOrCreate.userId);
2226                 }
2227                 if (resp.userToSwitchOrCreate.flags != 0) {
2228                     writer.printf("User flags: %s\n",
2229                             UserHalHelper.userFlagsToString(resp.userToSwitchOrCreate.flags));
2230                 }
2231                 if (!TextUtils.isEmpty(resp.userLocales)) {
2232                     writer.printf("User locales: %s\n", resp.userLocales);
2233                 }
2234             } finally {
2235                 latch.countDown();
2236             }
2237         };
2238 
2239         UsersInfo usersInfo = generateUsersInfo();
2240         mHal.getUserHal().getInitialUserInfo(requestType, timeout, usersInfo, callback);
2241         waitForHal(writer, latch, timeout);
2242     }
2243 
2244     private UsersInfo generateUsersInfo() {
2245         UserManager um = mContext.getSystemService(UserManager.class);
2246         UserHandleHelper userHandleHelper = new UserHandleHelper(mContext, um);
2247         return UserHalHelper.newUsersInfo(um, userHandleHelper);
2248     }
2249 
2250     private int getUserHalFlags(@UserIdInt int userId) {
2251         UserManager um = mContext.getSystemService(UserManager.class);
2252         UserHandleHelper userHandleHelper = new UserHandleHelper(mContext, um);
2253         return UserHalHelper.getFlags(userHandleHelper, userId);
2254     }
2255 
2256     private static void waitForHal(IndentingPrintWriter writer, CountDownLatch latch,
2257             int timeoutMs) {
2258         try {
2259             if (!latch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
2260                 writer.printf("HAL didn't respond in %dms\n", timeoutMs);
2261             }
2262         } catch (InterruptedException e) {
2263             Thread.currentThread().interrupt();
2264             writer.println("Interrupted waiting for HAL");
2265         }
2266     }
2267 
2268     private void switchUser(String[] args, IndentingPrintWriter writer) {
2269         if (args.length < 2) {
2270             writer.println("Insufficient number of args");
2271             return;
2272         }
2273 
2274         int targetUserId = Integer.parseInt(args[1]);
2275         int timeout = DEFAULT_HAL_TIMEOUT_MS + DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS;
2276         boolean halOnly = false;
2277         boolean ignoreUxr = false;
2278 
2279         for (int i = 2; i < args.length; i++) {
2280             String arg = args[i];
2281             switch (arg) {
2282                 case "--timeout":
2283                     timeout = Integer.parseInt(args[++i]);
2284                     break;
2285                 case "--hal-only":
2286                     halOnly = true;
2287                     break;
2288                 case "--ignore-uxr":
2289                     ignoreUxr = true;
2290                     break;
2291                 default:
2292                     writer.println("Invalid option at index " + i + ": " + arg);
2293                     return;
2294             }
2295         }
2296 
2297         Slogf.d(TAG, "switchUser(): target=" + targetUserId + ", halOnly=" + halOnly
2298                 + ", timeout=" + timeout);
2299 
2300         if (halOnly) {
2301             CountDownLatch latch = new CountDownLatch(1);
2302             UserHalService userHal = mHal.getUserHal();
2303             UserInfo targetUserInfo = new UserInfo();
2304             targetUserInfo.userId = targetUserId;
2305             targetUserInfo.flags = getUserHalFlags(targetUserId);
2306 
2307             SwitchUserRequest request = UserHalHelper.emptySwitchUserRequest();
2308             request.targetUser = targetUserInfo;
2309             request.usersInfo = generateUsersInfo();
2310 
2311             userHal.switchUser(request, timeout, (status, resp) -> {
2312                 try {
2313                     Slogf.d(TAG, "SwitchUserResponse: status=" + status + ", resp=" + resp);
2314                     writer.printf("Call Status: %s\n",
2315                             UserHalHelper.halCallbackStatusToString(status));
2316                     if (status != HalCallback.STATUS_OK) {
2317                         return;
2318                     }
2319                     writer.printf("Request id: %d\n", resp.requestId);
2320                     writer.printf("Message type: %s\n", DebugUtils.constantToString(
2321                             SwitchUserMessageType.class, resp.messageType));
2322                     writer.printf("Switch Status: %s\n", DebugUtils.constantToString(
2323                             SwitchUserStatus.class, resp.status));
2324                     String errorMessage = resp.errorMessage;
2325                     if (!TextUtils.isEmpty(errorMessage)) {
2326                         writer.printf("Error message: %s", errorMessage);
2327                     }
2328                     // If HAL returned OK, make a "post-switch" call to the HAL indicating an
2329                     // Android error. This is to "rollback" the HAL switch.
2330                     if (status == HalCallback.STATUS_OK
2331                             && resp.status == SwitchUserStatus.SUCCESS) {
2332                         userHal.postSwitchResponse(request);
2333                     }
2334                 } finally {
2335                     latch.countDown();
2336                 }
2337             });
2338             waitForHal(writer, latch, timeout);
2339             return;
2340         }
2341         CarUserManager carUserManager = getCarUserManager(mContext);
2342 
2343         SyncResultCallback<UserSwitchResult> syncResultCallback = new SyncResultCallback<>();
2344 
2345         if (ignoreUxr) {
2346             carUserManager.switchUserIgnoringUxRestriction(
2347                     new UserSwitchRequest.Builder(UserHandle.of(targetUserId)).build(),
2348                     Runnable::run, syncResultCallback);
2349 
2350         } else {
2351             carUserManager.switchUser(
2352                     new UserSwitchRequest.Builder(UserHandle.of(targetUserId)).build(),
2353                     Runnable::run, syncResultCallback);
2354         }
2355 
2356         try {
2357             showUserSwitchResult(writer, syncResultCallback.get(timeout, TimeUnit.MILLISECONDS));
2358         } catch (TimeoutException e) {
2359             writer.printf("UserSwitchResult: timed out waitng for result");
2360         } catch (InterruptedException e) {
2361             writer.printf("UserSwitchResult: interrupted waitng for result");
2362             Thread.currentThread().interrupt();
2363         }
2364     }
2365 
2366     private void showUserSwitchResult(IndentingPrintWriter writer, UserSwitchResult result) {
2367         if (result == null) return;
2368         writer.printf("UserSwitchResult: status=%s",
2369                 UserSwitchResult.statusToString(result.getStatus()));
2370         String msg = result.getErrorMessage();
2371         if (!TextUtils.isEmpty(msg)) {
2372             writer.printf(", errorMessage=%s", msg);
2373         }
2374         writer.println();
2375     }
2376 
2377     private void logoutUser(String[] args, IndentingPrintWriter writer) {
2378         int timeout = DEFAULT_HAL_TIMEOUT_MS + DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS;
2379 
2380         if (args.length > 1) {
2381             for (int i = 1; i < args.length; i++) {
2382                 String arg = args[i];
2383                 switch (arg) {
2384                     case "--timeout":
2385                         timeout = Integer.parseInt(args[++i]);
2386                         break;
2387                     default:
2388                         writer.println("Invalid option at index " + i + ": " + arg);
2389                         return;
2390                 }
2391             }
2392         }
2393 
2394         Slogf.d(TAG, "logoutUser(): timeout=%d", timeout);
2395 
2396         CarUserManager carUserManager = getCarUserManager(mContext);
2397         AsyncFuture<UserSwitchResult> future = carUserManager.logoutUser();
2398         UserSwitchResult result = waitForFuture(writer, future, timeout);
2399         showUserSwitchResult(writer, result);
2400     }
2401 
2402     private void createUser(String[] args, IndentingPrintWriter writer) {
2403         int timeout = DEFAULT_HAL_TIMEOUT_MS + DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS;
2404         int flags = 0;
2405         boolean isGuest = false;
2406         boolean halOnly = false;
2407         String name = null;
2408 
2409         for (int i = 1; i < args.length; i++) {
2410             String arg = args[i];
2411             switch (arg) {
2412                 case "--timeout":
2413                     timeout = Integer.parseInt(args[++i]);
2414                     break;
2415                 case "--guest":
2416                     isGuest = true;
2417                     break;
2418                 case "--hal-only":
2419                     halOnly = true;
2420                     break;
2421                 case "--flags":
2422                     flags = Integer.parseInt(args[++i]);
2423                     break;
2424                 case "--type":
2425                     // print an error and quit.
2426                     writer.printf("Error: --type is not supported. Use --guest to create a guest.");
2427                     writer.println();
2428                     return;
2429                 default:
2430                     if (name != null) {
2431                         writer.println("Invalid option at index " + i + ": " + arg);
2432                         return;
2433                     }
2434                     name = arg;
2435             }
2436         }
2437 
2438         Slogf.d(TAG, "createUser(): name=" + name
2439                 + ", flags=" + flags
2440                 + ", guest=" + isGuest + ", halOnly=" + halOnly + ", timeout=" + timeout);
2441 
2442         if (!halOnly) {
2443             CarUserManager carUserManager = getCarUserManager(mContext);
2444 
2445             SyncResultCallback<UserCreationResult> syncResultCallback =
2446                     new SyncResultCallback<UserCreationResult>();
2447             UserCreationRequest.Builder builder = new UserCreationRequest.Builder();
2448             if (name != null) {
2449                 builder.setName(name);
2450             }
2451 
2452             if (isGuest) {
2453                 builder.setGuest();
2454             }
2455 
2456             if ((flags & UserManagerHelper.FLAG_ADMIN) == UserManagerHelper.FLAG_ADMIN) {
2457                 builder.setAdmin();
2458             }
2459 
2460             if ((flags & UserManagerHelper.FLAG_EPHEMERAL) == UserManagerHelper.FLAG_EPHEMERAL) {
2461                 builder.setEphemeral();
2462             }
2463 
2464             carUserManager.createUser(builder.build(), Runnable::run, syncResultCallback);
2465 
2466             UserCreationResult result;
2467             try {
2468                 result = syncResultCallback.get(timeout, TimeUnit.MILLISECONDS);
2469             } catch (TimeoutException e) {
2470                 writer.printf("UserCreationResult: Got Timeout Exception - %s", e);
2471                 return;
2472             } catch (InterruptedException e) {
2473                 Thread.currentThread().interrupt();
2474                 writer.printf("UserCreationResult: Got InterruptedException - %s", e);
2475                 return;
2476             }
2477 
2478             if (result == null) return;
2479 
2480             UserHandle user = result.getUser();
2481             // NOTE: must always show the id=%d, as it's used by CTS tests
2482             writer.printf("UserCreationResult: status=%s, user=%s, id=%d",
2483                     UserCreationResult.statusToString(result.getStatus()),
2484                     user == null ? "N/A" : user.toString(),
2485                     user == null ? UserManagerHelper.USER_NULL : user.getIdentifier());
2486             Integer androidFailureStatus = result.getAndroidFailureStatus();
2487             if (androidFailureStatus != null) {
2488                 writer.printf(", androidStatus=%s", DebugUtils.constantToString(UserManager.class,
2489                         "USER_OPERATION_", androidFailureStatus));
2490             }
2491             String msg = result.getErrorMessage();
2492             if (!TextUtils.isEmpty(msg)) {
2493                 writer.printf(", errorMessage=%s", msg);
2494             }
2495             String internalMsg = result.getInternalErrorMessage();
2496             if (!TextUtils.isEmpty(internalMsg)) {
2497                 writer.printf(", internalErrorMessage=%s", internalMsg);
2498             }
2499             writer.println();
2500             return;
2501         }
2502 
2503         CountDownLatch latch = new CountDownLatch(1);
2504         UserHalService userHal = mHal.getUserHal();
2505 
2506         CreateUserRequest request = UserHalHelper.emptyCreateUserRequest();
2507 
2508         UserManager um = mContext.getSystemService(UserManager.class);
2509 
2510         NewUserRequest newUserRequest;
2511         try {
2512             newUserRequest = getCreateUserRequest(name, isGuest, flags);
2513         } catch (Exception e) {
2514             Slogf.e(TAG, e, "Error creating new user request. name: %s isGuest: %b and flags: %s",
2515                     name, isGuest, flags);
2516             writer.println("Failed to create user");
2517             return;
2518         }
2519 
2520         NewUserResponse newUserResponse = um.createUser(newUserRequest);
2521 
2522         if (!newUserResponse.isSuccessful()) {
2523             writer.printf("Failed to create user");
2524             return;
2525         }
2526 
2527         UserHandle newUser = newUserResponse.getUser();
2528 
2529         writer.printf("New user: %s\n", newUser);
2530         Slogf.i(TAG, "Created new user: " + newUser);
2531 
2532         request.newUserInfo.userId = newUser.getIdentifier();
2533         request.newUserInfo.flags = UserHalHelper.convertFlags(new UserHandleHelper(mContext, um),
2534                 newUser);
2535 
2536         request.usersInfo = generateUsersInfo();
2537 
2538         AtomicBoolean halOk = new AtomicBoolean(false);
2539         try {
2540             userHal.createUser(request, timeout, (status, resp) -> {
2541                 Slogf.d(TAG, "CreateUserResponse: status=" + status + ", resp=" + resp);
2542                 writer.printf("Call Status: %s\n",
2543                         UserHalHelper.halCallbackStatusToString(status));
2544                 if (status == HalCallback.STATUS_OK) {
2545                     halOk.set(resp.status == CreateUserStatus.SUCCESS);
2546                     writer.printf("Request id: %d\n", resp.requestId);
2547                     writer.printf("Create Status: %s\n", DebugUtils.constantToString(
2548                             CreateUserStatus.class, resp.status));
2549                     String errorMessage = resp.errorMessage;
2550                     if (!TextUtils.isEmpty(errorMessage)) {
2551                         writer.printf("Error message: %s", errorMessage);
2552                     }
2553                 }
2554                 latch.countDown();
2555             });
2556             waitForHal(writer, latch, timeout);
2557         } catch (RuntimeException e) {
2558             writer.printf("HAL failed: %s\n", e);
2559         } finally {
2560             if (!halOk.get()) {
2561                 writer.printf("Removing user %d due to HAL failure\n", newUser.getIdentifier());
2562                 boolean removed = um.removeUser(newUser);
2563                 writer.printf("User removed: %b\n", removed);
2564             }
2565         }
2566     }
2567 
2568     private NewUserRequest getCreateUserRequest(String name, boolean isGuest, int flags) {
2569         NewUserRequest.Builder builder = new NewUserRequest.Builder().setName(name);
2570         if ((flags & UserManagerHelper.FLAG_ADMIN) == UserManagerHelper.FLAG_ADMIN) {
2571             builder.setAdmin();
2572         }
2573 
2574         if ((flags & UserManagerHelper.FLAG_EPHEMERAL) == UserManagerHelper.FLAG_EPHEMERAL) {
2575             builder.setEphemeral();
2576         }
2577 
2578         if (isGuest) {
2579             builder.setUserType(UserManager.USER_TYPE_FULL_GUEST);
2580         }
2581 
2582         return builder.build();
2583     }
2584 
2585     private void removeUser(String[] args, IndentingPrintWriter writer) {
2586         if (args.length < 2) {
2587             writer.println("Insufficient number of args");
2588             return;
2589         }
2590 
2591         int userId = Integer.parseInt(args[1]);
2592         int timeout = DEFAULT_HAL_TIMEOUT_MS + DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS;
2593         boolean halOnly = false;
2594 
2595         for (int i = 2; i < args.length; i++) {
2596             String arg = args[i];
2597             switch (arg) {
2598                 case "--hal-only":
2599                     halOnly = true;
2600                     break;
2601                 default:
2602                     writer.println("Invalid option at index " + i + ": " + arg);
2603                     return;
2604             }
2605         }
2606 
2607         Slogf.d(TAG, "handleRemoveUser(): User to remove=" + userId + ", halOnly=" + halOnly);
2608 
2609         if (halOnly) {
2610             UserHalService userHal = mHal.getUserHal();
2611             UsersInfo usersInfo = generateUsersInfo();
2612             UserInfo userInfo = new UserInfo();
2613             userInfo.userId = userId;
2614             userInfo.flags = getUserHalFlags(userId);
2615 
2616             RemoveUserRequest request = UserHalHelper.emptyRemoveUserRequest();
2617             request.removedUserInfo = userInfo;
2618             request.usersInfo = usersInfo;
2619 
2620             userHal.removeUser(request);
2621             writer.printf("User removal sent for HAL only.\n");
2622             return;
2623         }
2624 
2625         CarUserManager carUserManager = getCarUserManager(mContext);
2626         SyncResultCallback<UserRemovalResult> syncResultCallback = new SyncResultCallback<>();
2627         carUserManager.removeUser(new UserRemovalRequest.Builder(
2628                 UserHandle.of(userId)).build(), Runnable::run, syncResultCallback);
2629         try {
2630             UserRemovalResult result = syncResultCallback.get(timeout, TimeUnit.MILLISECONDS);
2631             writer.printf("UserRemovalResult: status = %s\n",
2632                     UserRemovalResult.statusToString(result.getStatus()));
2633         } catch (TimeoutException e) {
2634             writer.printf("UserRemovalResult: timed out waitng for result");
2635         } catch (InterruptedException e) {
2636             writer.printf("UserRemovalResult: interrupted waitng for result");
2637             Thread.currentThread().interrupt();
2638         }
2639     }
2640 
2641     private static <T> T waitForFuture(IndentingPrintWriter writer,
2642             AsyncFuture<T> future, int timeoutMs) {
2643         T result = null;
2644         try {
2645             result = future.get(timeoutMs, TimeUnit.MILLISECONDS);
2646             if (result == null) {
2647                 writer.printf("Service didn't respond in %d ms", timeoutMs);
2648             }
2649         } catch (InterruptedException e) {
2650             Thread.currentThread().interrupt();
2651         } catch (ExecutionException | TimeoutException e) {
2652             writer.printf("Exception getting future: %s",  e);
2653         }
2654         return result;
2655     }
2656 
2657     private void getInitialUser(IndentingPrintWriter writer) {
2658         UserHandle user = mCarUserService.getInitialUser();
2659         writer.println(user == null ? NO_INITIAL_USER : user.getIdentifier());
2660     }
2661 
2662     private void getUserAuthAssociation(String[] args, IndentingPrintWriter writer) {
2663         if (args.length < 2) {
2664             writer.println("invalid usage, must pass at least 1 argument");
2665             return;
2666         }
2667 
2668         boolean halOnly = false;
2669         int userId = UserHandle.CURRENT.getIdentifier();
2670 
2671         UserIdentificationGetRequest request = UserHalHelper.emptyUserIdentificationGetRequest();
2672         ArrayList<Integer> associationTypes = new ArrayList<>();
2673         for (int i = 1; i < args.length; i++) {
2674             String arg = args[i];
2675             switch (arg) {
2676                 case "--user":
2677                     try {
2678                         userId = Integer.parseInt(args[++i]);
2679                     } catch (NumberFormatException e) {
2680                         writer.printf("Invalid user id at index %d (from %s): %s\n", i + 1,
2681                                 Arrays.toString(args), arg);
2682                     }
2683                     break;
2684                 case "--hal-only":
2685                     halOnly = true;
2686                     break;
2687                 default:
2688                     int type = parseAuthArg(VALID_USER_AUTH_TYPES, arg);
2689                     if (type == INVALID_USER_AUTH_TYPE_OR_VALUE) {
2690                         writer.printf("Invalid type at index %d (from %s): %s. %s\n", i + 1,
2691                                 Arrays.toString(args), arg, VALID_USER_AUTH_TYPES_HELP);
2692                         return;
2693                     }
2694                     associationTypes.add(type);
2695             }
2696         }
2697         request.associationTypes = toIntArray(associationTypes);
2698         if (userId == UserHandle.CURRENT.getIdentifier()) {
2699             userId = ActivityManager.getCurrentUser();
2700         }
2701         int requestSize = request.associationTypes.length;
2702         if (halOnly) {
2703             request.numberAssociationTypes = requestSize;
2704             request.userInfo.userId = userId;
2705             request.userInfo.flags = getUserHalFlags(userId);
2706 
2707             Slogf.d(TAG, "getUserAuthAssociation(): user=" + userId + ", halOnly=" + halOnly
2708                     + ", request=" + request);
2709             UserIdentificationResponse response = mHal.getUserHal().getUserAssociation(request);
2710             Slogf.d(TAG, "getUserAuthAssociation(): response=" + response);
2711             showResponse(writer, response);
2712             return;
2713         }
2714 
2715         CarUserManager carUserManager = getCarUserManager(writer, userId);
2716         int[] types = new int[requestSize];
2717         for (int i = 0; i < requestSize; i++) {
2718             types[i] = request.associationTypes[i];
2719         }
2720         UserIdentificationAssociationResponse response = carUserManager
2721                 .getUserIdentificationAssociation(types);
2722         showResponse(writer, response);
2723     }
2724 
2725     private CarUserManager getCarUserManager(IndentingPrintWriter writer,
2726             @UserIdInt int userId) {
2727         Context context = getContextForUser(userId);
2728         int actualUserId = Binder.getCallingUid();
2729         if (actualUserId != userId) {
2730             writer.printf("Emulating call for user id %d, but caller's user id is %d, so that's "
2731                     + "what CarUserService will use when calling HAL.\n", userId, actualUserId);
2732         }
2733 
2734         return getCarUserManager(context);
2735     }
2736 
2737     private Context getContextForUser(int userId) {
2738         if (userId == mContext.getUser().getIdentifier()) {
2739             return mContext;
2740         }
2741         return mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
2742     }
2743 
2744     private CarUserManager getCarUserManager(Context context) {
2745         Car car = Car.createCar(context);
2746         CarUserManager carUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
2747         return carUserManager;
2748     }
2749 
2750     private void showResponse(
2751             IndentingPrintWriter writer, UserIdentificationResponse response) {
2752         if (response == null) {
2753             writer.println("null response");
2754             return;
2755         }
2756 
2757         if (!TextUtils.isEmpty(response.errorMessage)) {
2758             writer.printf("Error message: %s\n", response.errorMessage);
2759         }
2760         int numberAssociations = response.associations.length;
2761         writer.printf("%d associations:\n", numberAssociations);
2762         for (int i = 0; i < numberAssociations; i++) {
2763             UserIdentificationAssociation association = response.associations[i];
2764             writer.printf("  %s\n", association);
2765         }
2766     }
2767 
2768     private void showResponse(IndentingPrintWriter writer,
2769             UserIdentificationAssociationResponse response) {
2770         if (response == null) {
2771             writer.println("null response");
2772             return;
2773         }
2774         if (!response.isSuccess()) {
2775             writer.printf("failed response: %s\n", response);
2776             return;
2777         }
2778         String errorMessage = response.getErrorMessage();
2779         if (!TextUtils.isEmpty(errorMessage)) {
2780             writer.printf("Error message: %s\n", errorMessage);
2781         }
2782         int[] values = response.getValues();
2783         if (values == null) {
2784             writer.printf("no associations on %s\n", response);
2785             return;
2786         }
2787         writer.printf("%d associations:\n", values.length);
2788         for (int i = 0; i < values.length; i++) {
2789             writer.printf("  %s\n", DebugUtils.constantToString(
2790                     UserIdentificationAssociationValue.class, values[i]));
2791         }
2792     }
2793 
2794     private void setUserAuthAssociation(String[] args, IndentingPrintWriter writer) {
2795         if (args.length < 3) {
2796             writer.println("invalid usage, must pass at least 4 arguments");
2797             return;
2798         }
2799 
2800         boolean halOnly = false;
2801         int timeout = DEFAULT_HAL_TIMEOUT_MS;
2802         int userId = UserHandle.CURRENT.getIdentifier();
2803 
2804         UserIdentificationSetRequest request = UserHalHelper.emptyUserIdentificationSetRequest();
2805         ArrayList<UserIdentificationSetAssociation> associations = new ArrayList<>();
2806         for (int i = 1; i < args.length; i++) {
2807             String arg = args[i];
2808             switch (arg) {
2809                 case "--user":
2810                     try {
2811                         userId = Integer.parseInt(args[++i]);
2812                     } catch (NumberFormatException e) {
2813                         writer.printf("Invalid user id at index %d (from %s): %s\n", i + 1,
2814                                 Arrays.toString(args), arg);
2815                     }
2816                     break;
2817                 case "--hal-only":
2818                     halOnly = true;
2819                     break;
2820                 case "--timeout":
2821                     timeout = Integer.parseInt(args[++i]);
2822                     break;
2823                 default:
2824                     UserIdentificationSetAssociation association =
2825                             new UserIdentificationSetAssociation();
2826                     association.type = parseAuthArg(VALID_USER_AUTH_TYPES, arg);
2827                     if (association.type == INVALID_USER_AUTH_TYPE_OR_VALUE) {
2828                         writer.printf("Invalid type at index %d (from %s): %s. %s\n", i + 1,
2829                                 Arrays.toString(args), arg, VALID_USER_AUTH_TYPES_HELP);
2830                         return;
2831                     }
2832                     association.value = parseAuthArg(VALID_USER_AUTH_SET_VALUES, args[++i]);
2833                     if (association.value == INVALID_USER_AUTH_TYPE_OR_VALUE) {
2834                         writer.printf("Invalid value at index %d (from %s): %s. %s\n", i + 1,
2835                                 Arrays.toString(args), arg, VALID_USER_AUTH_SET_VALUES_HELP);
2836                         return;
2837                     }
2838                     associations.add(association);
2839             }
2840         }
2841         int requestSize = associations.size();
2842         request.associations = associations.toArray(
2843                 new UserIdentificationSetAssociation[requestSize]);
2844 
2845         if (userId == UserHandle.CURRENT.getIdentifier()) {
2846             userId = ActivityManager.getCurrentUser();
2847         }
2848         if (halOnly) {
2849             request.numberAssociations = requestSize;
2850             request.userInfo.userId = userId;
2851             request.userInfo.flags = getUserHalFlags(userId);
2852 
2853             Slogf.d(TAG, "setUserAuthAssociation(): user=" + userId + ", halOnly=" + halOnly
2854                     + ", request=" + request);
2855             CountDownLatch latch = new CountDownLatch(1);
2856             mHal.getUserHal().setUserAssociation(timeout, request, (status, response) -> {
2857                 Slogf.d(TAG, "setUserAuthAssociation(): response=" + response);
2858                 try {
2859                     showResponse(writer, response);
2860                 } finally {
2861                     latch.countDown();
2862                 }
2863             });
2864             waitForHal(writer, latch, timeout);
2865             return;
2866         }
2867         CarUserManager carUserManager = getCarUserManager(writer, userId);
2868         int[] types = new int[requestSize];
2869         int[] values = new int[requestSize];
2870         for (int i = 0; i < requestSize; i++) {
2871             UserIdentificationSetAssociation association = request.associations[i];
2872             types[i] = association.type;
2873             values[i] = association.value;
2874         }
2875         AsyncFuture<UserIdentificationAssociationResponse> future = carUserManager
2876                 .setUserIdentificationAssociation(types, values);
2877         UserIdentificationAssociationResponse response = waitForFuture(writer, future, timeout);
2878         if (response != null) {
2879             showResponse(writer, response);
2880         }
2881     }
2882 
2883     private static int parseAuthArg(SparseArray<String> types, String type) {
2884         for (int i = 0; i < types.size(); i++) {
2885             if (types.valueAt(i).equals(type)) {
2886                 return types.keyAt(i);
2887             }
2888         }
2889         return INVALID_USER_AUTH_TYPE_OR_VALUE;
2890     }
2891 
2892     private void forceDayNightMode(String arg, IndentingPrintWriter writer) {
2893         int mode;
2894         switch (arg) {
2895             case PARAM_DAY_MODE:
2896                 mode = CarNightService.FORCED_DAY_MODE;
2897                 break;
2898             case PARAM_NIGHT_MODE:
2899                 mode = CarNightService.FORCED_NIGHT_MODE;
2900                 break;
2901             case PARAM_SENSOR_MODE:
2902                 mode = CarNightService.FORCED_SENSOR_MODE;
2903                 break;
2904             default:
2905                 writer.printf("Unknown value: %s. Valid argument: %s|%s|%s\n",
2906                         arg, PARAM_DAY_MODE, PARAM_NIGHT_MODE, PARAM_SENSOR_MODE);
2907                 return;
2908         }
2909         if (Flags.carNightGlobalSetting()) {
2910             Settings.Global.putInt(mContext.getContentResolver(), FORCED_DAY_NIGHT_MODE, mode);
2911             writer.println("DayNightMode changed to: " + arg);
2912         } else {
2913             int current = mCarNightService.forceDayNightMode(mode);
2914             String currentMode = null;
2915             switch (current) {
2916                 case UiModeManager.MODE_NIGHT_AUTO:
2917                     currentMode = PARAM_SENSOR_MODE;
2918                     break;
2919                 case UiModeManager.MODE_NIGHT_YES:
2920                     currentMode = PARAM_NIGHT_MODE;
2921                     break;
2922                 case UiModeManager.MODE_NIGHT_NO:
2923                     currentMode = PARAM_DAY_MODE;
2924                     break;
2925                 default:
2926                     break;
2927             }
2928             writer.println("DayNightMode changed to: " + currentMode);
2929         }
2930     }
2931 
2932     private void runSuspendCommand(String[] args, IndentingPrintWriter writer) {
2933         // args[0] is always either COMMAND_SUSPEND or COMMAND_HIBERNE.
2934         String command = args[0];
2935         boolean isHibernation = Objects.equals(command, COMMAND_HIBERNATE);
2936         // Default is --auto, so simulate is decided based on device capability.
2937         boolean simulate = !mCarPowerManagementService.isSuspendAvailable(isHibernation);
2938         boolean modeSet = false;
2939         boolean skipGarageMode = false;
2940         boolean freeMemory = false;
2941         int resumeDelay = CarPowerManagementService.NO_WAKEUP_BY_TIMER;
2942         int cancelDelay = CarPowerManagementService.NO_WAKEUP_BY_TIMER;
2943         int index = 1;
2944         while (index < args.length) {
2945             switch (args[index]) {
2946                 case PARAM_SIMULATE:
2947                     if (modeSet) {
2948                         writer.printf("Invalid command syntax.\nUsage: %s\n",
2949                                 getSuspendCommandUsage(command));
2950                         return;
2951                     }
2952                     simulate = true;
2953                     modeSet = true;
2954                     break;
2955                 case PARAM_AUTO:
2956                     if (modeSet) {
2957                         writer.printf("Invalid command syntax.\nUsage: %s\n",
2958                                 getSuspendCommandUsage(command));
2959                         return;
2960                     }
2961                     simulate = !mCarPowerManagementService.isSuspendAvailable(isHibernation);
2962                     modeSet = true;
2963                     break;
2964                 case PARAM_REAL:
2965                     if (modeSet) {
2966                         writer.printf("Invalid command syntax.\nUsage: %s\n",
2967                                 getSuspendCommandUsage(command));
2968                         return;
2969                     }
2970                     simulate = false;
2971                     modeSet = true;
2972                     break;
2973                 case PARAM_SKIP_GARAGEMODE:
2974                     skipGarageMode = true;
2975                     break;
2976                 case PARAM_WAKEUP_AFTER:
2977                     index++;
2978                     if (index >= args.length) {
2979                         writer.printf("Invalid command syntax.\nUsage: %s\n",
2980                                 getSuspendCommandUsage(command));
2981                         return;
2982                     }
2983                     resumeDelay = Integer.parseInt(args[index]);
2984                     break;
2985                 case PARAM_CANCEL_AFTER:
2986                     index++;
2987                     if (index >= args.length) {
2988                         writer.printf("Invalid command syntax.\nUsage: %s\n",
2989                                 getSuspendCommandUsage(command));
2990                         return;
2991                     }
2992                     cancelDelay = Integer.parseInt(args[index]);
2993                     break;
2994                 case PARAM_FREE_MEMORY:
2995                     freeMemory = true;
2996                     break;
2997                 default:
2998                     writer.printf("Invalid command syntax.\nUsage: %s\n",
2999                             getSuspendCommandUsage(command));
3000                     return;
3001             }
3002             index++;
3003         }
3004         if ((cancelDelay >= 0 || resumeDelay >= 0) && !simulate) {
3005             writer.printf("Wake up and cancel by timer is available only with simulated suspend."
3006                     + "\n");
3007             return;
3008         }
3009 
3010         if (cancelDelay >= 0 && resumeDelay >= 0 && simulate) {
3011             writer.printf("Cancel and resume cannot be set at the same time.\n");
3012             return;
3013         }
3014 
3015         if (freeMemory && !simulate) {
3016             writer.printf("Free memory can be used only with simulated hibernation.\n");
3017             return;
3018         }
3019 
3020         String suspendType = isHibernation ? "disk" : "RAM";
3021         if (simulate) {
3022             try {
3023                 writer.printf("Suspend: simulating suspend-to-%s.\n", suspendType);
3024                 if (Flags.carPowerCancelShellCommand()) {
3025                     mCarPowerManagementService.simulateSuspendAndMaybeReboot(
3026                             isHibernation ? PowerHalService.PowerState.SHUTDOWN_TYPE_HIBERNATION
3027                                     : PowerHalService.PowerState.SHUTDOWN_TYPE_DEEP_SLEEP,
3028                             /* shouldReboot= */ false, skipGarageMode, resumeDelay, cancelDelay,
3029                             freeMemory);
3030                 } else {
3031                     mCarPowerManagementService.simulateSuspendAndMaybeReboot(
3032                             isHibernation ? PowerHalService.PowerState.SHUTDOWN_TYPE_HIBERNATION
3033                                     : PowerHalService.PowerState.SHUTDOWN_TYPE_DEEP_SLEEP,
3034                             /* shouldReboot= */ false, skipGarageMode, resumeDelay, freeMemory);
3035                 }
3036             } catch (Exception e) {
3037                 writer.printf("Simulating suspend-to-%s failed: %s\n", suspendType, e.getMessage());
3038             }
3039         } else {
3040             try {
3041                 mCarPowerManagementService.suspendFromCommand(isHibernation, skipGarageMode);
3042             } catch (Exception e) {
3043                 writer.printf("Suspend to %s failed: %s.\n", suspendType, e.getMessage());
3044             }
3045         }
3046     }
3047 
3048     private void forceGarageMode(String arg, IndentingPrintWriter writer) {
3049         switch (arg) {
3050             case PARAM_ON_MODE:
3051                 mSystemInterface.setAllDisplayState(false);
3052                 mGarageModeService.forceStartGarageMode();
3053                 writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
3054                 break;
3055             case PARAM_OFF_MODE:
3056                 mSystemInterface.setAllDisplayState(true);
3057                 mGarageModeService.stopAndResetGarageMode();
3058                 writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
3059                 break;
3060             case PARAM_QUERY_MODE:
3061                 mGarageModeService.dump(writer);
3062                 break;
3063             case PARAM_REBOOT_AFTER_GARAGEMODE:
3064                 writer.printf("\"cmd car_service garagemode reboot\" is deprecated. Use "
3065                         + "\"cmd car_service power-off --reboot\" next time");
3066                 try {
3067                     mCarPowerManagementService.powerOffFromCommand(/*skipGarageMode= */ false,
3068                             /* reboot= */ true);
3069                     writer.println("Entering Garage Mode. Will reboot when it completes.");
3070                 } catch (IllegalStateException e) {
3071                     writer.printf("Entering Garage Mode failed: %s\n", e.getMessage());
3072                 }
3073                 break;
3074             default:
3075                 writer.printf("Unknown value: %s. Valid argument: %s|%s|%s|%s\n",
3076                         arg, PARAM_ON_MODE, PARAM_OFF_MODE, PARAM_QUERY_MODE,
3077                         PARAM_REBOOT_AFTER_GARAGEMODE);
3078         }
3079     }
3080 
3081     private void runSilentCommand(String arg, IndentingPrintWriter writer) {
3082         switch (arg) {
3083             case SILENT_MODE_FORCED_SILENT:
3084                 writer.println("Forcing silent mode to silent");
3085                 mCarPowerManagementService.setSilentMode(SILENT_MODE_FORCED_SILENT);
3086                 break;
3087             case SILENT_MODE_FORCED_NON_SILENT:
3088                 writer.println("Forcing silent mode to non-silent");
3089                 mCarPowerManagementService.setSilentMode(SILENT_MODE_FORCED_NON_SILENT);
3090                 break;
3091             case SILENT_MODE_NON_FORCED:
3092                 writer.println("Not forcing silent mode");
3093                 mCarPowerManagementService.setSilentMode(SILENT_MODE_NON_FORCED);
3094                 break;
3095             case PARAM_QUERY_MODE:
3096                 mCarPowerManagementService.dumpSilentMode(writer);
3097                 break;
3098             default:
3099                 writer.printf("Unknown value: %s. Valid argument: %s|%s|%s|%s\n", arg,
3100                         SILENT_MODE_FORCED_SILENT, SILENT_MODE_FORCED_NON_SILENT,
3101                         SILENT_MODE_NON_FORCED, PARAM_QUERY_MODE);
3102         }
3103     }
3104 
3105     private void emulateDrivingState(String[] args, IndentingPrintWriter writer) {
3106         if (args.length != 2) {
3107             writer.println("invalid usage, must pass driving state");
3108             return;
3109         }
3110         String mode = args[1];
3111         switch (mode) {
3112             case DRIVING_STATE_DRIVE:
3113                 emulateDrive();
3114                 break;
3115             case DRIVING_STATE_PARK:
3116                 emulatePark();
3117                 break;
3118             case DRIVING_STATE_REVERSE:
3119                 emulateReverse();
3120                 break;
3121             case DRIVING_STATE_NEUTRAL:
3122                 emulateNeutral();
3123                 break;
3124             default:
3125                 writer.printf("invalid driving mode %s; must be %s or %s\n", mode,
3126                         DRIVING_STATE_DRIVE, DRIVING_STATE_PARK);
3127         }
3128     }
3129 
3130     /**
3131      * Emulates driving mode. Called by
3132      * {@code adb shell cmd car_service emulate-driving-state drive}.
3133      */
3134     private void emulateDrive() {
3135         Slogf.i(TAG, "Emulating driving mode (speed=80mph, gear=8)");
3136         mHal.injectVhalEvent(VehiclePropertyIds.PERF_VEHICLE_SPEED,
3137                 /* areaId= */ 0, /* value= */ "80", /* delayTimeSeconds= */ 2000);
3138         mHal.injectVhalEvent(VehiclePropertyIds.GEAR_SELECTION,
3139                 /* areaId= */ 0, Integer.toString(VehicleGear.GEAR_8), /* delayTimeSeconds= */ 0);
3140         mHal.injectVhalEvent(VehiclePropertyIds.PARKING_BRAKE_ON,
3141                 /* areaId= */ 0, /* value= */ "false", /* delayTimeSeconds= */ 0);
3142     }
3143 
3144     /**
3145      * Emulates reverse driving mode. Called by
3146      * {@code adb shell cmd car_service emulate-driving-state reverse}.
3147      */
3148     private void emulateReverse() {
3149         Slogf.i(TAG, "Emulating reverse driving mode (speed=5mph)");
3150         mHal.injectVhalEvent(VehiclePropertyIds.PERF_VEHICLE_SPEED,
3151                 /* areaId= */ 0, /* value= */ "5", /* delayTimeSeconds= */ 2000);
3152         mHal.injectVhalEvent(VehiclePropertyIds.GEAR_SELECTION,
3153                 /* areaId= */ 0, Integer.toString(VehicleGear.GEAR_REVERSE),
3154                 /* delayTimeSeconds= */ 0);
3155         mHal.injectVhalEvent(VehiclePropertyIds.PARKING_BRAKE_ON,
3156                 /* areaId= */ 0, /* value= */ "false", /* delayTimeSeconds= */ 0);
3157     }
3158 
3159     /**
3160      * Emulates parking mode. Called by
3161      * {@code adb shell cmd car_service emulate-driving-state park}.
3162      */
3163     private void emulatePark() {
3164         Slogf.i(TAG, "Emulating parking mode");
3165         mHal.injectVhalEvent(VehiclePropertyIds.PERF_VEHICLE_SPEED,
3166                 /* areaId= */ 0, /* value= */ "0", /* delayTimeSeconds= */ 0);
3167         mHal.injectVhalEvent(VehiclePropertyIds.GEAR_SELECTION,
3168                 /* areaId= */ 0, Integer.toString(VehicleGear.GEAR_PARK),
3169                 /* delayTimeSeconds= */ 0);
3170     }
3171 
3172     /**
3173      * Emulates neutral driving state. Called by
3174      * {@code adb shell cmd car_service emulate-driving-state neutral}.
3175      */
3176     private void emulateNeutral() {
3177         Slogf.i(TAG, "Emulating neutral driving mode");
3178         mHal.injectVhalEvent(VehiclePropertyIds.PERF_VEHICLE_SPEED,
3179                 /* areaId= */ 0, /* value= */ "0", /* delayTimeSeconds= */ 0);
3180         mHal.injectVhalEvent(VehiclePropertyIds.GEAR_SELECTION,
3181                 /* areaId= */ 0, Integer.toString(VehicleGear.GEAR_NEUTRAL),
3182                 /* delayTimeSeconds= */ 0);
3183         mHal.injectVhalEvent(VehiclePropertyIds.PARKING_BRAKE_ON,
3184                 /* areaId= */ 0, /* value= */ "true", /* delayTimeSeconds= */ 0);
3185     }
3186 
3187     private int definePowerPolicy(String[] args, IndentingPrintWriter writer) {
3188         boolean result = mCarPowerManagementService.definePowerPolicyFromCommand(args, writer);
3189         if (result) return RESULT_OK;
3190         writer.printf("\nUsage: cmd car_service %s <POLICY_ID> [--enable COMP1,COMP2,...] "
3191                 + "[--disable COMP1,COMP2,...]\n", COMMAND_DEFINE_POWER_POLICY);
3192         return RESULT_ERROR;
3193     }
3194 
3195     private int applyPowerPolicy(String[] args, IndentingPrintWriter writer) {
3196         boolean result = mCarPowerManagementService.applyPowerPolicyFromCommand(args, writer);
3197         if (result) return RESULT_OK;
3198         writer.printf("\nUsage: cmd car_service %s <POLICY_ID>\n", COMMAND_APPLY_POWER_POLICY);
3199         return RESULT_ERROR;
3200     }
3201 
3202     private int definePowerPolicyGroup(String[] args, IndentingPrintWriter writer) {
3203         boolean result = mCarPowerManagementService.definePowerPolicyGroupFromCommand(args, writer);
3204         if (result) return RESULT_OK;
3205         writer.printf("\nUsage: cmd car_service %s <POLICY_GROUP_ID> [%s:<POLICY_ID>] "
3206                         + "[%s:<POLICY_ID>]\n", COMMAND_DEFINE_POWER_POLICY_GROUP,
3207                 POWER_STATE_WAIT_FOR_VHAL, POWER_STATE_ON);
3208         return RESULT_ERROR;
3209     }
3210 
3211     private int setPowerPolicyGroup(String[] args, IndentingPrintWriter writer) {
3212         boolean result = mCarPowerManagementService.setPowerPolicyGroupFromCommand(args, writer);
3213         if (result) return RESULT_OK;
3214         writer.printf("\nUsage: cmd car_service %s <POLICY_GROUP_ID>\n",
3215                 COMMAND_SET_POWER_POLICY_GROUP);
3216         return RESULT_ERROR;
3217     }
3218 
3219     private int applyCtsVerifierPowerPolicy(String policyId, String ops, String cmdName,
3220             IndentingPrintWriter writer) {
3221         String[] defArgs = {"define-power-policy", policyId, ops, "WIFI,BLUETOOTH,LOCATION"};
3222         mCarPowerManagementService.definePowerPolicyFromCommand(defArgs, writer);
3223 
3224         String[] appArgs = {"apply-power-policy", policyId};
3225         boolean result = mCarPowerManagementService.applyPowerPolicyFromCommand(appArgs, writer);
3226         if (result) return RESULT_OK;
3227 
3228         writer.printf("\nUsage: cmd car_service %s\n", cmdName);
3229         return RESULT_ERROR;
3230     }
3231 
3232     private int applyCtsVerifierPowerOffPolicy(String[] unusedArgs, IndentingPrintWriter writer) {
3233         return applyCtsVerifierPowerPolicy("cts_verifier_off", "--disable",
3234                 COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY, writer);
3235     }
3236 
3237     private int applyCtsVerifierPowerOnPolicy(String[] unusedArgs, IndentingPrintWriter writer) {
3238         return applyCtsVerifierPowerPolicy("cts_verifier_on", "--enable",
3239                 COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY, writer);
3240     }
3241 
3242     private void powerOff(String[] args, IndentingPrintWriter writer) {
3243         boolean skipGarageMode = false;
3244         boolean reboot = false;
3245         int index = 1;
3246         while (index < args.length) {
3247             switch (args[index]) {
3248                 case PARAM_SKIP_GARAGEMODE:
3249                     skipGarageMode = true;
3250                     break;
3251                 case PARAM_REBOOT:
3252                     reboot = true;
3253                     break;
3254                 default:
3255                     writer.printf("Invalid usage: %s [%s] [%s]\n", COMMAND_POWER_OFF,
3256                             PARAM_SKIP_GARAGEMODE, PARAM_REBOOT);
3257                     return;
3258             }
3259             index++;
3260         }
3261         mCarPowerManagementService.powerOffFromCommand(skipGarageMode, reboot);
3262     }
3263 
3264     /**
3265      * Get config for VHAL property
3266      *
3267      * @param args   the command line arguments to parse for VHAL property details
3268      * @param writer IndentingPrintWriter
3269      */
3270     private void getCarPropertyConfig(String[] args, IndentingPrintWriter writer) {
3271         String propertyIdString = args.length < 2 ? PARAM_ALL_PROPERTIES_OR_AREA_IDS : args[1];
3272         mHal.dumpPropertyConfigs(writer, decodePropertyId(propertyIdString));
3273     }
3274 
3275     /**
3276      * Get current value for VHAL property
3277      *
3278      * @param args   the command line arguments to parse for VHAL property details
3279      * @param writer IndentingPrintWriter
3280      */
3281     private void getPropertyValue(String[] args, IndentingPrintWriter writer) {
3282         String propertyIdString =
3283                 args.length < 2 ? PARAM_ALL_PROPERTIES_OR_AREA_IDS : args[1];
3284         String areaIdString = args.length < 3 ? PARAM_ALL_PROPERTIES_OR_AREA_IDS : args[2];
3285         mHal.dumpPropertyValueByCommand(writer, decodePropertyId(propertyIdString),
3286                 decodeAreaId(areaIdString));
3287     }
3288     /**
3289      * Inject a fake VHAL event
3290      *
3291      * @param args   the command line arguments to parse for VHAL event details
3292      * @param writer IndentingPrintWriter
3293      */
3294     private void injectVhalEvent(String[] args, IndentingPrintWriter writer) {
3295         int argNum = args.length;
3296         if (argNum < 3 || argNum > 6) {
3297             showInvalidArguments(writer);
3298             return;
3299         }
3300         int propertyId = decodePropertyId(args[1]);
3301         String delayTimeSeconds = Objects.equals(args[argNum - 2], "-t") ? args[argNum - 1] : "0";
3302         int areaId;
3303         String value;
3304         if (argNum == 4 || argNum == 6) {
3305             areaId = decodeAreaId(args[2]);
3306             value = args[3];
3307         } else {
3308             // area ID is not specified, assume global area ID
3309             if (!isPropertyAreaTypeGlobal(propertyId)) {
3310                 writer.println("Property " + toPropertyIdString(propertyId)
3311                         + " is not a global area type property. The area ID must be specified. "
3312                         + "Skipping injection.");
3313                 return;
3314             }
3315             areaId = 0;
3316             value = args[2];
3317         }
3318         String debugOutput = "Injecting VHAL event: property=" + toPropertyIdString(propertyId)
3319                 + ", areaId=" + toAreaIdString(propertyId, areaId) + ", value=" + value + (
3320                 TextUtils.isEmpty(delayTimeSeconds) ? ""
3321                         : ", delayTimeSeconds=" + delayTimeSeconds);
3322         Slogf.i(TAG, debugOutput);
3323         writer.println(debugOutput);
3324         mHal.injectVhalEvent(propertyId, areaId, value, Integer.decode(delayTimeSeconds));
3325     }
3326 
3327     /**
3328      * Inject a fake VHAL error error event
3329      *
3330      * @param args   the command line arguments to parse for error event details
3331      * @param writer IndentingPrintWriter
3332      */
3333     private void injectErrorEvent(String[] args, IndentingPrintWriter writer) {
3334         if (args.length != 4) {
3335             showInvalidArguments(writer);
3336             return;
3337         }
3338         int propertyId = decodePropertyId(args[1]);
3339         int areaId = decodeAreaId(args[2]);
3340         int errorCode = Integer.decode(args[3]);
3341         Slogf.i(TAG,
3342                 "Injecting VHAL error event: property=" + toPropertyIdString(
3343                         propertyId) + ", areaId=" + toAreaIdString(propertyId, areaId)
3344                         + ", errorCode=" + errorCode);
3345         VehiclePropError vehiclePropError = new VehiclePropError();
3346         vehiclePropError.propId = propertyId;
3347         vehiclePropError.areaId = areaId;
3348         vehiclePropError.errorCode = errorCode;
3349         mHal.onPropertySetError(new ArrayList<VehiclePropError>(List.of(vehiclePropError)));
3350     }
3351 
3352     // Inject continuous vhal events.
3353     private void injectContinuousEvents(String[] args, IndentingPrintWriter writer) {
3354         if (args.length < 3 || args.length > 8) {
3355             showInvalidArguments(writer);
3356             return;
3357         }
3358         String areaId = PARAM_VEHICLE_PROPERTY_GLOBAL_AREA_ID;
3359         String sampleRate = PARAM_INJECT_EVENT_DEFAULT_RATE;
3360         String durationTime = PARAM_INJECT_EVENT_DEFAULT_DURATION;
3361         String propId = args[1];
3362         String data = args[2];
3363         // scan input
3364         for (int i = 3; i < args.length - 1; i++) {
3365             switch (args[i]) {
3366                 case "-d":
3367                     durationTime = args[++i];
3368                     break;
3369                 case "-z" :
3370                     areaId = args[++i];
3371                     break;
3372                 case "-s" :
3373                     sampleRate = args[++i];
3374                     break;
3375                 default:
3376                     writer.printf("%s is an invalid flag.\n", args[i]);
3377                     showHelp(writer);
3378                     return;
3379             }
3380         }
3381         try {
3382             float sampleRateFloat = Float.parseFloat(sampleRate);
3383             if (sampleRateFloat <= 0) {
3384                 writer.printf("SampleRate: %s is an invalid value. "
3385                         + "SampleRate must be greater than 0.\n", sampleRate);
3386                 showHelp(writer);
3387                 return;
3388             }
3389             mHal.injectContinuousVhalEvent(Integer.decode(propId),
3390                     Integer.decode(areaId), data,
3391                     sampleRateFloat, Long.parseLong(durationTime));
3392         } catch (NumberFormatException e) {
3393             writer.printf("Invalid arguments: %s\n", e);
3394             showHelp(writer);
3395         }
3396 
3397     }
3398 
3399     private void setPropertyValue(String[] args, IndentingPrintWriter writer) {
3400         if (args.length != 4) {
3401             writer.println("Invalid command syntax:");
3402             writer.printf("Usage: %s\n", getSetPropertyValueUsage());
3403             return;
3404         }
3405         int propertyId = decodePropertyId(args[1]);
3406         int areaId = decodeAreaId(args[2]);
3407         String value = args[3];
3408         Slogf.i(TAG, "Setting vehicle property ID= %s, areaId= %s, value= %s",
3409                 toPropertyIdString(propertyId), toAreaIdString(propertyId, areaId), value);
3410         if (areaId == 0 && !isPropertyAreaTypeGlobal(propertyId)) {
3411             writer.printf("Property area type is inconsistent with given area ID: %s\n",
3412                     toAreaIdString(propertyId, areaId));
3413             return;
3414         }
3415         try {
3416             mHal.setPropertyFromCommand(propertyId, areaId, value, writer);
3417             writer.printf("Property %s area ID %s is set to %s successfully\n",
3418                     toPropertyIdString(propertyId), toAreaIdString(propertyId, areaId), value);
3419         } catch (Exception e) {
3420             writer.printf("Cannot set a property: %s\n", e);
3421         }
3422     }
3423 
3424     private static String getSetPropertyValueUsage() {
3425         return COMMAND_SET_PROPERTY_VALUE
3426                 + " <property name in SCREAMING_SNAKE_CASE or ID in Hex or Decimal> <areaId> "
3427                 + "<data (can be comma-separated)>";
3428     }
3429 
3430     // Set a target camera device for the rearview
3431     private void setRearviewCameraId(String[] args, IndentingPrintWriter writer) {
3432         if (args.length != 2) {
3433             showInvalidArguments(writer);
3434             return;
3435         }
3436 
3437         if (!mCarEvsService.setRearviewCameraIdFromCommand(args[1])) {
3438             writer.println("Failed to set CarEvsService rearview camera device id.");
3439         } else {
3440             writer.printf("CarEvsService is set to use %s.\n", args[1]);
3441         }
3442     }
3443 
3444     private void setCameraId(String[] args, IndentingPrintWriter writer) {
3445         if (args.length != 3) {
3446             showInvalidArguments(writer);
3447             return;
3448         }
3449 
3450         if (!mCarEvsService.setCameraIdFromCommand(args[1], args[2])) {
3451             writer.printf("Failed to set CarEvsService camera device id for %s.", args[1]);
3452         } else {
3453             writer.printf("CarEvsService is set to use %s for %s.\n", args[2], args[1]);
3454         }
3455     }
3456 
3457     private void enableCameraServiceType(String[] args, IndentingPrintWriter writer) {
3458         if (args.length != 3) {
3459             showInvalidArguments(writer);
3460             return;
3461         }
3462 
3463         if (!mCarEvsService.enableServiceTypeFromCommand(args[1], args[2])) {
3464             writer.printf("Failed to enable %s with a camera %s.\n",
3465                     args[1], args[2]);
3466             return;
3467         }
3468 
3469         writer.printf("%s is successfully enabled and set to use a camera %s.\n",
3470                 args[1], args[2]);
3471     }
3472 
3473     private void setDrivingSafetyRegion(String[] args, IndentingPrintWriter writer) {
3474         if (args.length != 1 && args.length != 2) {
3475             showInvalidArguments(writer);
3476             return;
3477         }
3478         String region = args.length == 2 ? args[1] : CarPackageManager.DRIVING_SAFETY_REGION_ALL;
3479         writer.println("Set driving safety region to:" + region);
3480         CarLocalServices.getService(CarPackageManagerService.class).resetDrivingSafetyRegion(
3481                 region);
3482     }
3483 
3484     private void getRearviewCameraId(IndentingPrintWriter writer) {
3485         writer.printf("CarEvsService is using %s for the rearview.\n",
3486                 mCarEvsService.getRearviewCameraIdFromCommand());
3487     }
3488 
3489     private void getCameraId(String[] args, IndentingPrintWriter writer) {
3490         if (args.length != 2) {
3491             showInvalidArguments(writer);
3492             return;
3493         }
3494 
3495         writer.printf("CarEvsService is using %s for %s.\n",
3496                 mCarEvsService.getCameraIdFromCommand(args[1]), args[1]);
3497     }
3498 
3499     private void checkCameraServiceTypeEnabled(String[] args, IndentingPrintWriter writer) {
3500         if (args.length != 2) {
3501             showInvalidArguments(writer);
3502             return;
3503         }
3504 
3505         if (!mCarEvsService.isServiceTypeEnabledFromCommand(args[1])) {
3506             writer.printf("%s is not enabled.\n", args[1]);
3507             return;
3508         }
3509 
3510         String cameraId = mCarEvsService.getCameraIdFromCommand(args[1]);
3511         writer.printf("%s is enabled and set to use %s.\n", args[1], cameraId);
3512     }
3513 
3514     private void controlWatchdogPackageKillableState(String[] args, IndentingPrintWriter writer) {
3515         if (args.length != 3) {
3516             showInvalidArguments(writer);
3517             return;
3518         }
3519         if (!Objects.equals(args[1], "true") && !Objects.equals(args[1], "false")) {
3520             writer.println("Failed to parse killable state argument. "
3521                     + "Valid arguments: killable | not-killable");
3522             return;
3523         }
3524         int currentUserId = ActivityManager.getCurrentUser();
3525         mCarWatchdogService.setKillablePackageAsUser(
3526                 args[2], UserHandle.of(currentUserId), Objects.equals(args[1], "true"));
3527         writer.printf("Set package killable state as '%s' for user '%d' and package '%s'\n",
3528                 Objects.equals(args[1], "true") ? "killable" : "not killable", currentUserId,
3529                 args[2]);
3530     }
3531 
3532     // Set third-party foreground I/O threshold for car watchdog
3533     private void setWatchdogIoThirdPartyForegroundBytes(String[] args,
3534             IndentingPrintWriter writer) {
3535         if (args.length != 2) {
3536             showInvalidArguments(writer);
3537             return;
3538         }
3539         try {
3540             long newForegroundModeBytes = Long.parseLong(args[1]);
3541             ResourceOveruseConfiguration configuration =
3542                     getThirdPartyResourceOveruseConfiguration(
3543                             CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
3544             if (configuration == null) {
3545                 writer.println("Failed to get third-party resource overuse configurations.");
3546                 return;
3547             }
3548             ResourceOveruseConfiguration newConfiguration = setComponentLevelForegroundIoBytes(
3549                     configuration, newForegroundModeBytes);
3550             int result = mCarWatchdogService.setResourceOveruseConfigurations(
3551                     Collections.singletonList(newConfiguration),
3552                     CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
3553             if (result == CarWatchdogManager.RETURN_CODE_SUCCESS) {
3554                 writer.printf(
3555                         "Successfully set third-party I/O overuse foreground threshold. { "
3556                                 + "foregroundModeBytes = %d } \n",
3557                         newForegroundModeBytes);
3558             } else {
3559                 writer.println("Failed to set third-party I/O overuse foreground threshold.");
3560             }
3561         } catch (NumberFormatException e) {
3562             writer.println("The argument provided does not contain a parsable long.");
3563             writer.println("Failed to set third-party I/O overuse foreground threshold.");
3564         } catch (RemoteException e) {
3565             writer.printf("Failed to set third-party I/O overuse foreground threshold: %s",
3566                     e.getMessage());
3567         }
3568     }
3569 
3570     private void getWatchdogIoThirdPartyForegroundBytes(IndentingPrintWriter writer) {
3571         ResourceOveruseConfiguration configuration =
3572                 getThirdPartyResourceOveruseConfiguration(
3573                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
3574         try {
3575             IoOveruseConfiguration ioOveruseConfiguration = Objects.requireNonNull(
3576                     configuration).getIoOveruseConfiguration();
3577             PerStateBytes componentLevelThresholds = Objects.requireNonNull(ioOveruseConfiguration)
3578                     .getComponentLevelThresholds();
3579             long foregroundBytes = Objects.requireNonNull(
3580                     componentLevelThresholds).getForegroundModeBytes();
3581             writer.printf("foregroundModeBytes = %d \n", foregroundBytes);
3582         } catch (NullPointerException e) {
3583             writer.println("Failed to get third-party I/O overuse foreground threshold.");
3584         }
3585     }
3586 
3587     private ResourceOveruseConfiguration getThirdPartyResourceOveruseConfiguration(
3588             int resourceOveruseFlag) {
3589         for (ResourceOveruseConfiguration configuration :
3590                 mCarWatchdogService.getResourceOveruseConfigurations(resourceOveruseFlag)) {
3591             if (configuration.getComponentType()
3592                     == ResourceOveruseConfiguration.COMPONENT_TYPE_THIRD_PARTY) {
3593                 return configuration;
3594             }
3595         }
3596         return null;
3597     }
3598 
3599     private ResourceOveruseConfiguration setComponentLevelForegroundIoBytes(
3600             ResourceOveruseConfiguration configuration, long foregroundModeBytes) {
3601         IoOveruseConfiguration ioOveruseConfiguration = configuration.getIoOveruseConfiguration();
3602         PerStateBytes componentLevelThresholds =
3603                 ioOveruseConfiguration.getComponentLevelThresholds();
3604         return constructResourceOveruseConfigurationBuilder(
3605                 configuration).setIoOveruseConfiguration(
3606                         new IoOveruseConfiguration.Builder(
3607                                 new PerStateBytes(foregroundModeBytes,
3608                                         componentLevelThresholds.getBackgroundModeBytes(),
3609                                         componentLevelThresholds.getGarageModeBytes()),
3610                                 ioOveruseConfiguration.getPackageSpecificThresholds(),
3611                                 ioOveruseConfiguration.getAppCategorySpecificThresholds(),
3612                                 ioOveruseConfiguration.getSystemWideThresholds())
3613                                 .build())
3614                 .build();
3615     }
3616 
3617     private ResourceOveruseConfiguration.Builder constructResourceOveruseConfigurationBuilder(
3618             ResourceOveruseConfiguration configuration) {
3619         return new ResourceOveruseConfiguration.Builder(configuration.getComponentType(),
3620                 configuration.getSafeToKillPackages(),
3621                 configuration.getVendorPackagePrefixes(),
3622                 configuration.getPackagesToAppCategoryTypes())
3623                 .setIoOveruseConfiguration(configuration.getIoOveruseConfiguration());
3624     }
3625 
3626     private void controlWatchdogProcessHealthCheck(String[] args, IndentingPrintWriter writer) {
3627         if (args.length != 2) {
3628             showInvalidArguments(writer);
3629             return;
3630         }
3631         if (!Objects.equals(args[1], "enable") && !Objects.equals(args[1], "disable")) {
3632             writer.println("Failed to parse argument. Valid arguments: enable | disable");
3633             return;
3634         }
3635         mCarWatchdogService.controlProcessHealthCheck(Objects.equals(args[1], "enable"));
3636         writer.printf("Watchdog health checking is now %sd \n", args[1]);
3637     }
3638 
3639     private void performResourceOveruseKill(String[] args, IndentingPrintWriter writer) {
3640         if (args.length != 2 && args.length != 4) {
3641             showInvalidArguments(writer);
3642             return;
3643         }
3644         String packageName = args[1];
3645         int userId;
3646         if (args.length > 2 && Objects.equals(args[2], "--user")) {
3647             try {
3648                 userId = Integer.parseInt(args[3]);
3649             } catch (NumberFormatException e) {
3650                 writer.printf("Invalid user id provided: %s\n", args[3]);
3651                 return;
3652             }
3653         } else {
3654             userId = ActivityManager.getCurrentUser();
3655         }
3656         boolean isKilled = mCarWatchdogService.performResourceOveruseKill(packageName, userId);
3657         if (isKilled) {
3658             writer.printf("Successfully killed package '%s' for user %d\n", packageName, userId);
3659         } else {
3660             writer.printf("Failed to kill package '%s' for user %d\n", packageName, userId);
3661         }
3662     }
3663 
3664     private void printTelemetryHelp(IndentingPrintWriter writer) {
3665         writer.println("A CLI to interact with CarTelemetryService.");
3666         writer.println("\nUSAGE: adb shell cmd car_service telemetry <subcommand> [options]");
3667         writer.println("\n\t-h");
3668         writer.println("\t  Print this help text.");
3669         writer.println("\tadd <name>");
3670         writer.println("\t  Adds MetricsConfig from STDIN. Only a binary proto is supported.");
3671         writer.println("\tremove <name>");
3672         writer.println("\t  Removes metrics config.");
3673         writer.println("\tremove-all");
3674         writer.println("\t  Removes all metrics configs.");
3675         writer.println("\tping-script-executor [published data filepath] [state filepath]");
3676         writer.println("\t  Runs a Lua script from stdin.");
3677         writer.println("\tlist");
3678         writer.println("\t  Lists the active config metrics.");
3679         writer.println("\tget-result --config <name> --result-count <num_reports> --timeout "
3680                 + "<timeout_sec> --print-results");
3681         writer.println("\t  Blocks until an expected <num_reports> number of metrics reports");
3682         writer.println("\t  is available and returns them.");
3683         writer.println("\t  <timeout_sec> specifies the maximum number of seconds that");
3684         writer.println("\t  CLI will block for the expected <num_reports>");
3685         writer.println("\t  number of reports to come in.");
3686         writer.println("\t  Optionally prints contents of every report received");
3687         writer.println("\t  if --print-results option is chosen.");
3688         writer.println("\nEXAMPLES:");
3689         writer.println("\t$ adb shell cmd car_service telemetry add name < config1.protobin");
3690         writer.println("\t\tWhere config1.protobin is a serialized MetricsConfig proto.");
3691         writer.println("\n\t$ adb shell cmd car_service telemetry get-result --config name "
3692                 + "--result-count 1 --timeout 10 --print-results");
3693         writer.println("\t$ adb shell cmd car_service telemetry ping-script-executor "
3694                 + "< example_script.lua");
3695         writer.println("\t$ adb shell cmd car_service telemetry ping-script-executor "
3696                 + "/data/local/tmp/published_data < example_script.lua");
3697         writer.println("\t$ adb shell cmd car_service telemetry ping-script-executor "
3698                 + "/data/local/tmp/bundle /data/local/tmp/bundle2 < example_script.lua");
3699     }
3700 
3701     private void handleTelemetryCommands(String[] args, IndentingPrintWriter writer) {
3702         if (args.length < 2) {
3703             printTelemetryHelp(writer);
3704             return;
3705         }
3706         Car car = Car.createCar(mContext);
3707         CarTelemetryManager carTelemetryManager =
3708                 (CarTelemetryManager) car.getCarManager(Car.CAR_TELEMETRY_SERVICE);
3709         if (carTelemetryManager == null) {
3710             writer.println("telemetry service is not enabled, cannot use CLI");
3711             return;
3712         }
3713         String cmd = args[1];
3714         switch (cmd) {
3715             case "add":
3716                 if (args.length != 3) {
3717                     writer.println("Invalid number of arguments.");
3718                     printTelemetryHelp(writer);
3719                     return;
3720                 }
3721                 try (BufferedInputStream in = new BufferedInputStream(
3722                         new FileInputStream(getInFileDescriptor()));
3723                      ByteArrayOutputStream out = new ByteArrayOutputStream()) {
3724                     FileUtils.copy(in, out);
3725                     CountDownLatch latch = new CountDownLatch(1);
3726                     carTelemetryManager.addMetricsConfig(args[2], out.toByteArray(), Runnable::run,
3727                             (metricsConfigName, statusCode) -> {
3728                                 if (statusCode == STATUS_ADD_METRICS_CONFIG_SUCCEEDED) {
3729                                     writer.printf("MetricsConfig %s is added.\n", args[2]);
3730                                 } else {
3731                                     writer.printf(
3732                                             "Failed to add %s. Status is %d. "
3733                                                     + "Please see logcat for details.\n",
3734                                             args[2],
3735                                             statusCode);
3736                                 }
3737                                 latch.countDown();
3738                             });
3739                     latch.await(TELEMETRY_RESULT_WAIT_TIMEOUT.toSeconds(), TimeUnit.SECONDS);
3740                 } catch (IOException | InterruptedException | NumberFormatException e) {
3741                     writer.println("Failed to read from stdin: " + e);
3742                 }
3743                 break;
3744             case "remove":
3745                 if (args.length != 3) {
3746                     writer.println("Invalid number of arguments.");
3747                     printTelemetryHelp(writer);
3748                     return;
3749                 }
3750                 carTelemetryManager.removeMetricsConfig(args[2]);
3751                 writer.printf("Removing %s... Please see logcat for details.\n", args[2]);
3752                 break;
3753             case "remove-all":
3754                 if (args.length != 2) {
3755                     writer.println("Invalid number of arguments.");
3756                     printTelemetryHelp(writer);
3757                     return;
3758                 }
3759                 carTelemetryManager.removeAllMetricsConfigs();
3760                 writer.printf("Removing all MetricsConfigs... Please see logcat for details.\n");
3761                 break;
3762             case "ping-script-executor":
3763                 if (args.length < 2 || args.length > 4) {
3764                     writer.println("Invalid number of arguments.");
3765                     printTelemetryHelp(writer);
3766                     return;
3767                 }
3768                 PersistableBundle publishedData = new PersistableBundle();
3769                 publishedData.putInt("age", 99);
3770                 publishedData.putStringArray(
3771                         "string_array",
3772                         new String[]{"a", "b", "c", "a", "b", "c", "a", "b", "c"});
3773                 PersistableBundle nestedBundle = new PersistableBundle();
3774                 nestedBundle.putInt("age", 100);
3775                 nestedBundle.putStringArray(
3776                         "string_array",
3777                         new String[]{"q", "w", "e", "r", "t", "y"});
3778                 publishedData.putPersistableBundle("pers_bundle", nestedBundle);
3779                 PersistableBundle savedState = null;
3780                 // Read published data
3781                 if (args.length >= 3) {
3782                     try {
3783                         publishedData = IoUtils.readBundle(new File(args[2]));
3784                     } catch (IOException e) {
3785                         writer.println("Published data path is invalid: " + e);
3786                         return;
3787                     }
3788                 }
3789                 // Read saved state
3790                 if (args.length == 4) {
3791                     try {
3792                         savedState = IoUtils.readBundle(new File(args[3]));
3793                     } catch (IOException e) {
3794                         writer.println("Saved data path is invalid: " + e);
3795                         return;
3796                     }
3797                 }
3798                 try {
3799                     pingScriptExecutor(writer, publishedData, savedState);
3800                 } catch (InterruptedException | RemoteException e) {
3801                     throw new RuntimeException(e);
3802                 }
3803                 break;
3804             case "list":
3805                 writer.println("Active metric configs:");
3806                 mCarTelemetryService.getActiveMetricsConfigDetails().forEach((configDetails) -> {
3807                     writer.printf("- %s\n", configDetails);
3808                 });
3809                 break;
3810             case "get-result":
3811                 if (args.length < 8 || args.length > 9) {
3812                     writer.println("Invalid number of arguments.");
3813                     printTelemetryHelp(writer);
3814                     return;
3815                 }
3816                 String configName = null;
3817                 String expectedResultCount = null;
3818                 String timeout = null;
3819                 boolean printResults = false;
3820                 for (int i = 2; i < args.length; i++) {
3821                     switch (args[i]) {
3822                         case "--config":
3823                             configName = args[++i];
3824                             break;
3825                         case "--result-count":
3826                             expectedResultCount = args[++i];
3827                             break;
3828                         case "--timeout":
3829                             timeout = args[++i];
3830                             break;
3831                         case "--print-results":
3832                             printResults = true;
3833                             break;
3834                         default:
3835                             writer.printf("%s is an invalid argument.\n", args[i]);
3836                             printTelemetryHelp(writer);
3837                             return;
3838                     }
3839                 }
3840                 if (configName == null) {
3841                     writer.printf("--config value was not provided.\n");
3842                     printTelemetryHelp(writer);
3843                     return;
3844                 }
3845                 if (expectedResultCount == null) {
3846                     writer.printf("--result_count value was not provided.\n");
3847                     printTelemetryHelp(writer);
3848                     return;
3849                 }
3850                 if (timeout == null) {
3851                     writer.printf("--timeout value was not provided.\n");
3852                     printTelemetryHelp(writer);
3853                     return;
3854                 }
3855                 CountDownLatch latch = new CountDownLatch(Integer.parseInt(expectedResultCount));
3856                 AtomicLong firstReportReady = new AtomicLong(Long.MIN_VALUE);
3857                 AtomicLong lastReportReady = new AtomicLong(Long.MIN_VALUE);
3858                 AtomicInteger numResultsReceived = new AtomicInteger(0);
3859 
3860                 boolean shouldPrintResults = printResults;
3861                 CarTelemetryManager.MetricsReportCallback callback =
3862                         (metricsConfigName, report, telemetryError, status) -> {
3863                             if (report != null) {
3864                                 // Captures the first time the callback is invoked.
3865                                 firstReportReady.compareAndSet(Long.MIN_VALUE,
3866                                         SystemClock.elapsedRealtime());
3867                                 // The callback can be invoked many times. This variable stores
3868                                 // the time instant when the callback was called most recently.
3869                                 lastReportReady.set(SystemClock.elapsedRealtime());
3870                                 report.size(); // unparcel()'s
3871                                 numResultsReceived.incrementAndGet();
3872                                 if (shouldPrintResults) {
3873                                     writer.println("Report for " + metricsConfigName + ": "
3874                                             + report);
3875                                 }
3876                                 latch.countDown();
3877                             } else if (telemetryError != null) {
3878                                 parseTelemetryError(telemetryError, writer);
3879                             }
3880                         };
3881                 String parsedConfigName = configName;
3882                 carTelemetryManager.clearReportReadyListener();
3883                 Executor executor = Executors.newSingleThreadExecutor();
3884                 carTelemetryManager.setReportReadyListener(executor, metricsConfigName -> {
3885                     if (metricsConfigName.equals(parsedConfigName)) {
3886                         carTelemetryManager.getFinishedReport(metricsConfigName, executor,
3887                                 callback);
3888                     }
3889                 });
3890                 try {
3891                     writer.println("Waiting for the results...");
3892                     writer.flush();
3893                     latch.await(/* timeout =*/Integer.parseInt(timeout), TimeUnit.SECONDS);
3894                     long delta = lastReportReady.get() - firstReportReady.get();
3895                     writer.println(
3896                             "Took " + delta + " millis to produce " + numResultsReceived.get()
3897                                     + " reports");
3898                     writer.println("The first report produced at " + firstReportReady.get()
3899                             + " millis since boot");
3900                     writer.println("The last report produced at " + lastReportReady.get()
3901                             + " millis since boot");
3902                     writer.flush();
3903                 } catch (InterruptedException e) {
3904                     writer.println("Result await error: " + e);
3905                 } finally {
3906                     carTelemetryManager.clearReportReadyListener();
3907                 }
3908                 break;
3909             default:
3910                 printTelemetryHelp(writer);
3911         }
3912     }
3913 
3914     private void pingScriptExecutor(
3915             IndentingPrintWriter writer,
3916             PersistableBundle publishedData,
3917             PersistableBundle savedState)
3918             throws InterruptedException, RemoteException {
3919         writer.println("Sending data to script executor...");
3920         if (mScriptExecutor == null) {
3921             writer.println("[I] No mScriptExecutor, creating a new one");
3922             connectToScriptExecutor(writer);
3923         }
3924         String script;
3925         try (
3926                 BufferedInputStream in = new BufferedInputStream(
3927                         new FileInputStream(getInFileDescriptor()));
3928                 ByteArrayOutputStream out = new ByteArrayOutputStream()) {
3929             FileUtils.copy(in, out);
3930             script = out.toString();
3931         } catch (IOException | NumberFormatException e) {
3932             writer.println("[E] Failed to read from stdin: " + e);
3933             return;
3934         }
3935         writer.println("[I] Running the script: ");
3936         writer.println(script);
3937         writer.flush();
3938 
3939         CountDownLatch resultLatch = new CountDownLatch(1);
3940         IScriptExecutorListener listener =
3941                 new IScriptExecutorListener.Stub() {
3942                     @Override
3943                     public void onScriptFinished(PersistableBundle result) {
3944                         writer.println("Script finished");
3945                         result.size(); // unparcel()'s
3946                         writer.println("result: " + result);
3947                         writer.flush();
3948                         resultLatch.countDown();
3949                     }
3950 
3951                     @Override
3952                     public void onSuccess(PersistableBundle state) {
3953                         writer.println("Script succeeded, saving inter result");
3954                         state.size(); // unparcel()'s
3955                         writer.println("state: " + state);
3956                         writer.flush();
3957                         resultLatch.countDown();
3958                     }
3959 
3960                     @Override
3961                     public void onError(int errorType, String msg, String stack) {
3962                         writer.println("Script error: " + errorType + ": " + msg);
3963                         writer.println("Stack: " + stack);
3964                         writer.flush();
3965                         resultLatch.countDown();
3966                     }
3967 
3968                     @Override
3969                     public void onMetricsReport(
3970                             @NonNull PersistableBundle report,
3971                             @Nullable PersistableBundle stateToPersist) {
3972                         writer.println("Script produced a report without finishing");
3973                         report.size(); // unparcel()'s
3974                         writer.println("report: " + report);
3975                         if (stateToPersist != null) {
3976                             stateToPersist.size(); // unparcel()'s
3977                             writer.println("state to persist: " + stateToPersist);
3978                         }
3979                         writer.flush();
3980                         resultLatch.countDown();
3981                     }
3982                 };
3983         mScriptExecutor.invokeScript(
3984                 script,
3985                 "foo",
3986                 publishedData,
3987                 savedState,
3988                 listener);
3989         writer.println("[I] Waiting for the result");
3990         writer.flush();
3991         resultLatch.await(10, TimeUnit.SECONDS); // seconds
3992         mContext.unbindService(mScriptExecutorConn);
3993     }
3994 
3995     private void connectToScriptExecutor(IndentingPrintWriter writer) throws InterruptedException {
3996         CountDownLatch connectionLatch = new CountDownLatch(1);
3997         mScriptExecutorConn =
3998                 new ServiceConnection() {
3999                     @Override
4000                     public void onServiceConnected(ComponentName name, IBinder service) {
4001                         writer.println("[I] Connected to ScriptExecutor Service");
4002                         writer.flush();
4003                         mScriptExecutor = IScriptExecutor.Stub.asInterface(service);
4004                         connectionLatch.countDown();
4005                     }
4006 
4007                     @Override
4008                     public void onServiceDisconnected(ComponentName name) {
4009                         writer.println("[E] Failed to connect to ScriptExecutor Service");
4010                         writer.flush();
4011                         mScriptExecutor = null;
4012                         connectionLatch.countDown();
4013                     }
4014                 };
4015         Intent intent = new Intent();
4016         intent.setComponent(
4017                 new ComponentName(
4018                         "com.android.car.scriptexecutor",
4019                         "com.android.car.scriptexecutor.ScriptExecutor"));
4020         writer.println("[I] Binding to the script executor");
4021         boolean success =
4022                 mContext.bindServiceAsUser(
4023                         intent,
4024                         mScriptExecutorConn,
4025                         Context.BIND_AUTO_CREATE,
4026                         UserHandle.SYSTEM);
4027         if (success) {
4028             writer.println("[I] Found ScriptExecutor package");
4029             writer.flush();
4030         } else {
4031             writer.println("[E] Failed to bind to ScriptExecutor");
4032             writer.flush();
4033             mScriptExecutor = null;
4034             if (mScriptExecutorConn != null) {
4035                 mContext.unbindService(mScriptExecutorConn);
4036             }
4037             return;
4038         }
4039         writer.println("[I] Waiting for the connection");
4040         connectionLatch.await(5, TimeUnit.SECONDS); // seconds
4041     }
4042 
4043     private void parseTelemetryError(byte[] telemetryError, IndentingPrintWriter writer) {
4044         try {
4045             TelemetryError error = TelemetryError.parseFrom(telemetryError);
4046             writer.println("Error: " + error.getErrorType().name() + ": "
4047                     + error.getMessage());
4048         } catch (IOException e) {
4049             writer.println("Error is received, but parsing error failed: " + e);
4050         }
4051     }
4052 
4053     private void controlComponentEnabledState(String[] args, IndentingPrintWriter writer) {
4054         if (args.length != 3) {
4055             showInvalidArguments(writer);
4056             return;
4057         }
4058 
4059         String packageName = args[2];
4060         int currentUserId = ActivityManager.getCurrentUser();
4061 
4062         if (Objects.equals(args[1], "get")) {
4063             try {
4064                 int curState = PackageManagerHelper
4065                         .getApplicationEnabledSettingForUser(packageName, currentUserId);
4066                 writer.println("Current State: " + getAppEnabledStateName(curState));
4067             } catch (Exception e) {
4068                 writer.printf("%s: getting package enabled state failed with error: %s\n",
4069                         TAG, e.toString());
4070             }
4071             return;
4072         }
4073 
4074         int newState = 0;
4075         switch (args[1]) {
4076             case "default":
4077                 newState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
4078                 break;
4079             case "enable":
4080                 newState = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
4081                 break;
4082             case "disable_until_used":
4083                 newState = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
4084                 break;
4085             default:
4086                 writer.println("unsupported state action: " + args[1]);
4087                 return;
4088         }
4089 
4090         String callingPackageName = mContext.getPackageManager().getNameForUid(Process.myUid());
4091         try {
4092             PackageManagerHelper.setApplicationEnabledSettingForUser(packageName, newState,
4093                     /* EnabledFlag */ 0, currentUserId, callingPackageName);
4094         } catch (Exception e) {
4095             writer.printf("%s: setting package enabled state failed with error: %s\n",
4096                     TAG, e.toString());
4097             return;
4098         }
4099         writer.println("New State: " + getAppEnabledStateName(newState));
4100     }
4101 
4102     private String getAppEnabledStateName(int enabledState) {
4103         String stateName = "COMPONENT_ENABLED_STATE_";
4104         switch (enabledState) {
4105             case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
4106                 stateName += "DEFAULT";
4107                 break;
4108             case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
4109                 stateName += "ENABLED";
4110                 break;
4111             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
4112                 stateName += "DISABLED";
4113                 break;
4114             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
4115                 stateName += "DISABLED_USER";
4116                 break;
4117             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
4118                 stateName += "DISABLED_UNTIL_USED";
4119                 break;
4120             default:
4121                 stateName += "UNSUPPORTED";
4122                 break;
4123         }
4124         return stateName;
4125     }
4126 
4127     private void checkLockIsSecure(String[] args, IndentingPrintWriter writer) {
4128         if ((args.length != 1) && (args.length != 2)) {
4129             showInvalidArguments(writer);
4130         }
4131 
4132         int userId = UserHandle.myUserId();
4133         if (args.length == 2) {
4134             userId = Integer.parseInt(args[1]);
4135         }
4136         writer.println(LockPatternHelper.isSecure(mContext, userId));
4137     }
4138 
4139     private void listVhalProps(IndentingPrintWriter writer) {
4140         // Note: The output here is used in AtsVehicleDeviceTest. DO NOT CHANGE the format without
4141         // updating AtsVehicleDeviceTest.
4142         writer.println("All supported property IDs from Vehicle HAL:");
4143         List<Integer> propIds = new ArrayList<>();
4144         try {
4145             HalPropConfig[] configs = mHal.getAllPropConfigs();
4146             for (int i = 0; i < configs.length; i++) {
4147                 propIds.add(configs[i].getPropId());
4148             }
4149             writer.println(propIds.toString());
4150         } catch (RemoteException | ServiceSpecificException e) {
4151             writer.println("Failed to call getAllPropConfigs, exception: " + e);
4152         }
4153     }
4154 
4155     private void getVhalBackend(IndentingPrintWriter writer) {
4156         // Note: The output here is used in AtsVehicleDeviceTest. DO NOT CHANGE the format without
4157         // updating AtsVehicleDeviceTest.
4158         if (mHal.isAidlVhal()) {
4159             writer.println("Vehicle HAL backend: AIDL");
4160         } else {
4161             writer.println("Vehicle HAL backend: HIDL");
4162         }
4163     }
4164 
4165     private void testEchoReverseBytes(String[] args, IndentingPrintWriter writer) {
4166         // Note: The output here is used in
4167         // AndroidCarApiTest:android.car.apitest.VehicleHalLargeParcelableTest.
4168         // Do not change the output format without updating the test.
4169         if (args.length != 3) {
4170             showInvalidArguments(writer);
4171             return;
4172         }
4173 
4174         int propId = Integer.parseInt(args[1]);
4175         int requestSize = Integer.parseInt(args[2]);
4176 
4177         byte[] byteValues = new byte[requestSize];
4178         for (int i = 0; i < requestSize; i++) {
4179             byteValues[i] = (byte) (i);
4180         }
4181 
4182         try {
4183             mHal.set(mHal.getHalPropValueBuilder().build(propId, /* areaId= */ 0, byteValues));
4184         } catch (IllegalArgumentException e) {
4185             writer.println(
4186                     "Test Skipped: The property: " + propId + " is not supported, error: " + e);
4187             return;
4188         } catch (ServiceSpecificException e) {
4189             writer.println(
4190                     "Test Failed: Failed to set property: " + propId + ", error: " + e);
4191             return;
4192         }
4193 
4194         HalPropValue result;
4195         try {
4196             result = mHal.get(mHal.getHalPropValueBuilder().build(propId, /* areaId= */ 0));
4197         } catch (IllegalArgumentException | ServiceSpecificException e) {
4198             writer.println(
4199                     "Test Failed: Failed to get property: " + propId + ", error: " + e);
4200             return;
4201         }
4202 
4203         int resultSize = result.getByteValuesSize();
4204         if (resultSize != requestSize) {
4205             writer.println("Test Failed: expect: " + requestSize + " bytes to be returned, got: "
4206                     + resultSize);
4207             return;
4208         }
4209 
4210         byte[] reverse = new byte[requestSize];
4211         for (int i = 0; i < requestSize; i++) {
4212             reverse[i] = byteValues[requestSize - 1 - i];
4213         }
4214 
4215         byte[] resultValues = result.getByteArray();
4216         if (!Arrays.equals(resultValues, reverse)) {
4217             writer.println("Test Failed: result mismatch, expect: " + Arrays.toString(reverse)
4218                     + ", got: " + Arrays.toString(resultValues));
4219             return;
4220         }
4221 
4222         try {
4223             // Set the property to a single byte to free-up memory. Cannot use empty byte array
4224             // here which would cause IllegalArgumentException.
4225             mHal.set(mHal.getHalPropValueBuilder().build(propId, /* areaId= */ 0,
4226                     new byte[]{ 0x00 }));
4227         } catch (IllegalArgumentException | ServiceSpecificException e) {
4228             writer.println(
4229                     "Test Failed: Failed to clean up property value: failed to set property: "
4230                             + propId + ", error: " + e);
4231             return;
4232         }
4233 
4234         writer.println("Test Succeeded!");
4235     }
4236 
4237     private void getTargetCarVersion(String[] args, IndentingPrintWriter writer) {
4238         if (args.length < 2) {
4239             showInvalidArguments(writer);
4240             return;
4241         }
4242 
4243         int firstAppArg = 1;
4244 
4245         // TODO(b/234499460): move --user logic to private helper / support 'all'
4246         int userId = UserHandle.CURRENT.getIdentifier();
4247         if (Objects.equals(args[1], "--user")) {
4248             if (args.length < 4) {
4249                 showInvalidArguments(writer);
4250                 return;
4251             }
4252             String userArg = args[2];
4253             firstAppArg += 2;
4254             if (!Objects.equals(userArg, "current") && !Objects.equals(userArg, "cur")) {
4255                 try {
4256                     userId = Integer.parseInt(args[2]);
4257                 } catch (NumberFormatException e) {
4258                     showInvalidArguments(writer);
4259                     return;
4260                 }
4261             }
4262         }
4263         if (userId == UserHandle.CURRENT.getIdentifier()) {
4264             userId = ActivityManager.getCurrentUser();
4265         }
4266         writer.printf("User %d:\n", userId);
4267 
4268         Context userContext = getContextForUser(userId);
4269         for (int i = firstAppArg; i < args.length; i++) {
4270             String app = args[i];
4271             try {
4272                 CarVersion Version = CarPackageManagerService.getTargetCarVersion(
4273                         userContext, app);
4274                 writer.printf("  %s: major=%d, minor=%d\n", app,
4275                         Version.getMajorVersion(), Version.getMinorVersion());
4276             } catch (ServiceSpecificException e) {
4277                 if (e.errorCode == CarPackageManager.ERROR_CODE_NO_PACKAGE) {
4278                     writer.printf("  %s: not found\n", app);
4279                 } else {
4280                     writer.printf("  %s: unexpected exception: %s \n", app, e);
4281                 }
4282                 continue;
4283             }
4284         }
4285     }
4286 
4287     private void setProcessGroup(String[] args, IndentingPrintWriter writer) {
4288         if (args.length != 3) {
4289             showInvalidArguments(writer);
4290             return;
4291         }
4292 
4293         int pid = Integer.parseInt(args[1]);
4294         int group = Integer.parseInt(args[2]);
4295         Slogf.d(TAG, "Setting process group for pid %d, group %d", pid, group);
4296 
4297         CarServiceHelperWrapper.getInstance().setProcessGroup(pid, group);
4298 
4299         writer.printf("  Successfully set pid %s to group %s\n", args[1], args[2]);
4300     }
4301 
4302     private void getProcessGroup(String[] args, IndentingPrintWriter writer) {
4303         if (args.length != 2) {
4304             showInvalidArguments(writer);
4305             return;
4306         }
4307 
4308         int pid = Integer.parseInt(args[1]);
4309         int group = CarServiceHelperWrapper.getInstance().getProcessGroup(pid);
4310 
4311         writer.printf("%d\n", group);
4312     }
4313 
4314     private void setProcessProfile(String[] args, IndentingPrintWriter writer) {
4315         if (args.length != 4) {
4316             showInvalidArguments(writer);
4317             return;
4318         }
4319 
4320         int pid = Integer.parseInt(args[1]);
4321         int uid = Integer.parseInt(args[2]);
4322         String profile = args[3];
4323 
4324         Slogf.d(TAG, "Setting process profile for pid %d, uid %d, profile %s", pid, uid, profile);
4325 
4326         CarServiceHelperWrapper.getInstance().setProcessProfile(pid, uid, profile);
4327 
4328         writer.printf("  Successfully set pid %d uid %d to profile %s\n", pid, uid, profile);
4329     }
4330 
4331     private void getDisplayByUser(String[] args, IndentingPrintWriter writer) {
4332         if (args.length != 2) {
4333             showInvalidArguments(writer);
4334             return;
4335         }
4336 
4337         // TODO(b/234499460): move --user logic to private helper / support 'all' and 'current'
4338         String userIdArg = args[1];
4339         int userId;
4340 
4341         if (Objects.equals(userIdArg, "current") || Objects.equals(userIdArg, "cur")) {
4342             userId = ActivityManager.getCurrentUser();
4343         } else {
4344             try {
4345                 userId = Integer.parseInt(userIdArg);
4346             } catch (NumberFormatException e) {
4347                 writer.printf("Invalid user id: %s\n", userIdArg);
4348                 return;
4349             }
4350         }
4351 
4352         int displayId = CarServiceHelperWrapper.getInstance().getMainDisplayAssignedToUser(userId);
4353         if (displayId == Display.INVALID_DISPLAY) {
4354             writer.println("none");
4355         } else {
4356             writer.println(displayId);
4357         }
4358     }
4359 
4360     private void getUserByDisplay(String[] args, IndentingPrintWriter writer) {
4361         if (args.length != 2) {
4362             showInvalidArguments(writer);
4363             return;
4364         }
4365 
4366         int displayId;
4367         String displayArg = args[1];
4368         try {
4369             displayId = Integer.parseInt(displayArg);
4370         } catch (NumberFormatException e) {
4371             writer.printf("Invalid displayId id: %s\n", displayArg);
4372             return;
4373         }
4374 
4375         int userId = CarServiceHelperWrapper.getInstance().getUserAssignedToDisplay(displayId);
4376         if (userId == UserManagerHelper.USER_NULL) {
4377             writer.println("none");
4378             return;
4379         }
4380         writer.println(userId);
4381     }
4382 
4383     private static boolean isPropertyAreaTypeGlobal(int propertyId) {
4384         return (propertyId & VehicleArea.MASK) == VehicleArea.GLOBAL;
4385     }
4386 
4387     private static String getSuspendCommandUsage(String command) {
4388         return command + " [" + PARAM_AUTO + "|" + PARAM_SIMULATE + "|" + PARAM_REAL + "] ["
4389                 + PARAM_SKIP_GARAGEMODE + "] [" + PARAM_WAKEUP_AFTER + " RESUME_DELAY | "
4390                 + PARAM_CANCEL_AFTER + " CANCEL_DELAY]" + "[" + PARAM_FREE_MEMORY + "]";
4391     }
4392 
4393     private static final class AudioZoneMirrorStatusCallbackImpl extends
4394             IAudioZonesMirrorStatusCallback.Stub {
4395 
4396         private static final long TEST_CALLBACK_TIMEOUT_MS = 5_000;
4397 
4398         private int[] mZoneIds;
4399         private int mStatus;
4400         private CountDownLatch mStatusLatch = new CountDownLatch(1);
4401 
4402         @Override
4403         public void onAudioZonesMirrorStatusChanged(int[] zoneIds, int status) {
4404             mZoneIds = zoneIds;
4405             mStatus = status;
4406             mStatusLatch.countDown();
4407         }
4408 
4409         private boolean waitForCallback() throws Exception {
4410             return mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
4411         }
4412 
4413         public void reset() {
4414             mZoneIds = null;
4415             mStatus = 0;
4416             mStatusLatch = new CountDownLatch(1);
4417         }
4418     }
4419 }
4420