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