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