1 /*
2  * Copyright (C) 2020 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_VOLUME;
19 import static android.car.Car.PERMISSION_CAR_POWER;
20 import static android.car.Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG;
21 import static android.car.Car.PERMISSION_USE_CAR_WATCHDOG;
22 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER;
23 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS;
24 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER;
25 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_1;
26 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_2;
27 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_3;
28 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_4;
29 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.KEY_FOB;
30 import static android.media.AudioManager.FLAG_SHOW_UI;
31 
32 import static com.android.car.power.PolicyReader.POWER_STATE_ON;
33 import static com.android.car.power.PolicyReader.POWER_STATE_WAIT_FOR_VHAL;
34 
35 import android.annotation.NonNull;
36 import android.annotation.Nullable;
37 import android.annotation.UserIdInt;
38 import android.app.ActivityManager;
39 import android.app.ActivityOptions;
40 import android.app.UiModeManager;
41 import android.car.Car;
42 import android.car.CarOccupantZoneManager;
43 import android.car.VehiclePropertyIds;
44 import android.car.content.pm.CarPackageManager;
45 import android.car.input.CarInputManager;
46 import android.car.input.CustomInputEvent;
47 import android.car.input.RotaryEvent;
48 import android.car.user.CarUserManager;
49 import android.car.user.UserCreationResult;
50 import android.car.user.UserIdentificationAssociationResponse;
51 import android.car.user.UserRemovalResult;
52 import android.car.user.UserSwitchResult;
53 import android.car.userlib.HalCallback;
54 import android.car.userlib.UserHalHelper;
55 import android.car.util.concurrent.AsyncFuture;
56 import android.car.watchdog.CarWatchdogManager;
57 import android.car.watchdog.IoOveruseConfiguration;
58 import android.car.watchdog.PerStateBytes;
59 import android.car.watchdog.ResourceOveruseConfiguration;
60 import android.content.ComponentName;
61 import android.content.Context;
62 import android.content.Intent;
63 import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
64 import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
65 import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
66 import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
67 import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
68 import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType;
69 import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
70 import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
71 import android.hardware.automotive.vehicle.V2_0.UserFlags;
72 import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociation;
73 import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue;
74 import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType;
75 import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue;
76 import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
77 import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
78 import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
79 import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
80 import android.hardware.automotive.vehicle.V2_0.UserInfo;
81 import android.hardware.automotive.vehicle.V2_0.UsersInfo;
82 import android.hardware.automotive.vehicle.V2_0.VehicleArea;
83 import android.hardware.automotive.vehicle.V2_0.VehicleDisplay;
84 import android.hardware.automotive.vehicle.V2_0.VehicleGear;
85 import android.os.Binder;
86 import android.os.Build;
87 import android.os.Process;
88 import android.os.RemoteException;
89 import android.os.ShellCommand;
90 import android.os.SystemClock;
91 import android.os.UserHandle;
92 import android.os.UserManager;
93 import android.text.TextUtils;
94 import android.util.ArrayMap;
95 import android.util.IndentingPrintWriter;
96 import android.util.Slog;
97 import android.util.SparseArray;
98 import android.view.KeyEvent;
99 
100 import com.android.car.am.FixedActivityService;
101 import com.android.car.audio.CarAudioService;
102 import com.android.car.evs.CarEvsService;
103 import com.android.car.garagemode.GarageModeService;
104 import com.android.car.hal.InputHalService;
105 import com.android.car.hal.UserHalService;
106 import com.android.car.hal.VehicleHal;
107 import com.android.car.pm.CarPackageManagerService;
108 import com.android.car.power.CarPowerManagementService;
109 import com.android.car.systeminterface.SystemInterface;
110 import com.android.car.user.CarUserService;
111 import com.android.car.watchdog.CarWatchdogService;
112 import com.android.internal.util.Preconditions;
113 
114 import java.util.ArrayList;
115 import java.util.Arrays;
116 import java.util.Collections;
117 import java.util.List;
118 import java.util.Objects;
119 import java.util.concurrent.CountDownLatch;
120 import java.util.concurrent.ExecutionException;
121 import java.util.concurrent.TimeUnit;
122 import java.util.concurrent.TimeoutException;
123 import java.util.concurrent.atomic.AtomicBoolean;
124 
125 final class CarShellCommand extends ShellCommand {
126 
127     private static final String NO_INITIAL_USER = "N/A";
128 
129     private static final String TAG = CarLog.tagFor(CarShellCommand.class);
130     private static final boolean VERBOSE = false;
131 
132     private static final String COMMAND_HELP = "-h";
133     private static final String COMMAND_DAY_NIGHT_MODE = "day-night-mode";
134     private static final String COMMAND_INJECT_VHAL_EVENT = "inject-vhal-event";
135     private static final String COMMAND_INJECT_ERROR_EVENT = "inject-error-event";
136     private static final String COMMAND_INJECT_CONTINUOUS_EVENT = "inject-continuous-events";
137     private static final String COMMAND_ENABLE_UXR = "enable-uxr";
138     private static final String COMMAND_GARAGE_MODE = "garage-mode";
139     private static final String COMMAND_GET_DO_ACTIVITIES = "get-do-activities";
140     private static final String COMMAND_GET_CARPROPERTYCONFIG = "get-carpropertyconfig";
141     private static final String COMMAND_GET_PROPERTY_VALUE = "get-property-value";
142     private static final String COMMAND_PROJECTION_AP_TETHERING = "projection-tethering";
143     private static final String COMMAND_PROJECTION_UI_MODE = "projection-ui-mode";
144     private static final String COMMAND_RESUME = "resume";
145     private static final String COMMAND_SUSPEND = "suspend";
146     private static final String COMMAND_SET_UID_TO_ZONE = "set-audio-zone-for-uid";
147     private static final String COMMAND_RESET_VOLUME_CONTEXT = "reset-selected-volume-context";
148     private static final String COMMAND_SET_MUTE_CAR_VOLUME_GROUP = "set-mute-car-volume-group";
149     private static final String COMMAND_SET_GROUP_VOLUME = "set-group-volume";
150     private static final String COMMAND_START_FIXED_ACTIVITY_MODE = "start-fixed-activity-mode";
151     private static final String COMMAND_STOP_FIXED_ACTIVITY_MODE = "stop-fixed-activity-mode";
152     private static final String COMMAND_ENABLE_FEATURE = "enable-feature";
153     private static final String COMMAND_DISABLE_FEATURE = "disable-feature";
154     private static final String COMMAND_INJECT_KEY = "inject-key";
155     private static final String COMMAND_INJECT_ROTARY = "inject-rotary";
156     private static final String COMMAND_INJECT_CUSTOM_INPUT = "inject-custom-input";
157     private static final String COMMAND_GET_INITIAL_USER_INFO = "get-initial-user-info";
158     private static final String COMMAND_SWITCH_USER = "switch-user";
159     private static final String COMMAND_REMOVE_USER = "remove-user";
160     private static final String COMMAND_CREATE_USER = "create-user";
161     private static final String COMMAND_GET_INITIAL_USER = "get-initial-user";
162     private static final String COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE =
163             "set-occupant-zone-for-user";
164     private static final String COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE =
165             "reset-user-in-occupant-zone";
166     private static final String COMMAND_GET_USER_AUTH_ASSOCIATION =
167             "get-user-auth-association";
168     private static final String COMMAND_SET_USER_AUTH_ASSOCIATION =
169             "set-user-auth-association";
170     private static final String COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE =
171             "set-start-bg-users-on-garage-mode";
172     private static final String COMMAND_DEFINE_POWER_POLICY = "define-power-policy";
173     private static final String COMMAND_APPLY_POWER_POLICY = "apply-power-policy";
174     private static final String COMMAND_DEFINE_POWER_POLICY_GROUP = "define-power-policy-group";
175     private static final String COMMAND_SET_POWER_POLICY_GROUP = "set-power-policy-group";
176     private static final String COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY =
177             "apply-cts-verifier-power-off-policy";
178     private static final String COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY =
179             "apply-cts-verifier-power-on-policy";
180     private static final String COMMAND_POWER_OFF = "power-off";
181     private static final String POWER_OFF_SKIP_GARAGEMODE = "--skip-garagemode";
182     private static final String POWER_OFF_SHUTDOWN = "--shutdown";
183     private static final String COMMAND_SILENT_MODE = "silent-mode";
184     // Used with COMMAND_SILENT_MODE for forced silent: "forced-silent"
185     private static final String SILENT_MODE_FORCED_SILENT =
186             CarPowerManagementService.SILENT_MODE_FORCED_SILENT;
187     // Used with COMMAND_SILENT_MODE for forced non silent: "forced-non-silent"
188     private static final String SILENT_MODE_FORCED_NON_SILENT =
189             CarPowerManagementService.SILENT_MODE_FORCED_NON_SILENT;
190     // Used with COMMAND_SILENT_MODE for non forced silent mode: "non-forced-silent-mode"
191     private static final String SILENT_MODE_NON_FORCED =
192             CarPowerManagementService.SILENT_MODE_NON_FORCED;
193 
194     private static final String COMMAND_EMULATE_DRIVING_STATE = "emulate-driving-state";
195     private static final String DRIVING_STATE_DRIVE = "drive";
196     private static final String DRIVING_STATE_PARK = "park";
197     private static final String DRIVING_STATE_REVERSE = "reverse";
198 
199     private static final String COMMAND_SET_REARVIEW_CAMERA_ID = "set-rearview-camera-id";
200     private static final String COMMAND_GET_REARVIEW_CAMERA_ID = "get-rearview-camera-id";
201 
202     private static final String COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE =
203             "watchdog-control-package-killable-state";
204     private static final String COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES =
205             "watchdog-io-set-3p-foreground-bytes";
206     private static final String COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES =
207             "watchdog-io-get-3p-foreground-bytes";
208     private static final String COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK =
209             "watchdog-control-health-check";
210 
211     private static final String COMMAND_DRIVING_SAFETY_SET_REGION =
212             "set-drivingsafety-region";
213 
214     private static final String[] CREATE_OR_MANAGE_USERS_PERMISSIONS = new String[] {
215             android.Manifest.permission.CREATE_USERS,
216             android.Manifest.permission.MANAGE_USERS
217     };
218 
219     // List of commands allowed in user build. All these command should be protected with
220     // a permission. K: command, V: required permissions (must have at least 1).
221     // Only commands with permission already granted to shell user should be allowed.
222     // Commands that can affect safety should be never allowed in user build.
223     //
224     // This map is looked up first, then USER_BUILD_COMMAND_TO_PERMISSION_MAP
225     private static final ArrayMap<String, String[]> USER_BUILD_COMMAND_TO_PERMISSIONS_MAP;
226     static {
227         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP = new ArrayMap<>(7);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_INITIAL_USER_INFO, CREATE_OR_MANAGE_USERS_PERMISSIONS)228         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_INITIAL_USER_INFO,
229                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SWITCH_USER, CREATE_OR_MANAGE_USERS_PERMISSIONS)230         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SWITCH_USER,
231                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_REMOVE_USER, CREATE_OR_MANAGE_USERS_PERMISSIONS)232         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_REMOVE_USER,
233                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_CREATE_USER, CREATE_OR_MANAGE_USERS_PERMISSIONS)234         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_CREATE_USER,
235                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_USER_AUTH_ASSOCIATION, CREATE_OR_MANAGE_USERS_PERMISSIONS)236         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_USER_AUTH_ASSOCIATION,
237                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SET_USER_AUTH_ASSOCIATION, CREATE_OR_MANAGE_USERS_PERMISSIONS)238         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SET_USER_AUTH_ASSOCIATION,
239                 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)240         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE,
241                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
242     }
243 
244     // List of commands allowed in user build. All these command should be protected with
245     // a permission. K: command, V: required permission.
246     // Only commands with permission already granted to shell user should be allowed.
247     // Commands that can affect safety should be never allowed in user build.
248     private static final ArrayMap<String, String> USER_BUILD_COMMAND_TO_PERMISSION_MAP;
249     static {
250         USER_BUILD_COMMAND_TO_PERMISSION_MAP = new ArrayMap<>(8);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GARAGE_MODE, android.Manifest.permission.DEVICE_POWER)251         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GARAGE_MODE,
252                 android.Manifest.permission.DEVICE_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_RESUME, android.Manifest.permission.DEVICE_POWER)253         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_RESUME,
254                 android.Manifest.permission.DEVICE_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SUSPEND, android.Manifest.permission.DEVICE_POWER)255         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SUSPEND,
256                 android.Manifest.permission.DEVICE_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DEFINE_POWER_POLICY, android.Manifest.permission.DEVICE_POWER)257         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DEFINE_POWER_POLICY,
258                 android.Manifest.permission.DEVICE_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_POWER_POLICY, android.Manifest.permission.DEVICE_POWER)259         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_POWER_POLICY,
260                 android.Manifest.permission.DEVICE_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DEFINE_POWER_POLICY_GROUP, android.Manifest.permission.DEVICE_POWER)261         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DEFINE_POWER_POLICY_GROUP,
262                 android.Manifest.permission.DEVICE_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_POWER_POLICY_GROUP, android.Manifest.permission.DEVICE_POWER)263         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_POWER_POLICY_GROUP,
264                 android.Manifest.permission.DEVICE_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY, android.Manifest.permission.DEVICE_POWER)265         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY,
266                 android.Manifest.permission.DEVICE_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY, android.Manifest.permission.DEVICE_POWER)267         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY,
268                 android.Manifest.permission.DEVICE_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SILENT_MODE, PERMISSION_CAR_POWER)269         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SILENT_MODE,
270                 PERMISSION_CAR_POWER);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_INITIAL_USER, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)271         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_INITIAL_USER,
272                 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)273         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_DAY_NIGHT_MODE,
274                 android.Manifest.permission.MODIFY_DAY_NIGHT_MODE);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_RESET_VOLUME_CONTEXT, PERMISSION_CAR_CONTROL_AUDIO_VOLUME)275         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_RESET_VOLUME_CONTEXT,
276                 PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_MUTE_CAR_VOLUME_GROUP, PERMISSION_CAR_CONTROL_AUDIO_VOLUME)277         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_MUTE_CAR_VOLUME_GROUP,
278                 PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_GROUP_VOLUME, PERMISSION_CAR_CONTROL_AUDIO_VOLUME)279         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_GROUP_VOLUME,
280                 PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_KEY, android.Manifest.permission.INJECT_EVENTS)281         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_KEY,
282                 android.Manifest.permission.INJECT_EVENTS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_ROTARY, android.Manifest.permission.INJECT_EVENTS)283         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_ROTARY,
284                 android.Manifest.permission.INJECT_EVENTS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE, PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG)285         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE,
286                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES, PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG)287         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES,
288                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES, PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG)289         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES,
290                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK, PERMISSION_USE_CAR_WATCHDOG)291         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK,
292                 PERMISSION_USE_CAR_WATCHDOG);
293     }
294 
295     private static final String PARAM_DAY_MODE = "day";
296     private static final String PARAM_NIGHT_MODE = "night";
297     private static final String PARAM_SENSOR_MODE = "sensor";
298     private static final String PARAM_VEHICLE_PROPERTY_AREA_GLOBAL = "0";
299     private static final String PARAM_INJECT_EVENT_DEFAULT_RATE = "10";
300     private static final String PARAM_INJECT_EVENT_DEFAULT_DURATION = "60";
301     private static final String PARAM_ALL_PROPERTIES_OR_AREA = "-1";
302     private static final String PARAM_ON_MODE = "on";
303     private static final String PARAM_OFF_MODE = "off";
304     private static final String PARAM_QUERY_MODE = "query";
305     private static final String PARAM_REBOOT = "reboot";
306     private static final String PARAM_MUTE = "mute";
307     private static final String PARAM_UNMUTE = "unmute";
308 
309 
310     private static final int RESULT_OK = 0;
311     private static final int RESULT_ERROR = -1; // Arbitrary value, any non-0 is fine
312 
313     private static final int DEFAULT_HAL_TIMEOUT_MS = 1_000;
314 
315     private static final int DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS = 60_000;
316 
317     private static final int INVALID_USER_AUTH_TYPE_OR_VALUE = -1;
318 
319     private static final SparseArray<String> VALID_USER_AUTH_TYPES;
320     private static final String VALID_USER_AUTH_TYPES_HELP;
321 
322     private static final SparseArray<String> VALID_USER_AUTH_SET_VALUES;
323     private static final String VALID_USER_AUTH_SET_VALUES_HELP;
324 
325     private static final ArrayMap<String, Integer> CUSTOM_INPUT_FUNCTION_ARGS;
326 
327     static {
328         VALID_USER_AUTH_TYPES = new SparseArray<>(5);
VALID_USER_AUTH_TYPES.put(KEY_FOB, UserIdentificationAssociationType.toString(KEY_FOB))329         VALID_USER_AUTH_TYPES.put(KEY_FOB, UserIdentificationAssociationType.toString(KEY_FOB));
VALID_USER_AUTH_TYPES.put(CUSTOM_1, UserIdentificationAssociationType.toString(CUSTOM_1))330         VALID_USER_AUTH_TYPES.put(CUSTOM_1, UserIdentificationAssociationType.toString(CUSTOM_1));
VALID_USER_AUTH_TYPES.put(CUSTOM_2, UserIdentificationAssociationType.toString(CUSTOM_2))331         VALID_USER_AUTH_TYPES.put(CUSTOM_2, UserIdentificationAssociationType.toString(CUSTOM_2));
VALID_USER_AUTH_TYPES.put(CUSTOM_3, UserIdentificationAssociationType.toString(CUSTOM_3))332         VALID_USER_AUTH_TYPES.put(CUSTOM_3, UserIdentificationAssociationType.toString(CUSTOM_3));
VALID_USER_AUTH_TYPES.put(CUSTOM_4, UserIdentificationAssociationType.toString(CUSTOM_4))333         VALID_USER_AUTH_TYPES.put(CUSTOM_4, UserIdentificationAssociationType.toString(CUSTOM_4));
334         VALID_USER_AUTH_TYPES_HELP = getHelpString("types", VALID_USER_AUTH_TYPES);
335 
336         VALID_USER_AUTH_SET_VALUES = new SparseArray<>(3);
VALID_USER_AUTH_SET_VALUES.put(ASSOCIATE_CURRENT_USER, UserIdentificationAssociationSetValue.toString(ASSOCIATE_CURRENT_USER))337         VALID_USER_AUTH_SET_VALUES.put(ASSOCIATE_CURRENT_USER,
338                 UserIdentificationAssociationSetValue.toString(ASSOCIATE_CURRENT_USER));
VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_CURRENT_USER, UserIdentificationAssociationSetValue.toString(DISASSOCIATE_CURRENT_USER))339         VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_CURRENT_USER,
340                 UserIdentificationAssociationSetValue.toString(DISASSOCIATE_CURRENT_USER));
VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_ALL_USERS, UserIdentificationAssociationSetValue.toString(DISASSOCIATE_ALL_USERS))341         VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_ALL_USERS,
342                 UserIdentificationAssociationSetValue.toString(DISASSOCIATE_ALL_USERS));
343         VALID_USER_AUTH_SET_VALUES_HELP = getHelpString("values", VALID_USER_AUTH_SET_VALUES);
344 
345         CUSTOM_INPUT_FUNCTION_ARGS = new ArrayMap<>(10);
346         CUSTOM_INPUT_FUNCTION_ARGS.put("f1", CustomInputEvent.INPUT_CODE_F1);
347         CUSTOM_INPUT_FUNCTION_ARGS.put("f2", CustomInputEvent.INPUT_CODE_F2);
348         CUSTOM_INPUT_FUNCTION_ARGS.put("f3", CustomInputEvent.INPUT_CODE_F3);
349         CUSTOM_INPUT_FUNCTION_ARGS.put("f4", CustomInputEvent.INPUT_CODE_F4);
350         CUSTOM_INPUT_FUNCTION_ARGS.put("f5", CustomInputEvent.INPUT_CODE_F5);
351         CUSTOM_INPUT_FUNCTION_ARGS.put("f6", CustomInputEvent.INPUT_CODE_F6);
352         CUSTOM_INPUT_FUNCTION_ARGS.put("f7", CustomInputEvent.INPUT_CODE_F7);
353         CUSTOM_INPUT_FUNCTION_ARGS.put("f8", CustomInputEvent.INPUT_CODE_F8);
354         CUSTOM_INPUT_FUNCTION_ARGS.put("f9", CustomInputEvent.INPUT_CODE_F9);
355         CUSTOM_INPUT_FUNCTION_ARGS.put("f10", CustomInputEvent.INPUT_CODE_F10);
356     }
357 
358     @NonNull
getHelpString(@onNull String name, @NonNull SparseArray<String> values)359     private static String getHelpString(@NonNull String name, @NonNull SparseArray<String> values) {
360         StringBuilder help = new StringBuilder("Valid ").append(name).append(" are: ");
361         int size = values.size();
362         for (int i = 0; i < size; i++) {
363             help.append(values.valueAt(i));
364             if (i != size - 1) {
365                 help.append(", ");
366             }
367         }
368         return help.append('.').toString();
369     }
370 
371     private final Context mContext;
372     private final VehicleHal mHal;
373     private final CarAudioService mCarAudioService;
374     private final CarPackageManagerService mCarPackageManagerService;
375     private final CarProjectionService mCarProjectionService;
376     private final CarPowerManagementService mCarPowerManagementService;
377     private final FixedActivityService mFixedActivityService;
378     private final CarFeatureController mFeatureController;
379     private final CarInputService mCarInputService;
380     private final CarNightService mCarNightService;
381     private final SystemInterface mSystemInterface;
382     private final GarageModeService mGarageModeService;
383     private final CarUserService mCarUserService;
384     private final CarOccupantZoneService mCarOccupantZoneService;
385     private final CarEvsService mCarEvsService;
386     private final CarWatchdogService mCarWatchdogService;
387     private long mKeyDownTime;
388 
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)389     CarShellCommand(Context context,
390             VehicleHal hal,
391             CarAudioService carAudioService,
392             CarPackageManagerService carPackageManagerService,
393             CarProjectionService carProjectionService,
394             CarPowerManagementService carPowerManagementService,
395             FixedActivityService fixedActivityService,
396             CarFeatureController featureController,
397             CarInputService carInputService,
398             CarNightService carNightService,
399             SystemInterface systemInterface,
400             GarageModeService garageModeService,
401             CarUserService carUserService,
402             CarOccupantZoneService carOccupantZoneService,
403             CarEvsService carEvsService,
404             CarWatchdogService carWatchdogService) {
405         mContext = context;
406         mHal = hal;
407         mCarAudioService = carAudioService;
408         mCarPackageManagerService = carPackageManagerService;
409         mCarProjectionService = carProjectionService;
410         mCarPowerManagementService = carPowerManagementService;
411         mFixedActivityService = fixedActivityService;
412         mFeatureController = featureController;
413         mCarInputService = carInputService;
414         mCarNightService = carNightService;
415         mSystemInterface = systemInterface;
416         mGarageModeService = garageModeService;
417         mCarUserService = carUserService;
418         mCarOccupantZoneService = carOccupantZoneService;
419         mCarEvsService = carEvsService;
420         mCarWatchdogService = carWatchdogService;
421     }
422 
423     @Override
onCommand(String cmd)424     public int onCommand(String cmd) {
425         if (cmd == null) {
426             onHelp();
427             return RESULT_ERROR;
428         }
429         ArrayList<String> argsList = new ArrayList<>();
430         argsList.add(cmd);
431         String arg = null;
432         do {
433             arg = getNextArg();
434             if (arg != null) {
435                 argsList.add(arg);
436             }
437         } while (arg != null);
438         String[] args = new String[argsList.size()];
439         argsList.toArray(args);
440         try (IndentingPrintWriter pw = new IndentingPrintWriter(getOutPrintWriter())) {
441             return exec(args, pw);
442         }
443     }
444 
445     @Override
onHelp()446     public void onHelp() {
447         try (IndentingPrintWriter pw = new IndentingPrintWriter(getOutPrintWriter())) {
448             showHelp(pw);
449         }
450     }
451 
showHelp(IndentingPrintWriter pw)452     private static void showHelp(IndentingPrintWriter pw) {
453         pw.println("Car service commands:");
454         pw.println("\t-h");
455         pw.println("\t  Print this help text.");
456         pw.println("\tday-night-mode [day|night|sensor]");
457         pw.println("\t  Force into day/night mode or restore to auto.");
458         pw.println("\tinject-vhal-event <PROPERTY_ID in Hex or Decimal> [zone] "
459                 + "data(can be comma separated list) "
460                 + "[-t delay_time_seconds]");
461         pw.println("\t  Inject a vehicle property for testing.");
462         pw.println("\t  delay_time_seconds: the event timestamp is increased by certain second.");
463         pw.println("\t  If not specified, it will be 0.");
464         pw.println("\tinject-error-event <PROPERTY_ID in Hex or Decimal> zone <errorCode>");
465         pw.println("\t  Inject an error event from VHAL for testing.");
466         pw.println("\tinject-continuous-events <PROPERTY_ID in Hex or Decimal> "
467                 + "data(can be comma separated list) "
468                 + "[-z zone]  [-s SampleRate in Hz] [-d time duration in seconds]");
469         pw.println("\t  Inject continuous vehicle events for testing.");
470         pw.printf("\t  If not specified, CarService will inject fake events with areaId:%s "
471                         + "at sample rate %s for %s seconds.", PARAM_VEHICLE_PROPERTY_AREA_GLOBAL,
472                 PARAM_INJECT_EVENT_DEFAULT_RATE, PARAM_INJECT_EVENT_DEFAULT_DURATION);
473         pw.println("\tenable-uxr true|false");
474         pw.println("\t  Enable/Disable UX restrictions and App blocking.");
475         pw.println("\tgarage-mode [on|off|query|reboot]");
476         pw.println("\t  Force into or out of garage mode, or check status.");
477         pw.println("\t  With 'reboot', enter garage mode, then reboot when it completes.");
478         pw.println("\tget-do-activities pkgname");
479         pw.println("\t  Get Distraction Optimized activities in given package.");
480         pw.println("\tget-carpropertyconfig [PROPERTY_ID in Hex or Decimal]");
481         pw.println("\t  Get a CarPropertyConfig by Id or list all CarPropertyConfigs");
482         pw.println("\tget-property-value [PROPERTY_ID in Hex or Decimal] [areaId]");
483         pw.println("\t  Get a vehicle property value by property id and areaId");
484         pw.println("\t  or list all property values for all areaId");
485         pw.println("\tsuspend");
486         pw.println("\t  Suspend the system to Deep Sleep.");
487         pw.println("\tresume");
488         pw.println("\t  Wake the system up after a 'suspend.'");
489         pw.println("\tprojection-tethering [true|false]");
490         pw.println("\t  Whether tethering should be used when creating access point for"
491                 + " wireless projection");
492         pw.println("\t--metrics");
493         pw.println("\t  When used with dumpsys, only metrics will be in the dumpsys output.");
494         pw.printf("\t%s [zoneid] [uid]\n", COMMAND_SET_UID_TO_ZONE);
495         pw.println("\t  Maps the audio zoneid to uid.");
496         pw.printf("\t%s\n", COMMAND_RESET_VOLUME_CONTEXT);
497         pw.println("\t  Resets the last selected volume context for volume changes.");
498         pw.printf("\t%s [zoneId] [groupId] [%s\\%s]\n", COMMAND_SET_MUTE_CAR_VOLUME_GROUP,
499                 PARAM_MUTE, PARAM_UNMUTE);
500         pw.printf("\t  %s\\%s groupId in zoneId\n", PARAM_MUTE, PARAM_UNMUTE);
501         pw.printf("\t%s [zoneId] [groupId] [volume]\n", COMMAND_SET_GROUP_VOLUME);
502         pw.println("\t  sets the group volume for [groupId] in [zoneId] to %volume,");
503         pw.println("\t  [volume] must be an integer between 0 to 100");
504         pw.println("\tstart-fixed-activity displayId packageName activityName");
505         pw.println("\t  Start an Activity the specified display as fixed mode");
506         pw.println("\tstop-fixed-mode displayId");
507         pw.println("\t  Stop fixed Activity mode for the given display. "
508                 + "The Activity will not be restarted upon crash.");
509         pw.println("\tenable-feature featureName");
510         pw.println("\t  Enable the requested feature. Change will happen after reboot.");
511         pw.println("\t  This requires root/su.");
512         pw.println("\tdisable-feature featureName");
513         pw.println("\t  Disable the requested feature. Change will happen after reboot");
514         pw.println("\t  This requires root/su.");
515         pw.println("\tinject-key [-d display] [-t down_delay_ms | -a down|up] key_code");
516         pw.println("\t  inject key down and/or up event to car service");
517         pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
518         pw.println("\t  down_delay_ms: delay from down to up key event. If not specified,");
519         pw.println("\t                 it will be 0");
520         pw.println("\t  key_code: int key code defined in android KeyEvent");
521         pw.println("\t  If -a isn't specified, both down and up will be injected.");
522         pw.println("\tinject-rotary [-d display] [-i input_type] [-c clockwise]");
523         pw.println("\t              [-dt delta_times_ms]");
524         pw.println("\t  inject rotary input event to car service.");
525         pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
526         pw.println("\t  input_type: 10 for navigation controller input, 11 for volume");
527         pw.println("\t              controller input. If not specified, it will be 10.");
528         pw.println("\t  clockwise: true if the event is clockwise, false if the event is");
529         pw.println("\t             counter-clockwise. If not specified, it will be false.");
530         pw.println("\t  delta_times_ms: a list of delta time (current time minus event time)");
531         pw.println("\t                  in descending order. If not specified, it will be 0.");
532         pw.println("\tinject-custom-input [-d display] [-r repeatCounter] EVENT");
533         pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
534         pw.println("\t  repeatCounter: number of times the button was hit (default value is 1)");
535         pw.println("\t  EVENT: mandatory last argument. Possible values for for this flag are ");
536         pw.println("\t         F1, F2, up to F10 (functions to defined by OEM partners)");
537         pw.printf("\t%s <REQ_TYPE> [--timeout TIMEOUT_MS]\n", COMMAND_GET_INITIAL_USER_INFO);
538         pw.println("\t  Calls the Vehicle HAL to get the initial boot info, passing the given");
539         pw.println("\t  REQ_TYPE (which could be either FIRST_BOOT, FIRST_BOOT_AFTER_OTA, ");
540         pw.println("\t  COLD_BOOT, RESUME, or any numeric value that would be passed 'as-is')");
541         pw.println("\t  and an optional TIMEOUT_MS to wait for the HAL response (if not set,");
542         pw.println("\t  it will use a  default value).");
543         pw.println("\t  The --hal-only option only calls HAL, without using CarUserService.");
544 
545         pw.printf("\t%s <USER_ID> [--hal-only] [--timeout TIMEOUT_MS]\n", COMMAND_SWITCH_USER);
546         pw.println("\t  Switches to user USER_ID using the HAL integration.");
547         pw.println("\t  The --hal-only option only calls HAL, without switching the user,");
548         pw.println("\t  while the --timeout defines how long to wait for the response.");
549 
550         pw.printf("\t%s <USER_ID> [--hal-only]\n", COMMAND_REMOVE_USER);
551         pw.println("\t  Removes user with USER_ID using the HAL integration.");
552         pw.println("\t  The --hal-only option only calls HAL, without removing the user,");
553 
554         pw.printf("\t%s [--hal-only] [--timeout TIMEOUT_MS] [--type TYPE] [--flags FLAGS] [NAME]\n",
555                 COMMAND_CREATE_USER);
556         pw.println("\t  Creates a new user using the HAL integration.");
557         pw.println("\t  The --hal-only uses UserManager to create the user,");
558         pw.println("\t  while the --timeout defines how long to wait for the response.");
559 
560         pw.printf("\t%s\n", COMMAND_GET_INITIAL_USER);
561         pw.printf("\t  Gets the id of the initial user (or %s when it's not available)\n",
562                 NO_INITIAL_USER);
563 
564         pw.printf("\t%s [occupantZoneId] [userId]\n", COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE);
565         pw.println("\t  Maps the occupant zone id to user id.");
566         pw.printf("\t%s [occupantZoneId]\n", COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE);
567         pw.println("\t  Unmaps the user assigned to occupant zone id.");
568 
569         pw.printf("\t%s [--hal-only] [--user USER_ID] TYPE1 [..TYPE_N]\n",
570                 COMMAND_GET_USER_AUTH_ASSOCIATION);
571         pw.println("\t  Gets the N user authentication values for the N types for the given user");
572         pw.println("\t  (or current user when not specified).");
573         pw.println("\t  By defautt it calls CarUserManager, but using --hal-only will call just "
574                 + "UserHalService.");
575 
576         pw.printf("\t%s [--hal-only] [--user USER_ID] TYPE1 VALUE1 [..TYPE_N VALUE_N]\n",
577                 COMMAND_SET_USER_AUTH_ASSOCIATION);
578         pw.println("\t  Sets the N user authentication types with the N values for the given user");
579         pw.println("\t  (or current user when not specified).");
580         pw.println("\t  By default it calls CarUserManager, but using --hal-only will call just "
581                 + "UserHalService.");
582         pw.printf("\t  %s\n", VALID_USER_AUTH_TYPES_HELP);
583         pw.printf("\t  %s\n", VALID_USER_AUTH_SET_VALUES_HELP);
584 
585         pw.printf("\t%s [true|false]\n", COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE);
586         pw.println("\t  Controls backgroud user start and stop during garage mode.");
587         pw.println("\t  If false, garage mode operations (background users start at garage mode"
588                 + " entry and background users stop at garage mode exit) will be skipped.");
589 
590         pw.printf("\t  %s [%s|%s|%s|%s]\n", COMMAND_SILENT_MODE, SILENT_MODE_FORCED_SILENT,
591                 SILENT_MODE_FORCED_NON_SILENT, SILENT_MODE_NON_FORCED, PARAM_QUERY_MODE);
592         pw.println("\t  Forces silent mode silent or non-silent. With query (or no command) "
593                 + "displays the silent state");
594         pw.println("\t  and shows how many listeners are monitoring the state.");
595 
596         pw.printf("\t%s [%s|%s|%s]\n", COMMAND_EMULATE_DRIVING_STATE, DRIVING_STATE_DRIVE,
597                 DRIVING_STATE_PARK, DRIVING_STATE_REVERSE);
598         pw.println("\t  Emulates the giving driving state.");
599 
600         pw.printf("\t%s <POLICY_ID> [--enable COMP1,COMP2,...] [--disable COMP1,COMP2,...]\n",
601                 COMMAND_DEFINE_POWER_POLICY);
602         pw.println("\t  Defines a power policy. Components not specified in --enable or --disable");
603         pw.println("\t  are unchanged when the policy is applied.");
604         pw.println("\t  Components should be comma-separated without space.");
605 
606         pw.printf("\t%s <POLICY_ID>\n", COMMAND_APPLY_POWER_POLICY);
607         pw.println("\t  Applies power policy which is defined in /vendor/etc/power_policy.xml or");
608         pw.printf("\t  by %s command\n", COMMAND_DEFINE_POWER_POLICY);
609 
610         pw.printf("\t%s <POLICY_GROUP_ID> [%s:<POLICY_ID>] [%s:<POLICY_ID>]\n",
611                 COMMAND_DEFINE_POWER_POLICY_GROUP, POWER_STATE_WAIT_FOR_VHAL, POWER_STATE_ON);
612         pw.println("\t  Defines a power policy group. The policy ID must be defined in advance.");
613 
614         pw.printf("\t%s <POLICY_GROUP_ID>\n", COMMAND_SET_POWER_POLICY_GROUP);
615         pw.println("\t  Sets power policy group which is defined in /vendor/etc/power_policy.xml ");
616         pw.printf("\t  or by %s command\n", COMMAND_DEFINE_POWER_POLICY_GROUP);
617 
618         pw.printf("\t%s\n", COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY);
619         pw.println("\t  Define and apply the cts_verifier_off power policy with "
620                 + "--disable WIFI,LOCATION,BLUETOOTH");
621 
622         pw.printf("\t%s\n", COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY);
623         pw.println("\t  Define and apply the cts_verifier_on power policy with "
624                 + "--enable WIFI,LOCATION,BLUETOOTH");
625 
626         pw.printf("\t%s [%s] [%s]\n", COMMAND_POWER_OFF, POWER_OFF_SKIP_GARAGEMODE,
627                 POWER_OFF_SHUTDOWN);
628         pw.println("\t  Powers off the car.");
629 
630         pw.printf("\t%s <CAMERA_ID>\n", COMMAND_SET_REARVIEW_CAMERA_ID);
631         pw.println("\t  Configures a target camera device CarEvsService to use.");
632         pw.println("\t  If CAMEAR_ID is \"default\", this command will configure CarEvsService ");
633         pw.println("\t  to use its default camera device.");
634 
635         pw.printf("\t%s\n", COMMAND_GET_REARVIEW_CAMERA_ID);
636         pw.println("\t  Gets the name of the camera device CarEvsService is using for " +
637                 "the rearview.");
638 
639         pw.printf("\t%s true|false <PACKAGE_NAME>\n",
640                 COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE);
641         pw.println("\t  Marks PACKAGE_NAME as killable or not killable on resource overuse ");
642 
643         pw.printf("\t%s <FOREGROUND_MODE_BYTES>\n", COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES);
644         pw.println("\t  Sets third-party apps foreground I/O overuse threshold");
645 
646         pw.printf("\t%s\n", COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES);
647         pw.println("\t  Gets third-party apps foreground I/O overuse threshold");
648 
649         pw.printf("\t%s enable|disable\n", COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK);
650         pw.println("\t  Enables/disables car watchdog process health check.");
651 
652         pw.printf("\t%s [REGION_STRING]", COMMAND_DRIVING_SAFETY_SET_REGION);
653         pw.println("\t  Set driving safety region.");
654         pw.println("\t  Skipping REGION_STRING leads into resetting to all regions");
655     }
656 
showInvalidArguments(IndentingPrintWriter pw)657     private static int showInvalidArguments(IndentingPrintWriter pw) {
658         pw.println("Incorrect number of arguments.");
659         showHelp(pw);
660         return RESULT_ERROR;
661     }
662 
runSetZoneIdForUid(String zoneString, String uidString)663     private void runSetZoneIdForUid(String zoneString, String uidString) {
664         int uid = Integer.parseInt(uidString);
665         int zoneId = Integer.parseInt(zoneString);
666         mCarAudioService.setZoneIdForUid(zoneId, uid);
667     }
668 
runSetMuteCarVolumeGroup(String zoneString, String groupIdString, String muteString)669     private void runSetMuteCarVolumeGroup(String zoneString, String groupIdString,
670             String muteString) {
671         int groupId = Integer.parseInt(groupIdString);
672         int zoneId = Integer.parseInt(zoneString);
673         if (!PARAM_MUTE.equalsIgnoreCase(muteString)
674                 && !PARAM_UNMUTE.equalsIgnoreCase(muteString)) {
675             throw new IllegalArgumentException("Failed to set volume group mute for "
676                     + groupIdString + " in zone " + zoneString
677                     + ", bad mute argument: " + muteString);
678         }
679         boolean muteState = PARAM_MUTE.equalsIgnoreCase(muteString);
680         mCarAudioService.setVolumeGroupMute(zoneId, groupId, muteState, FLAG_SHOW_UI);
681     }
682 
683 
runSetGroupVolume(String zoneIdString, String groupIdString, String volumeString)684     private void runSetGroupVolume(String zoneIdString, String groupIdString, String volumeString) {
685         int groupId = Integer.parseInt(groupIdString);
686         int zoneId = Integer.parseInt(zoneIdString);
687         int percentVolume = Integer.parseInt(volumeString);
688         Preconditions.checkArgumentInRange(percentVolume, 0, 100,
689                 "%volume for group " + groupIdString + " in zone " + zoneIdString);
690         int minIndex = mCarAudioService.getGroupMinVolume(zoneId, groupId);
691         int maxIndex = mCarAudioService.getGroupMaxVolume(zoneId, groupId);
692         int index = minIndex
693                 + (int) ((float) (maxIndex - minIndex) * ((float) percentVolume / 100.0f));
694         mCarAudioService.setGroupVolume(zoneId, groupId, index, FLAG_SHOW_UI);
695     }
696 
runResetSelectedVolumeContext()697     private void runResetSelectedVolumeContext() {
698         mCarAudioService.resetSelectedVolumeContext();
699     }
700 
runSetOccupantZoneIdForUserId(String occupantZoneIdString, String userIdString)701     private void runSetOccupantZoneIdForUserId(String occupantZoneIdString,
702             String userIdString) {
703         int userId = Integer.parseInt(userIdString);
704         int occupantZoneId = Integer.parseInt(occupantZoneIdString);
705         if (!mCarOccupantZoneService.assignProfileUserToOccupantZone(occupantZoneId, userId)) {
706             throw new IllegalStateException("Failed to set userId " + userId + " to occupantZoneId "
707                     + occupantZoneIdString);
708         }
709     }
710 
runResetOccupantZoneId(String occupantZoneIdString)711     private void runResetOccupantZoneId(String occupantZoneIdString) {
712         int occupantZoneId = Integer.parseInt(occupantZoneIdString);
713         if (!mCarOccupantZoneService
714                 .assignProfileUserToOccupantZone(occupantZoneId, UserHandle.USER_NULL)) {
715             throw new IllegalStateException("Failed to reset occupantZoneId "
716                     + occupantZoneIdString);
717         }
718     }
719 
assertHasAtLeastOnePermission(String cmd, String[] requiredPermissions)720     private void assertHasAtLeastOnePermission(String cmd, String[] requiredPermissions) {
721         for (String requiredPermission : requiredPermissions) {
722             if (ICarImpl.hasPermission(mContext, requiredPermission)) return;
723         }
724         if (requiredPermissions.length == 1) {
725             throw new SecurityException("The command '" + cmd + "' requires permission:"
726                     + requiredPermissions[0]);
727         }
728         throw new SecurityException(
729                 "The command " + cmd + " requires one of the following permissions:"
730                         + Arrays.toString(requiredPermissions));
731     }
732 
exec(String[] args, IndentingPrintWriter writer)733     int exec(String[] args, IndentingPrintWriter writer) {
734         String cmd = args[0];
735         String[] requiredPermissions = USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.get(cmd);
736         if (requiredPermissions == null) {
737             String requiredPermission = USER_BUILD_COMMAND_TO_PERMISSION_MAP.get(cmd);
738             if (requiredPermission != null) {
739                 requiredPermissions = new String[] { requiredPermission };
740             }
741 
742         }
743         if (VERBOSE) {
744             Slog.v(TAG, "cmd: " + cmd + ", requiredPermissions: "
745                     + Arrays.toString(requiredPermissions));
746         }
747         if (Build.IS_USER && requiredPermissions == null) {
748             throw new SecurityException("The command '" + cmd + "' requires non-user build");
749         }
750         if (requiredPermissions != null) {
751             assertHasAtLeastOnePermission(cmd, requiredPermissions);
752         }
753 
754         switch (cmd) {
755             case COMMAND_HELP:
756                 showHelp(writer);
757                 break;
758             case COMMAND_DAY_NIGHT_MODE: {
759                 String value = args.length < 2 ? "" : args[1];
760                 forceDayNightMode(value, writer);
761                 break;
762             }
763             case COMMAND_GARAGE_MODE: {
764                 String value = args.length < 2 ? "" : args[1];
765                 forceGarageMode(value, writer);
766                 break;
767             }
768             case COMMAND_INJECT_VHAL_EVENT:
769                 String zone = PARAM_VEHICLE_PROPERTY_AREA_GLOBAL;
770                 String data;
771                 int argNum = args.length;
772                 if (argNum < 3 || argNum > 6) {
773                     return showInvalidArguments(writer);
774                 }
775                 String delayTime = args[argNum - 2].equals("-t") ?  args[argNum - 1] : "0";
776                 if (argNum == 4 || argNum == 6) {
777                     // Zoned
778                     zone = args[2];
779                     data = args[3];
780                 } else {
781                     // Global
782                     data = args[2];
783                 }
784                 injectVhalEvent(args[1], zone, data, false, delayTime, writer);
785                 break;
786             case COMMAND_INJECT_CONTINUOUS_EVENT:
787                 injectContinuousEvents(args, writer);
788                 break;
789             case COMMAND_INJECT_ERROR_EVENT:
790                 if (args.length != 4) {
791                     return showInvalidArguments(writer);
792                 }
793                 String errorAreaId = args[2];
794                 String errorCode = args[3];
795                 injectVhalEvent(args[1], errorAreaId, errorCode, true, "0", writer);
796                 break;
797             case COMMAND_ENABLE_UXR:
798                 if (args.length != 2) {
799                     return showInvalidArguments(writer);
800                 }
801                 boolean enableBlocking = Boolean.valueOf(args[1]);
802                 if (mCarPackageManagerService != null) {
803                     mCarPackageManagerService.setEnableActivityBlocking(enableBlocking);
804                 }
805                 break;
806             case COMMAND_GET_DO_ACTIVITIES:
807                 if (args.length != 2) {
808                     return showInvalidArguments(writer);
809                 }
810                 String pkgName = args[1].toLowerCase();
811                 if (mCarPackageManagerService != null) {
812                     String[] doActivities =
813                             mCarPackageManagerService.getDistractionOptimizedActivities(
814                                     pkgName);
815                     if (doActivities != null) {
816                         writer.println("DO Activities for " + pkgName);
817                         for (String a : doActivities) {
818                             writer.println(a);
819                         }
820                     } else {
821                         writer.println("No DO Activities for " + pkgName);
822                     }
823                 }
824                 break;
825             case COMMAND_GET_CARPROPERTYCONFIG:
826                 String propertyId = args.length < 2 ? PARAM_ALL_PROPERTIES_OR_AREA : args[1];
827                 mHal.dumpPropertyConfigs(writer, Integer.decode(propertyId));
828                 break;
829             case COMMAND_GET_PROPERTY_VALUE:
830                 String propId = args.length < 2 ? PARAM_ALL_PROPERTIES_OR_AREA : args[1];
831                 String areaId = args.length < 3 ? PARAM_ALL_PROPERTIES_OR_AREA : args[2];
832                 mHal.dumpPropertyValueByCommend(writer, Integer.decode(propId),
833                         Integer.decode(areaId));
834                 break;
835             case COMMAND_PROJECTION_UI_MODE:
836                 if (args.length != 2) {
837                     return showInvalidArguments(writer);
838                 }
839                 mCarProjectionService.setUiMode(Integer.valueOf(args[1]));
840                 break;
841             case COMMAND_PROJECTION_AP_TETHERING:
842                 if (args.length != 2) {
843                     return showInvalidArguments(writer);
844                 }
845                 mCarProjectionService.setAccessPointTethering(Boolean.valueOf(args[1]));
846                 break;
847             case COMMAND_RESUME:
848                 mCarPowerManagementService.forceSimulatedResume();
849                 writer.println("Resume: Simulating resuming from Deep Sleep");
850                 break;
851             case COMMAND_SUSPEND:
852                 mCarPowerManagementService.forceSuspendAndMaybeReboot(false);
853                 writer.println("Suspend: Simulating powering down to Deep Sleep");
854                 break;
855             case COMMAND_SET_UID_TO_ZONE:
856                 if (args.length != 3) {
857                     return showInvalidArguments(writer);
858                 }
859                 runSetZoneIdForUid(args[1], args[2]);
860                 break;
861             case COMMAND_RESET_VOLUME_CONTEXT:
862                 if (args.length > 1) {
863                     return showInvalidArguments(writer);
864                 }
865                 runResetSelectedVolumeContext();
866                 break;
867             case COMMAND_SET_MUTE_CAR_VOLUME_GROUP:
868                 if (args.length != 4) {
869                     return showInvalidArguments(writer);
870                 }
871                 runSetMuteCarVolumeGroup(args[1], args[2], args[3]);
872                 break;
873             case COMMAND_SET_GROUP_VOLUME:
874                 if (args.length != 4) {
875                     return showInvalidArguments(writer);
876                 }
877                 runSetGroupVolume(args[1], args[2], args[3]);
878                 break;
879             case COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE:
880                 if (args.length != 3) {
881                     return showInvalidArguments(writer);
882                 }
883                 runSetOccupantZoneIdForUserId(args[1], args[2]);
884                 break;
885             case COMMAND_SILENT_MODE: {
886                 String value = args.length < 2 ? ""
887                         : args.length == 2 ? args[1] : "too many arguments";
888                 runSilentCommand(value, writer);
889                 break;
890             }
891             case COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE:
892                 if (args.length != 2) {
893                     return showInvalidArguments(writer);
894                 }
895                 runResetOccupantZoneId(args[1]);
896                 break;
897             case COMMAND_START_FIXED_ACTIVITY_MODE:
898                 startFixedActivity(args, writer);
899                 break;
900             case COMMAND_STOP_FIXED_ACTIVITY_MODE:
901                 stopFixedMode(args, writer);
902                 break;
903             case COMMAND_ENABLE_FEATURE:
904                 if (args.length != 2) {
905                     return showInvalidArguments(writer);
906                 }
907                 enableDisableFeature(args, writer, /* enable= */ true);
908                 break;
909             case COMMAND_DISABLE_FEATURE:
910                 if (args.length != 2) {
911                     return showInvalidArguments(writer);
912                 }
913                 enableDisableFeature(args, writer, /* enable= */ false);
914                 break;
915             case COMMAND_INJECT_KEY:
916                 if (args.length < 2) {
917                     return showInvalidArguments(writer);
918                 }
919                 injectKey(args, writer);
920                 break;
921             case COMMAND_INJECT_ROTARY:
922                 if (args.length < 1) {
923                     return showInvalidArguments(writer);
924                 }
925                 injectRotary(args, writer);
926                 break;
927             case COMMAND_INJECT_CUSTOM_INPUT:
928                 if (args.length < 2) {
929                     return showInvalidArguments(writer);
930                 }
931                 injectCustomInputEvent(args, writer);
932                 break;
933             case COMMAND_GET_INITIAL_USER_INFO:
934                 getInitialUserInfo(args, writer);
935                 break;
936             case COMMAND_SWITCH_USER:
937                 switchUser(args, writer);
938                 break;
939             case COMMAND_REMOVE_USER:
940                 removeUser(args, writer);
941                 break;
942             case COMMAND_CREATE_USER:
943                 createUser(args, writer);
944                 break;
945             case COMMAND_GET_INITIAL_USER:
946                 getInitialUser(writer);
947                 break;
948             case COMMAND_GET_USER_AUTH_ASSOCIATION:
949                 getUserAuthAssociation(args, writer);
950                 break;
951             case COMMAND_SET_USER_AUTH_ASSOCIATION:
952                 setUserAuthAssociation(args, writer);
953                 break;
954             case COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE:
955                 setStartBackgroundUsersOnGarageMode(args, writer);
956                 break;
957             case COMMAND_EMULATE_DRIVING_STATE:
958                 emulateDrivingState(args, writer);
959                 break;
960             case COMMAND_DEFINE_POWER_POLICY:
961                 return definePowerPolicy(args, writer);
962             case COMMAND_APPLY_POWER_POLICY:
963                 return applyPowerPolicy(args, writer);
964             case COMMAND_DEFINE_POWER_POLICY_GROUP:
965                 return definePowerPolicyGroup(args, writer);
966             case COMMAND_SET_POWER_POLICY_GROUP:
967                 return setPowerPolicyGroup(args, writer);
968             case COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY:
969                 return applyCtsVerifierPowerOffPolicy(args, writer);
970             case COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY:
971                 return applyCtsVerifierPowerOnPolicy(args, writer);
972             case COMMAND_POWER_OFF:
973                 powerOff(args, writer);
974                 break;
975             case COMMAND_SET_REARVIEW_CAMERA_ID:
976                 setRearviewCameraId(args, writer);
977                 break;
978             case COMMAND_GET_REARVIEW_CAMERA_ID:
979                 getRearviewCameraId(writer);
980                 break;
981             case COMMAND_WATCHDOG_CONTROL_PACKAGE_KILLABLE_STATE:
982                 controlWatchdogPackageKillableState(args, writer);
983                 break;
984             case COMMAND_WATCHDOG_IO_SET_3P_FOREGROUND_BYTES:
985                 setWatchdogIoThirdPartyForegroundBytes(args, writer);
986                 break;
987             case COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES:
988                 getWatchdogIoThirdPartyForegroundBytes(writer);
989                 break;
990             case COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK:
991                 controlWatchdogProcessHealthCheck(args, writer);
992                 break;
993             case COMMAND_DRIVING_SAFETY_SET_REGION:
994                 setDrivingSafetyRegion(args, writer);
995                 break;
996             default:
997                 writer.println("Unknown command: \"" + cmd + "\"");
998                 showHelp(writer);
999                 return RESULT_ERROR;
1000         }
1001         return RESULT_OK;
1002     }
1003 
1004     private void setStartBackgroundUsersOnGarageMode(String[] args, IndentingPrintWriter writer) {
1005         if (args.length < 2) {
1006             writer.println("Insufficient number of args");
1007             return;
1008         }
1009 
1010         boolean enabled = Boolean.parseBoolean(args[1]);
1011         Slog.d(TAG, "setStartBackgroundUsersOnGarageMode(): " + (enabled ? "enabled" : "disabled"));
1012         mCarUserService.setStartBackgroundUsersOnGarageMode(enabled);
1013         writer.printf("StartBackgroundUsersOnGarageMode set to %b\n", enabled);
1014     }
1015 
1016     private void startFixedActivity(String[] args, IndentingPrintWriter writer) {
1017         if (args.length != 4) {
1018             writer.println("Incorrect number of arguments");
1019             showHelp(writer);
1020             return;
1021         }
1022         int displayId;
1023         try {
1024             displayId = Integer.parseInt(args[1]);
1025         } catch (NumberFormatException e) {
1026             writer.println("Wrong display id:" + args[1]);
1027             return;
1028         }
1029         String packageName = args[2];
1030         String activityName = args[3];
1031         Intent intent = new Intent();
1032         intent.setComponent(new ComponentName(packageName, activityName));
1033         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1034         ActivityOptions options = ActivityOptions.makeBasic();
1035         options.setLaunchDisplayId(displayId);
1036         if (!mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
1037                 displayId, ActivityManager.getCurrentUser())) {
1038             writer.println("Failed to start");
1039             return;
1040         }
1041         writer.println("Succeeded");
1042     }
1043 
1044     private void stopFixedMode(String[] args, IndentingPrintWriter writer) {
1045         if (args.length != 2) {
1046             writer.println("Incorrect number of arguments");
1047             showHelp(writer);
1048             return;
1049         }
1050         int displayId;
1051         try {
1052             displayId = Integer.parseInt(args[1]);
1053         } catch (NumberFormatException e) {
1054             writer.println("Wrong display id:" + args[1]);
1055             return;
1056         }
1057         mFixedActivityService.stopFixedActivityMode(displayId);
1058     }
1059 
1060     private void enableDisableFeature(String[] args, IndentingPrintWriter writer, boolean enable) {
1061         if (Binder.getCallingUid() != Process.ROOT_UID) {
1062             writer.println("Only allowed to root/su");
1063             return;
1064         }
1065         String featureName = args[1];
1066         long id = Binder.clearCallingIdentity();
1067         // no permission check here
1068         int r;
1069         if (enable) {
1070             r = mFeatureController.enableFeature(featureName);
1071         } else {
1072             r = mFeatureController.disableFeature(featureName);
1073         }
1074         switch (r) {
1075             case Car.FEATURE_REQUEST_SUCCESS:
1076                 if (enable) {
1077                     writer.println("Enabled feature:" + featureName);
1078                 } else {
1079                     writer.println("Disabled feature:" + featureName);
1080                 }
1081                 break;
1082             case Car.FEATURE_REQUEST_ALREADY_IN_THE_STATE:
1083                 if (enable) {
1084                     writer.println("Already enabled:" + featureName);
1085                 } else {
1086                     writer.println("Already disabled:" + featureName);
1087                 }
1088                 break;
1089             case Car.FEATURE_REQUEST_MANDATORY:
1090                 writer.println("Cannot change mandatory feature:" + featureName);
1091                 break;
1092             case Car.FEATURE_REQUEST_NOT_EXISTING:
1093                 writer.println("Non-existing feature:" + featureName);
1094                 break;
1095             default:
1096                 writer.println("Unknown error:" + r);
1097                 break;
1098         }
1099         Binder.restoreCallingIdentity(id);
1100     }
1101 
1102     private void injectKey(String[] args, IndentingPrintWriter writer) {
1103         int i = 1; // 0 is command itself
1104         int display = CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
1105         int delayMs = 0;
1106         int keyCode = KeyEvent.KEYCODE_UNKNOWN;
1107         int action = -1;
1108         try {
1109             while (i < args.length) {
1110                 switch (args[i]) {
1111                     case "-d":
1112                         i++;
1113                         int vehicleDisplay = Integer.parseInt(args[i]);
1114                         if (!checkVehicleDisplay(vehicleDisplay, writer)) {
1115                             return;
1116                         }
1117                         display = InputHalService.convertDisplayType(vehicleDisplay);
1118                         break;
1119                     case "-t":
1120                         i++;
1121                         delayMs = Integer.parseInt(args[i]);
1122                         break;
1123                     case "-a":
1124                         i++;
1125                         if (args[i].equalsIgnoreCase("down")) {
1126                             action = KeyEvent.ACTION_DOWN;
1127                         } else if (args[i].equalsIgnoreCase("up")) {
1128                             action = KeyEvent.ACTION_UP;
1129                         } else {
1130                             throw new IllegalArgumentException("Invalid action: " + args[i]);
1131                         }
1132                         break;
1133                     default:
1134                         if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
1135                             throw new IllegalArgumentException("key_code already set:"
1136                                     + keyCode);
1137                         }
1138                         keyCode = Integer.parseInt(args[i]);
1139                 }
1140                 i++;
1141             }
1142         } catch (NumberFormatException e) {
1143             writer.println("Invalid args:" + e);
1144             showHelp(writer);
1145             return;
1146         }
1147         if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
1148             writer.println("Missing key code or invalid keycode");
1149             showHelp(writer);
1150             return;
1151         }
1152         if (delayMs < 0) {
1153             writer.println("Invalid delay:" + delayMs);
1154             showHelp(writer);
1155 
1156             return;
1157         }
1158         if (action == -1) {
1159             injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, display);
1160             SystemClock.sleep(delayMs);
1161             injectKeyEvent(KeyEvent.ACTION_UP, keyCode, display);
1162         } else {
1163             injectKeyEvent(action, keyCode, display);
1164         }
1165         writer.println("Succeeded");
1166     }
1167 
1168     private void injectKeyEvent(int action, int keyCode, int display) {
1169         long currentTime = SystemClock.uptimeMillis();
1170         if (action == KeyEvent.ACTION_DOWN) mKeyDownTime = currentTime;
1171         long token = Binder.clearCallingIdentity();
1172         try {
1173             mCarInputService.injectKeyEvent(
1174                     new KeyEvent(/* downTime= */ mKeyDownTime, /* eventTime= */ currentTime,
1175                             action, keyCode, /* repeat= */ 0), display);
1176         } finally {
1177             Binder.restoreCallingIdentity(token);
1178         }
1179     }
1180 
1181     private void injectRotary(String[] args, IndentingPrintWriter writer) {
1182         int i = 1; // 0 is command itself
1183         int display = CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
1184         int inputType = CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION;
1185         boolean clockwise = false;
1186         List<Long> deltaTimeMs = new ArrayList<>();
1187         try {
1188             while (i < args.length) {
1189                 switch (args[i]) {
1190                     case "-d":
1191                         i++;
1192                         int vehicleDisplay = Integer.parseInt(args[i]);
1193                         if (!checkVehicleDisplay(vehicleDisplay, writer)) {
1194                             return;
1195                         }
1196                         display = InputHalService.convertDisplayType(vehicleDisplay);
1197                         break;
1198                     case "-i":
1199                         i++;
1200                         inputType = Integer.parseInt(args[i]);
1201                         break;
1202                     case "-c":
1203                         i++;
1204                         clockwise = Boolean.parseBoolean(args[i]);
1205                         break;
1206                     case "-dt":
1207                         i++;
1208                         while (i < args.length) {
1209                             deltaTimeMs.add(Long.parseLong(args[i]));
1210                             i++;
1211                         }
1212                         break;
1213                     default:
1214                         writer.println("Invalid option at index " + i + ": " + args[i]);
1215                         return;
1216                 }
1217                 i++;
1218             }
1219         } catch (NumberFormatException e) {
1220             writer.println("Invalid args:" + e);
1221             showHelp(writer);
1222             return;
1223         }
1224         if (deltaTimeMs.isEmpty()) {
1225             deltaTimeMs.add(0L);
1226         }
1227         for (int j = 0; j < deltaTimeMs.size(); j++) {
1228             if (deltaTimeMs.get(j) < 0) {
1229                 writer.println("Delta time shouldn't be negative: " + deltaTimeMs.get(j));
1230                 showHelp(writer);
1231                 return;
1232             }
1233             if (j > 0 && deltaTimeMs.get(j) > deltaTimeMs.get(j - 1)) {
1234                 writer.println("Delta times should be in descending order");
1235                 showHelp(writer);
1236                 return;
1237             }
1238         }
1239         long[] uptimeMs = new long[deltaTimeMs.size()];
1240         long currentUptime = SystemClock.uptimeMillis();
1241         for (int j = 0; j < deltaTimeMs.size(); j++) {
1242             uptimeMs[j] = currentUptime - deltaTimeMs.get(j);
1243         }
1244         RotaryEvent rotaryEvent = new RotaryEvent(inputType, clockwise, uptimeMs);
1245         mCarInputService.onRotaryEvent(rotaryEvent, display);
1246         writer.println("Succeeded in injecting: " + rotaryEvent);
1247     }
1248 
1249     private void injectCustomInputEvent(String[] args, IndentingPrintWriter writer) {
1250         int display = CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
1251         int repeatCounter = 1;
1252 
1253         int argIdx = 1;
1254         for (; argIdx < args.length - 1; argIdx++) {
1255             switch (args[argIdx]) {
1256                 case "-d":
1257                     int vehicleDisplay = Integer.parseInt(args[++argIdx]);
1258                     if (!checkVehicleDisplay(vehicleDisplay, writer)) {
1259                         return;
1260                     }
1261                     display = InputHalService.convertDisplayType(vehicleDisplay);
1262                     break;
1263                 case "-r":
1264                     repeatCounter = Integer.parseInt(args[++argIdx]);
1265                     break;
1266                 default:
1267                     writer.printf("Unrecognized argument: {%s}\n", args[argIdx]);
1268                     writer.println("Pass -help to see the full list of options");
1269                     return;
1270             }
1271         }
1272 
1273         if (argIdx == args.length) {
1274             writer.println("Last mandatory argument (fn) not passed.");
1275             writer.println("Pass -help to see the full list of options");
1276             return;
1277         }
1278 
1279         // Processing the last remaining argument (expected to be 'f1', 'f2', ..., 'f10').
1280         String eventValue = args[argIdx].toLowerCase();
1281         Integer inputCode = CUSTOM_INPUT_FUNCTION_ARGS.get(eventValue);
1282         if (inputCode == null) {
1283             writer.printf("Invalid input event value {%s}, valid values are f1, f2, ..., f10\n",
1284                     eventValue);
1285             writer.println("Pass -help to see the full list of options");
1286             return;
1287         }
1288 
1289         CustomInputEvent event = new CustomInputEvent(inputCode, display, repeatCounter);
1290         mCarInputService.onCustomInputEvent(event);
1291         writer.printf("Succeeded in injecting {%s}\n", event);
1292     }
1293 
1294     private boolean checkVehicleDisplay(int vehicleDisplay, IndentingPrintWriter writer) {
1295         if (vehicleDisplay != VehicleDisplay.MAIN
1296                 && vehicleDisplay != VehicleDisplay.INSTRUMENT_CLUSTER) {
1297             writer.println("Invalid display:" + vehicleDisplay);
1298             showHelp(writer);
1299             return false;
1300         }
1301         return true;
1302     }
1303 
1304     private void getInitialUserInfo(String[] args, IndentingPrintWriter writer) {
1305         if (args.length < 2) {
1306             writer.println("Insufficient number of args");
1307             return;
1308         }
1309 
1310         // Gets the request type
1311         String typeArg = args[1];
1312         int requestType = UserHalHelper.parseInitialUserInfoRequestType(typeArg);
1313 
1314         int timeout = DEFAULT_HAL_TIMEOUT_MS;
1315         for (int i = 2; i < args.length; i++) {
1316             String arg = args[i];
1317             switch (arg) {
1318                 case "--timeout":
1319                     timeout = Integer.parseInt(args[++i]);
1320                     break;
1321                 default:
1322                     writer.println("Invalid option at index " + i + ": " + arg);
1323                     return;
1324 
1325             }
1326         }
1327 
1328         Slog.d(TAG, "handleGetInitialUserInfo(): type=" + requestType + " (" + typeArg
1329                 + "), timeout=" + timeout);
1330 
1331         CountDownLatch latch = new CountDownLatch(1);
1332         HalCallback<InitialUserInfoResponse> callback = (status, resp) -> {
1333             try {
1334                 Slog.d(TAG, "GetUserInfoResponse: status=" + status + ", resp=" + resp);
1335                 writer.printf("Call status: %s\n",
1336                         UserHalHelper.halCallbackStatusToString(status));
1337                 if (status != HalCallback.STATUS_OK) {
1338                     return;
1339                 }
1340                 writer.printf("Request id: %d\n", resp.requestId);
1341                 writer.printf("Action: %s\n",
1342                         InitialUserInfoResponseAction.toString(resp.action));
1343                 if (!TextUtils.isEmpty(resp.userNameToCreate)) {
1344                     writer.printf("User name: %s\n", resp.userNameToCreate);
1345                 }
1346                 if (resp.userToSwitchOrCreate.userId != UserHandle.USER_NULL) {
1347                     writer.printf("User id: %d\n", resp.userToSwitchOrCreate.userId);
1348                 }
1349                 if (resp.userToSwitchOrCreate.flags != UserFlags.NONE) {
1350                     writer.printf("User flags: %s\n",
1351                             UserHalHelper.userFlagsToString(resp.userToSwitchOrCreate.flags));
1352                 }
1353                 if (!TextUtils.isEmpty(resp.userLocales)) {
1354                     writer.printf("User locales: %s\n", resp.userLocales);
1355                 }
1356             } finally {
1357                 latch.countDown();
1358             }
1359         };
1360         UsersInfo usersInfo = generateUsersInfo();
1361         mHal.getUserHal().getInitialUserInfo(requestType, timeout, usersInfo, callback);
1362         waitForHal(writer, latch, timeout);
1363     }
1364 
1365     private UsersInfo generateUsersInfo() {
1366         return UserHalHelper.newUsersInfo(UserManager.get(mContext));
1367     }
1368 
1369     private int getUserHalFlags(@UserIdInt int userId) {
1370         return UserHalHelper.getFlags(UserManager.get(mContext), userId);
1371     }
1372 
1373     private static void waitForHal(IndentingPrintWriter writer, CountDownLatch latch,
1374             int timeoutMs) {
1375         try {
1376             if (!latch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
1377                 writer.printf("HAL didn't respond in %dms\n", timeoutMs);
1378             }
1379         } catch (InterruptedException e) {
1380             Thread.currentThread().interrupt();
1381             writer.println("Interrupted waiting for HAL");
1382         }
1383         return;
1384     }
1385 
1386     private void switchUser(String[] args, IndentingPrintWriter writer) {
1387         if (args.length < 2) {
1388             writer.println("Insufficient number of args");
1389             return;
1390         }
1391 
1392         int targetUserId = Integer.parseInt(args[1]);
1393         int timeout = DEFAULT_HAL_TIMEOUT_MS + DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS;
1394         boolean halOnly = false;
1395 
1396         for (int i = 2; i < args.length; i++) {
1397             String arg = args[i];
1398             switch (arg) {
1399                 case "--timeout":
1400                     timeout = Integer.parseInt(args[++i]);
1401                     break;
1402                 case "--hal-only":
1403                     halOnly = true;
1404                     break;
1405                 default:
1406                     writer.println("Invalid option at index " + i + ": " + arg);
1407                     return;
1408             }
1409         }
1410 
1411         Slog.d(TAG, "switchUser(): target=" + targetUserId + ", halOnly=" + halOnly
1412                 + ", timeout=" + timeout);
1413 
1414         if (halOnly) {
1415             CountDownLatch latch = new CountDownLatch(1);
1416             UserHalService userHal = mHal.getUserHal();
1417             UserInfo targetUserInfo = new UserInfo();
1418             targetUserInfo.userId = targetUserId;
1419             targetUserInfo.flags = getUserHalFlags(targetUserId);
1420 
1421             SwitchUserRequest request = new SwitchUserRequest();
1422             request.targetUser = targetUserInfo;
1423             request.usersInfo = generateUsersInfo();
1424 
1425             userHal.switchUser(request, timeout, (status, resp) -> {
1426                 try {
1427                     Slog.d(TAG, "SwitchUserResponse: status=" + status + ", resp=" + resp);
1428                     writer.printf("Call Status: %s\n",
1429                             UserHalHelper.halCallbackStatusToString(status));
1430                     if (status != HalCallback.STATUS_OK) {
1431                         return;
1432                     }
1433                     writer.printf("Request id: %d\n", resp.requestId);
1434                     writer.printf("Message type: %s\n",
1435                             SwitchUserMessageType.toString(resp.messageType));
1436                     writer.printf("Switch Status: %s\n", SwitchUserStatus.toString(resp.status));
1437                     String errorMessage = resp.errorMessage;
1438                     if (!TextUtils.isEmpty(errorMessage)) {
1439                         writer.printf("Error message: %s", errorMessage);
1440                     }
1441                     // If HAL returned OK, make a "post-switch" call to the HAL indicating an
1442                     // Android error. This is to "rollback" the HAL switch.
1443                     if (status == HalCallback.STATUS_OK
1444                             && resp.status == SwitchUserStatus.SUCCESS) {
1445                         userHal.postSwitchResponse(request);
1446                     }
1447                 } finally {
1448                     latch.countDown();
1449                 }
1450             });
1451             waitForHal(writer, latch, timeout);
1452             return;
1453         }
1454         CarUserManager carUserManager = getCarUserManager(mContext);
1455         AsyncFuture<UserSwitchResult> future = carUserManager.switchUser(targetUserId);
1456         UserSwitchResult result = waitForFuture(writer, future, timeout);
1457         if (result == null) return;
1458         writer.printf("UserSwitchResult: status=%s",
1459                 UserSwitchResult.statusToString(result.getStatus()));
1460         String msg = result.getErrorMessage();
1461         if (!TextUtils.isEmpty(msg)) {
1462             writer.printf(", errorMessage=%s", msg);
1463         }
1464         writer.println();
1465     }
1466 
1467     private void createUser(String[] args, IndentingPrintWriter writer) {
1468         int timeout = DEFAULT_HAL_TIMEOUT_MS + DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS;
1469         int flags = 0;
1470         boolean halOnly = false;
1471         String name = null;
1472         String userType = null;
1473 
1474         for (int i = 1; i < args.length; i++) {
1475             String arg = args[i];
1476             switch (arg) {
1477                 case "--timeout":
1478                     timeout = Integer.parseInt(args[++i]);
1479                     break;
1480                 case "--hal-only":
1481                     halOnly = true;
1482                     break;
1483                 case "--flags":
1484                     flags = Integer.parseInt(args[++i]);
1485                     break;
1486                 case "--type":
1487                     userType = args[++i];
1488                     break;
1489                 default:
1490                     if (name != null) {
1491                         writer.println("Invalid option at index " + i + ": " + arg);
1492                         return;
1493                     }
1494                     name = arg;
1495             }
1496         }
1497 
1498         if (userType == null) {
1499             userType = android.content.pm.UserInfo.getDefaultUserType(flags);
1500         }
1501 
1502         Slog.d(TAG, "createUser(): name=" + name + ", userType=" + userType
1503                 + ", flags=" + android.content.pm.UserInfo.flagsToString(flags)
1504                 + ", halOnly=" + halOnly + ", timeout=" + timeout);
1505 
1506         if (!halOnly) {
1507             CarUserManager carUserManager = getCarUserManager(mContext);
1508             AsyncFuture<UserCreationResult> future = carUserManager
1509                     .createUser(name, userType, flags);
1510 
1511             UserCreationResult result = waitForFuture(writer, future, timeout);
1512             if (result == null) return;
1513 
1514             android.content.pm.UserInfo user = result.getUser();
1515             writer.printf("UserCreationResult: status=%s, user=%s",
1516                     UserCreationResult.statusToString(result.getStatus()),
1517                     user == null ? "N/A" : user.toFullString());
1518             String msg = result.getErrorMessage();
1519             if (!TextUtils.isEmpty(msg)) {
1520                 writer.printf(", errorMessage=%s", msg);
1521             }
1522             writer.println();
1523             return;
1524         }
1525 
1526         CountDownLatch latch = new CountDownLatch(1);
1527         UserHalService userHal = mHal.getUserHal();
1528 
1529         CreateUserRequest request = new CreateUserRequest();
1530 
1531         UserManager um = UserManager.get(mContext);
1532         android.content.pm.UserInfo newUser = um.createUser(name, userType, flags);
1533         if (newUser == null) {
1534             writer.printf("Failed to create user");
1535             return;
1536         }
1537         writer.printf("New user: %s\n", newUser.toFullString());
1538         Slog.i(TAG, "Created new user: " + newUser.toFullString());
1539 
1540         request.newUserInfo.userId = newUser.id;
1541         request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
1542 
1543         request.usersInfo = generateUsersInfo();
1544 
1545         AtomicBoolean halOk = new AtomicBoolean(false);
1546         try {
1547             userHal.createUser(request, timeout, (status, resp) -> {
1548                 Slog.d(TAG, "CreateUserResponse: status=" + status + ", resp=" + resp);
1549                 writer.printf("Call Status: %s\n",
1550                         UserHalHelper.halCallbackStatusToString(status));
1551                 if (status == HalCallback.STATUS_OK) {
1552                     halOk.set(resp.status == CreateUserStatus.SUCCESS);
1553                     writer.printf("Request id: %d\n", resp.requestId);
1554                     writer.printf("Create Status: %s\n", CreateUserStatus.toString(resp.status));
1555                     String errorMessage = resp.errorMessage;
1556                     if (!TextUtils.isEmpty(errorMessage)) {
1557                         writer.printf("Error message: %s", errorMessage);
1558                     }
1559                 }
1560                 latch.countDown();
1561             });
1562             waitForHal(writer, latch, timeout);
1563         } catch (RuntimeException e) {
1564             writer.printf("HAL failed: %s\n", e);
1565         } finally {
1566             if (!halOk.get()) {
1567                 writer.printf("Removing user %d due to HAL failure\n", newUser.id);
1568                 boolean removed = um.removeUser(newUser.id);
1569                 writer.printf("User removed: %b\n", removed);
1570             }
1571         }
1572     }
1573 
1574     private void removeUser(String[] args, IndentingPrintWriter writer) {
1575         if (args.length < 2) {
1576             writer.println("Insufficient number of args");
1577             return;
1578         }
1579 
1580         int userId = Integer.parseInt(args[1]);
1581         boolean halOnly = false;
1582 
1583         for (int i = 2; i < args.length; i++) {
1584             String arg = args[i];
1585             switch (arg) {
1586                 case "--hal-only":
1587                     halOnly = true;
1588                     break;
1589                 default:
1590                     writer.println("Invalid option at index " + i + ": " + arg);
1591                     return;
1592             }
1593         }
1594 
1595         Slog.d(TAG, "handleRemoveUser(): User to remove=" + userId + ", halOnly=" + halOnly);
1596 
1597         if (halOnly) {
1598             UserHalService userHal = mHal.getUserHal();
1599             UsersInfo usersInfo = generateUsersInfo();
1600             UserInfo userInfo = new UserInfo();
1601             userInfo.userId = userId;
1602             userInfo.flags = getUserHalFlags(userId);
1603 
1604             RemoveUserRequest request = new RemoveUserRequest();
1605             request.removedUserInfo = userInfo;
1606             request.usersInfo = usersInfo;
1607 
1608             userHal.removeUser(request);
1609             writer.printf("User removal sent for HAL only.\n");
1610             return;
1611         }
1612 
1613         CarUserManager carUserManager = getCarUserManager(mContext);
1614         UserRemovalResult result = carUserManager.removeUser(userId);
1615         writer.printf("UserRemovalResult: status = %s\n",
1616                 UserRemovalResult.statusToString(result.getStatus()));
1617     }
1618 
1619     private static <T> T waitForFuture(@NonNull IndentingPrintWriter writer,
1620             @NonNull AsyncFuture<T> future, int timeoutMs) {
1621         T result = null;
1622         try {
1623             result = future.get(timeoutMs, TimeUnit.MILLISECONDS);
1624             if (result == null) {
1625                 writer.printf("Service didn't respond in %d ms", timeoutMs);
1626             }
1627         } catch (InterruptedException e) {
1628             Thread.currentThread().interrupt();
1629         } catch (ExecutionException | TimeoutException e) {
1630             writer.printf("Exception getting future: %s",  e);
1631         }
1632         return result;
1633     }
1634 
1635     private void getInitialUser(IndentingPrintWriter writer) {
1636         UserHandle user = mCarUserService.getInitialUser();
1637         writer.println(user == null ? NO_INITIAL_USER : user.getIdentifier());
1638     }
1639 
1640     private void getUserAuthAssociation(String[] args, IndentingPrintWriter writer) {
1641         if (args.length < 2) {
1642             writer.println("invalid usage, must pass at least 1 argument");
1643             return;
1644         }
1645 
1646         boolean halOnly = false;
1647         int userId = UserHandle.USER_CURRENT;
1648 
1649         UserIdentificationGetRequest request = new UserIdentificationGetRequest();
1650         for (int i = 1; i < args.length; i++) {
1651             String arg = args[i];
1652             switch (arg) {
1653                 case "--user":
1654                     try {
1655                         userId = Integer.parseInt(args[++i]);
1656                     } catch (NumberFormatException e) {
1657                         writer.printf("Invalid user id at index %d (from %s): %s\n", i + 1,
1658                                 Arrays.toString(args), arg);
1659                     }
1660                     break;
1661                 case "--hal-only":
1662                     halOnly = true;
1663                     break;
1664                 default:
1665                     int type = parseAuthArg(VALID_USER_AUTH_TYPES, arg);
1666                     if (type == INVALID_USER_AUTH_TYPE_OR_VALUE) {
1667                         writer.printf("Invalid type at index %d (from %s): %s. %s\n", i + 1,
1668                                 Arrays.toString(args), arg, VALID_USER_AUTH_TYPES_HELP);
1669                         return;
1670                     }
1671                     request.associationTypes.add(type);
1672             }
1673 
1674         }
1675         if (userId == UserHandle.USER_CURRENT) {
1676             userId = ActivityManager.getCurrentUser();
1677         }
1678         int requestSize = request.associationTypes.size();
1679         if (halOnly) {
1680             request.numberAssociationTypes = requestSize;
1681             request.userInfo.userId = userId;
1682             request.userInfo.flags = getUserHalFlags(userId);
1683 
1684             Slog.d(TAG, "getUserAuthAssociation(): user=" + userId + ", halOnly=" + halOnly
1685                     + ", request=" + request);
1686             UserIdentificationResponse response = mHal.getUserHal().getUserAssociation(request);
1687             Slog.d(TAG, "getUserAuthAssociation(): response=" + response);
1688             showResponse(writer, response);
1689             return;
1690         }
1691 
1692         CarUserManager carUserManager = getCarUserManager(writer, userId);
1693         int[] types = new int[requestSize];
1694         for (int i = 0; i < requestSize; i++) {
1695             types[i] = request.associationTypes.get(i);
1696         }
1697         UserIdentificationAssociationResponse response = carUserManager
1698                 .getUserIdentificationAssociation(types);
1699         showResponse(writer, response);
1700     }
1701 
1702     private CarUserManager getCarUserManager(@NonNull IndentingPrintWriter writer,
1703             @UserIdInt int userId) {
1704         Context context;
1705         if (userId == mContext.getUserId()) {
1706             context = mContext;
1707         } else {
1708             context = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
1709         }
1710         int actualUserId = Binder.getCallingUid();
1711         if (actualUserId != userId) {
1712             writer.printf("Emulating call for user id %d, but caller's user id is %d, so that's "
1713                     + "what CarUserService will use when calling HAL.\n", userId, actualUserId);
1714         }
1715 
1716         return getCarUserManager(context);
1717     }
1718 
1719     private CarUserManager getCarUserManager(@NonNull Context context) {
1720         Car car = Car.createCar(context);
1721         CarUserManager carUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
1722         return carUserManager;
1723     }
1724 
1725     private void showResponse(@NonNull IndentingPrintWriter writer,
1726             @NonNull UserIdentificationResponse response) {
1727         if (response == null) {
1728             writer.println("null response");
1729             return;
1730         }
1731 
1732         if (!TextUtils.isEmpty(response.errorMessage)) {
1733             writer.printf("Error message: %s\n", response.errorMessage);
1734         }
1735         int numberAssociations = response.associations.size();
1736         writer.printf("%d associations:\n", numberAssociations);
1737         for (int i = 0; i < numberAssociations; i++) {
1738             UserIdentificationAssociation association = response.associations.get(i);
1739             writer.printf("  %s\n", association);
1740         }
1741     }
1742 
1743     private void showResponse(@NonNull IndentingPrintWriter writer,
1744             @NonNull UserIdentificationAssociationResponse response) {
1745         if (response == null) {
1746             writer.println("null response");
1747             return;
1748         }
1749         if (!response.isSuccess()) {
1750             writer.printf("failed response: %s\n", response);
1751             return;
1752         }
1753         String errorMessage = response.getErrorMessage();
1754         if (!TextUtils.isEmpty(errorMessage)) {
1755             writer.printf("Error message: %s\n", errorMessage);
1756         }
1757         int[] values = response.getValues();
1758         if (values == null) {
1759             writer.printf("no associations on %s\n", response);
1760             return;
1761         }
1762         writer.printf("%d associations:\n", values.length);
1763         for (int i = 0; i < values.length; i++) {
1764             writer.printf("  %s\n", UserIdentificationAssociationValue.toString(values[i]));
1765         }
1766     }
1767 
1768     private void setUserAuthAssociation(String[] args, IndentingPrintWriter writer) {
1769         if (args.length < 3) {
1770             writer.println("invalid usage, must pass at least 4 arguments");
1771             return;
1772         }
1773 
1774         boolean halOnly = false;
1775         int timeout = DEFAULT_HAL_TIMEOUT_MS;
1776         int userId = UserHandle.USER_CURRENT;
1777 
1778         UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1779         for (int i = 1; i < args.length; i++) {
1780             String arg = args[i];
1781             switch (arg) {
1782                 case "--user":
1783                     try {
1784                         userId = Integer.parseInt(args[++i]);
1785                     } catch (NumberFormatException e) {
1786                         writer.printf("Invalid user id at index %d (from %s): %s\n", i + 1,
1787                                 Arrays.toString(args), arg);
1788                     }
1789                     break;
1790                 case "--hal-only":
1791                     halOnly = true;
1792                     break;
1793                 case "--timeout":
1794                     timeout = Integer.parseInt(args[++i]);
1795                     break;
1796                 default:
1797                     UserIdentificationSetAssociation association =
1798                             new UserIdentificationSetAssociation();
1799                     association.type = parseAuthArg(VALID_USER_AUTH_TYPES, arg);
1800                     if (association.type == INVALID_USER_AUTH_TYPE_OR_VALUE) {
1801                         writer.printf("Invalid type at index %d (from %s): %s. %s\n", i + 1,
1802                                 Arrays.toString(args), arg, VALID_USER_AUTH_TYPES_HELP);
1803                         return;
1804                     }
1805                     association.value = parseAuthArg(VALID_USER_AUTH_SET_VALUES, args[++i]);
1806                     if (association.value == INVALID_USER_AUTH_TYPE_OR_VALUE) {
1807                         writer.printf("Invalid value at index %d (from %s): %s. %s\n", i + 1,
1808                                 Arrays.toString(args), arg, VALID_USER_AUTH_SET_VALUES_HELP);
1809                         return;
1810                     }
1811                     request.associations.add(association);
1812             }
1813 
1814         }
1815         if (userId == UserHandle.USER_CURRENT) {
1816             userId = ActivityManager.getCurrentUser();
1817         }
1818         int requestSize = request.associations.size();
1819         if (halOnly) {
1820             request.numberAssociations = requestSize;
1821             request.userInfo.userId = userId;
1822             request.userInfo.flags = getUserHalFlags(userId);
1823 
1824             Slog.d(TAG, "setUserAuthAssociation(): user=" + userId + ", halOnly=" + halOnly
1825                     + ", request=" + request);
1826             CountDownLatch latch = new CountDownLatch(1);
1827             mHal.getUserHal().setUserAssociation(timeout, request, (status, response) -> {
1828                 Slog.d(TAG, "setUserAuthAssociation(): response=" + response);
1829                 try {
1830                     showResponse(writer, response);
1831                 } finally {
1832                     latch.countDown();
1833                 }
1834             });
1835             waitForHal(writer, latch, timeout);
1836             return;
1837         }
1838         CarUserManager carUserManager = getCarUserManager(writer, userId);
1839         int[] types = new int[requestSize];
1840         int[] values = new int[requestSize];
1841         for (int i = 0; i < requestSize; i++) {
1842             UserIdentificationSetAssociation association = request.associations.get(i);
1843             types[i] = association.type;
1844             values[i] = association.value;
1845         }
1846         AsyncFuture<UserIdentificationAssociationResponse> future = carUserManager
1847                 .setUserIdentificationAssociation(types, values);
1848         UserIdentificationAssociationResponse response = waitForFuture(writer, future, timeout);
1849         if (response != null) {
1850             showResponse(writer, response);
1851         }
1852     }
1853 
1854     private static int parseAuthArg(@NonNull SparseArray<String> types, @NonNull String type) {
1855         for (int i = 0; i < types.size(); i++) {
1856             if (types.valueAt(i).equals(type)) {
1857                 return types.keyAt(i);
1858             }
1859         }
1860         return INVALID_USER_AUTH_TYPE_OR_VALUE;
1861     }
1862 
1863     private void forceDayNightMode(String arg, IndentingPrintWriter writer) {
1864         int mode;
1865         switch (arg) {
1866             case PARAM_DAY_MODE:
1867                 mode = CarNightService.FORCED_DAY_MODE;
1868                 break;
1869             case PARAM_NIGHT_MODE:
1870                 mode = CarNightService.FORCED_NIGHT_MODE;
1871                 break;
1872             case PARAM_SENSOR_MODE:
1873                 mode = CarNightService.FORCED_SENSOR_MODE;
1874                 break;
1875             default:
1876                 writer.printf("Unknown value: %s. Valid argument: %s|%s|%s\n",
1877                         arg, PARAM_DAY_MODE, PARAM_NIGHT_MODE, PARAM_SENSOR_MODE);
1878                 return;
1879         }
1880         int current = mCarNightService.forceDayNightMode(mode);
1881         String currentMode = null;
1882         switch (current) {
1883             case UiModeManager.MODE_NIGHT_AUTO:
1884                 currentMode = PARAM_SENSOR_MODE;
1885                 break;
1886             case UiModeManager.MODE_NIGHT_YES:
1887                 currentMode = PARAM_NIGHT_MODE;
1888                 break;
1889             case UiModeManager.MODE_NIGHT_NO:
1890                 currentMode = PARAM_DAY_MODE;
1891                 break;
1892         }
1893         writer.println("DayNightMode changed to: " + currentMode);
1894     }
1895 
1896     private void forceGarageMode(String arg, IndentingPrintWriter writer) {
1897         switch (arg) {
1898             case PARAM_ON_MODE:
1899                 mSystemInterface.setDisplayState(false);
1900                 mGarageModeService.forceStartGarageMode();
1901                 writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
1902                 break;
1903             case PARAM_OFF_MODE:
1904                 mSystemInterface.setDisplayState(true);
1905                 mGarageModeService.stopAndResetGarageMode();
1906                 writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
1907                 break;
1908             case PARAM_QUERY_MODE:
1909                 mGarageModeService.dump(writer);
1910                 break;
1911             case PARAM_REBOOT:
1912                 mCarPowerManagementService.forceSuspendAndMaybeReboot(true);
1913                 writer.println("Entering Garage Mode. Will reboot when it completes.");
1914                 break;
1915             default:
1916                 writer.printf("Unknown value: %s. Valid argument: %s|%s|%s|%s\n",
1917                         arg, PARAM_ON_MODE, PARAM_OFF_MODE, PARAM_QUERY_MODE, PARAM_REBOOT);
1918         }
1919     }
1920 
1921     private void runSilentCommand(String arg, IndentingPrintWriter writer) {
1922         switch (arg) {
1923             case SILENT_MODE_FORCED_SILENT:
1924                 writer.println("Forcing silent mode to silent");
1925                 mCarPowerManagementService.setSilentMode(SILENT_MODE_FORCED_SILENT);
1926                 break;
1927             case SILENT_MODE_FORCED_NON_SILENT:
1928                 writer.println("Forcing silent mode to non-silent");
1929                 mCarPowerManagementService.setSilentMode(SILENT_MODE_FORCED_NON_SILENT);
1930                 break;
1931             case SILENT_MODE_NON_FORCED:
1932                 writer.println("Not forcing silent mode");
1933                 mCarPowerManagementService.setSilentMode(SILENT_MODE_NON_FORCED);
1934                 break;
1935             case PARAM_QUERY_MODE:
1936                 mCarPowerManagementService.dumpSilentMode(writer);
1937                 break;
1938             default:
1939                 writer.printf("Unknown value: %s. Valid argument: %s|%s|%s|%s\n", arg,
1940                         SILENT_MODE_FORCED_SILENT, SILENT_MODE_FORCED_NON_SILENT,
1941                         SILENT_MODE_NON_FORCED, PARAM_QUERY_MODE);
1942         }
1943     }
1944 
1945     private void emulateDrivingState(String[] args, IndentingPrintWriter writer) {
1946         if (args.length != 2) {
1947             writer.println("invalid usage, must pass driving state");
1948             return;
1949         }
1950         String mode = args[1];
1951         switch (mode) {
1952             case DRIVING_STATE_DRIVE:
1953                 emulateDrive();
1954                 break;
1955             case DRIVING_STATE_PARK:
1956                 emulatePark();
1957                 break;
1958             case DRIVING_STATE_REVERSE:
1959                 emulateReverse();
1960                 break;
1961             default:
1962                 writer.printf("invalid driving mode %s; must be %s or %s\n", mode,
1963                         DRIVING_STATE_DRIVE, DRIVING_STATE_PARK);
1964         }
1965     }
1966 
1967     /**
1968      * Emulates driving mode. Called by
1969      * {@code adb shell cmd car_service emulate-driving-state drive}.
1970      */
1971     private void emulateDrive() {
1972         Slog.i(TAG, "Emulating driving mode (speed=80mph, gear=8)");
1973         mHal.injectVhalEvent(VehiclePropertyIds.PERF_VEHICLE_SPEED,
1974                 /* zone= */ 0, /* value= */ "80", /* delayTime= */ 2000);
1975         mHal.injectVhalEvent(VehiclePropertyIds.GEAR_SELECTION,
1976                 /* zone= */ 0, Integer.toString(VehicleGear.GEAR_8), /* delayTime= */ 0);
1977         mHal.injectVhalEvent(VehiclePropertyIds.PARKING_BRAKE_ON,
1978                 /* zone= */ 0, /* value= */ "false", /* delayTime= */ 0);
1979     }
1980 
1981     /**
1982      * Emulates reverse driving mode. Called by
1983      * {@code adb shell cmd car_service emulate-driving-state reverse}.
1984      */
1985     private void emulateReverse() {
1986         Slog.i(TAG, "Emulating reverse driving mode (speed=5mph)");
1987         mHal.injectVhalEvent(VehiclePropertyIds.PERF_VEHICLE_SPEED,
1988                 /* zone= */ 0, /* value= */ "5", /* delayTime= */ 2000);
1989         mHal.injectVhalEvent(VehiclePropertyIds.GEAR_SELECTION,
1990                 /* zone= */ 0, Integer.toString(VehicleGear.GEAR_REVERSE), /* delayTime= */ 0);
1991         mHal.injectVhalEvent(VehiclePropertyIds.PARKING_BRAKE_ON,
1992                 /* zone= */ 0, /* value= */ "false", /* delayTime= */ 0);
1993     }
1994 
1995     /**
1996      * Emulates parking mode. Called by
1997      * {@code adb shell cmd car_service emulate-driving-state park}.
1998      */
1999     private void emulatePark() {
2000         Slog.i(TAG, "Emulating parking mode");
2001         mHal.injectVhalEvent(VehiclePropertyIds.PERF_VEHICLE_SPEED,
2002                 /* zone= */ 0, /* value= */ "0", /* delayTime= */ 0);
2003         mHal.injectVhalEvent(VehiclePropertyIds.GEAR_SELECTION,
2004                 /* zone= */ 0, Integer.toString(VehicleGear.GEAR_PARK), /* delayTime= */ 0);
2005     }
2006 
2007     private int definePowerPolicy(String[] args, IndentingPrintWriter writer) {
2008         boolean result = mCarPowerManagementService.definePowerPolicyFromCommand(args, writer);
2009         if (result) return RESULT_OK;
2010         writer.printf("\nUsage: cmd car_service %s <POLICY_ID> [--enable COMP1,COMP2,...] "
2011                 + "[--disable COMP1,COMP2,...]\n", COMMAND_DEFINE_POWER_POLICY);
2012         return RESULT_ERROR;
2013     }
2014 
2015     private int applyPowerPolicy(String[] args, IndentingPrintWriter writer) {
2016         boolean result = mCarPowerManagementService.applyPowerPolicyFromCommand(args, writer);
2017         if (result) return RESULT_OK;
2018         writer.printf("\nUsage: cmd car_service %s <POLICY_ID>\n", COMMAND_APPLY_POWER_POLICY);
2019         return RESULT_ERROR;
2020     }
2021 
2022     private int definePowerPolicyGroup(String[] args, IndentingPrintWriter writer) {
2023         boolean result = mCarPowerManagementService.definePowerPolicyGroupFromCommand(args, writer);
2024         if (result) return RESULT_OK;
2025         writer.printf("\nUsage: cmd car_service %s <POLICY_GROUP_ID> [%s:<POLICY_ID>] "
2026                 + "[%s:<POLICY_ID>]\n", COMMAND_DEFINE_POWER_POLICY_GROUP,
2027                 POWER_STATE_WAIT_FOR_VHAL, POWER_STATE_ON);
2028         return RESULT_ERROR;
2029     }
2030 
2031     private int setPowerPolicyGroup(String[] args, IndentingPrintWriter writer) {
2032         boolean result = mCarPowerManagementService.setPowerPolicyGroupFromCommand(args, writer);
2033         if (result) return RESULT_OK;
2034         writer.printf("\nUsage: cmd car_service %s <POLICY_GROUP_ID>\n",
2035                 COMMAND_SET_POWER_POLICY_GROUP);
2036         return RESULT_ERROR;
2037     }
2038 
2039     private int applyCtsVerifierPowerPolicy(String policyId, String ops, String cmdName,
2040             IndentingPrintWriter writer) {
2041         String[] defArgs = {"define-power-policy", policyId, ops, "WIFI,BLUETOOTH,LOCATION"};
2042         mCarPowerManagementService.definePowerPolicyFromCommand(defArgs, writer);
2043 
2044         String[] appArgs = {"apply-power-policy", policyId};
2045         boolean result = mCarPowerManagementService.applyPowerPolicyFromCommand(appArgs, writer);
2046         if (result) return RESULT_OK;
2047 
2048         writer.printf("\nUsage: cmd car_service %s\n", cmdName);
2049         return RESULT_ERROR;
2050     }
2051 
2052     private int applyCtsVerifierPowerOffPolicy(String[] unusedArgs, IndentingPrintWriter writer) {
2053         return applyCtsVerifierPowerPolicy("cts_verifier_off", "--disable",
2054                 COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY, writer);
2055     }
2056 
2057     private int applyCtsVerifierPowerOnPolicy(String[] unusedArgs, IndentingPrintWriter writer) {
2058         return applyCtsVerifierPowerPolicy("cts_verifier_on", "--enable",
2059                 COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY, writer);
2060     }
2061 
2062     private void powerOff(String[] args, IndentingPrintWriter writer) {
2063         int index = 1;
2064         boolean skipGarageMode = false;
2065         boolean shutdown = false;
2066         while (index < args.length) {
2067             switch (args[index]) {
2068                 case POWER_OFF_SKIP_GARAGEMODE:
2069                     skipGarageMode = true;
2070                     break;
2071                 case POWER_OFF_SHUTDOWN:
2072                     shutdown = true;
2073                     break;
2074                 default:
2075                     writer.printf("Not supported option: %s\n", args[index]);
2076                     return;
2077             }
2078             index++;
2079         }
2080         mCarPowerManagementService.powerOffFromCommand(skipGarageMode, shutdown);
2081     }
2082 
2083     /**
2084      * Inject a fake  VHAL event
2085      *
2086      * @param property the Vehicle property Id as defined in the HAL
2087      * @param zone     Zone that this event services
2088      * @param isErrorEvent indicates the type of event
2089      * @param value    Data value of the event
2090      * @param delayTime the event timestamp is increased by delayTime
2091      * @param writer   IndentingPrintWriter
2092      */
2093     private void injectVhalEvent(String property, String zone, String value,
2094             boolean isErrorEvent, String delayTime, IndentingPrintWriter writer) {
2095         Slog.i(TAG, "Injecting VHAL event: prop="  + property + ", zone=" + zone + ", value="
2096                 + value + ", isError=" + isErrorEvent
2097                 + (TextUtils.isEmpty(delayTime) ?  "" : ", delayTime=" + delayTime));
2098         if (zone.equalsIgnoreCase(PARAM_VEHICLE_PROPERTY_AREA_GLOBAL)) {
2099             if (!isPropertyAreaTypeGlobal(property)) {
2100                 writer.printf("Property area type inconsistent with given zone: %s \n", zone);
2101                 return;
2102             }
2103         }
2104         try {
2105             if (isErrorEvent) {
2106                 mHal.onPropertySetError(Integer.decode(value), Integer.decode(property),
2107                         Integer.decode(zone));
2108             } else {
2109                 mHal.injectVhalEvent(Integer.decode(property), Integer.decode(zone), value,
2110                         Integer.decode(delayTime));
2111             }
2112         } catch (NumberFormatException e) {
2113             writer.printf("Invalid property Id zone Id or value: %s \n", e);
2114             showHelp(writer);
2115         }
2116     }
2117 
2118     // Inject continuous vhal events.
2119     private void injectContinuousEvents(String[] args, IndentingPrintWriter writer) {
2120         if (args.length < 3 || args.length > 8) {
2121             showInvalidArguments(writer);
2122             return;
2123         }
2124         String areaId = PARAM_VEHICLE_PROPERTY_AREA_GLOBAL;
2125         String sampleRate = PARAM_INJECT_EVENT_DEFAULT_RATE;
2126         String durationTime = PARAM_INJECT_EVENT_DEFAULT_DURATION;
2127         String propId = args[1];
2128         String data = args[2];
2129         // scan input
2130         for (int i = 3; i < args.length - 1; i++) {
2131             switch (args[i]) {
2132                 case "-d":
2133                     durationTime = args[++i];
2134                     break;
2135                 case "-z" :
2136                     areaId = args[++i];
2137                     break;
2138                 case "-s" :
2139                     sampleRate = args[++i];
2140                     break;
2141                 default:
2142                     writer.printf("%s is an invalid flag.\n", args[i]);
2143                     showHelp(writer);
2144                     return;
2145             }
2146         }
2147         try {
2148             float sampleRateFloat = Float.parseFloat(sampleRate);
2149             if (sampleRateFloat <= 0) {
2150                 writer.printf("SampleRate: %s is an invalid value. "
2151                         + "SampleRate must be greater than 0.\n", sampleRate);
2152                 showHelp(writer);
2153                 return;
2154             }
2155             mHal.injectContinuousVhalEvent(Integer.decode(propId),
2156                     Integer.decode(areaId), data,
2157                     sampleRateFloat, Long.parseLong(durationTime));
2158         } catch (NumberFormatException e) {
2159             writer.printf("Invalid arguments: %s\n", e);
2160             showHelp(writer);
2161         }
2162 
2163     }
2164 
2165     // Set a target camera device for the rearview
2166     private void setRearviewCameraId(String[] args, IndentingPrintWriter writer) {
2167         if (args.length != 2) {
2168             showInvalidArguments(writer);
2169             return;
2170         }
2171 
2172         if (!mCarEvsService.setRearviewCameraIdFromCommand(args[1])) {
2173             writer.println("Failed to set CarEvsService rearview camera device id.");
2174         } else {
2175             writer.printf("CarEvsService is set to use %s.\n", args[1]);
2176         }
2177     }
2178 
2179     private void setDrivingSafetyRegion(String[] args, IndentingPrintWriter writer) {
2180         if (args.length != 1 && args.length != 2) {
2181             showInvalidArguments(writer);
2182             return;
2183         }
2184         String region = args.length == 2 ? args[1] : CarPackageManager.DRIVING_SAFETY_REGION_ALL;
2185         writer.println("Set driving safety region to:" + region);
2186         CarLocalServices.getService(CarPackageManagerService.class).resetDrivingSafetyRegion(
2187                 region);
2188     }
2189 
2190     private void getRearviewCameraId(IndentingPrintWriter writer) {
2191         writer.printf("CarEvsService is using %s for the rearview.\n",
2192                 mCarEvsService.getRearviewCameraIdFromCommand());
2193     }
2194 
2195     private void controlWatchdogPackageKillableState(String[] args, IndentingPrintWriter writer) {
2196         if (args.length != 3) {
2197             showInvalidArguments(writer);
2198             return;
2199         }
2200         if (!args[1].equals("true") && !args[1].equals("false")) {
2201             writer.println("Failed to parse killable state argument. "
2202                     + "Valid arguments: killable | not-killable");
2203             return;
2204         }
2205         int currentUserId = ActivityManager.getCurrentUser();
2206         mCarWatchdogService.setKillablePackageAsUser(
2207                 args[2], UserHandle.of(currentUserId), args[1].equals("true"));
2208         writer.printf("Set package killable state as '%s' for user '%d' and package '%s'\n",
2209                 args[1].equals("true") ? "killable" : "not killable", currentUserId, args[2]);
2210     }
2211 
2212     // Set third-party foreground I/O threshold for car watchdog
2213     private void setWatchdogIoThirdPartyForegroundBytes(String[] args,
2214             IndentingPrintWriter writer) {
2215         if (args.length != 2) {
2216             showInvalidArguments(writer);
2217             return;
2218         }
2219         try {
2220             long newForegroundModeBytes = Long.parseLong(args[1]);
2221             ResourceOveruseConfiguration configuration =
2222                     getThirdPartyResourceOveruseConfiguration(
2223                             CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
2224             if (configuration == null) {
2225                 writer.println("Failed to get third-party resource overuse configurations.");
2226                 return;
2227             }
2228             ResourceOveruseConfiguration newConfiguration = setComponentLevelForegroundIoBytes(
2229                     configuration, newForegroundModeBytes);
2230             int result = mCarWatchdogService.setResourceOveruseConfigurations(
2231                     Collections.singletonList(newConfiguration),
2232                     CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
2233             if (result == CarWatchdogManager.RETURN_CODE_SUCCESS) {
2234                 writer.printf(
2235                         "Successfully set third-party I/O overuse foreground threshold. { "
2236                                 + "foregroundModeBytes = %d } \n",
2237                         newForegroundModeBytes);
2238             } else {
2239                 writer.println("Failed to set third-party I/O overuse foreground threshold.");
2240             }
2241         } catch (NumberFormatException e) {
2242             writer.println("The argument provided does not contain a parsable long.");
2243             writer.println("Failed to set third-party I/O overuse foreground threshold.");
2244         } catch (RemoteException e) {
2245             writer.printf("Failed to set third-party I/O overuse foreground threshold: %s",
2246                     e.getMessage());
2247         }
2248     }
2249 
2250     private void getWatchdogIoThirdPartyForegroundBytes(IndentingPrintWriter writer) {
2251         ResourceOveruseConfiguration configuration =
2252                 getThirdPartyResourceOveruseConfiguration(
2253                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
2254         try {
2255             IoOveruseConfiguration ioOveruseConfiguration = Objects.requireNonNull(
2256                     configuration).getIoOveruseConfiguration();
2257             PerStateBytes componentLevelThresholds = Objects.requireNonNull(ioOveruseConfiguration)
2258                     .getComponentLevelThresholds();
2259             long foregroundBytes = Objects.requireNonNull(
2260                     componentLevelThresholds).getForegroundModeBytes();
2261             writer.printf("foregroundModeBytes = %d \n", foregroundBytes);
2262         } catch (NullPointerException e) {
2263             writer.println("Failed to get third-party I/O overuse foreground threshold.");
2264         }
2265     }
2266 
2267     private ResourceOveruseConfiguration getThirdPartyResourceOveruseConfiguration(
2268             int resourceOveruseFlag) {
2269         for (ResourceOveruseConfiguration configuration :
2270                 mCarWatchdogService.getResourceOveruseConfigurations(resourceOveruseFlag)) {
2271             if (configuration.getComponentType()
2272                     == ResourceOveruseConfiguration.COMPONENT_TYPE_THIRD_PARTY) {
2273                 return configuration;
2274             }
2275         }
2276         return null;
2277     }
2278 
2279     private ResourceOveruseConfiguration setComponentLevelForegroundIoBytes(
2280             ResourceOveruseConfiguration configuration, long foregroundModeBytes) {
2281         IoOveruseConfiguration ioOveruseConfiguration = configuration.getIoOveruseConfiguration();
2282         PerStateBytes componentLevelThresholds =
2283                 ioOveruseConfiguration.getComponentLevelThresholds();
2284         return constructResourceOveruseConfigurationBuilder(
2285                 configuration).setIoOveruseConfiguration(
2286                 new IoOveruseConfiguration.Builder(
2287                         new PerStateBytes(foregroundModeBytes,
2288                                 componentLevelThresholds.getBackgroundModeBytes(),
2289                                 componentLevelThresholds.getGarageModeBytes()),
2290                         ioOveruseConfiguration.getPackageSpecificThresholds(),
2291                         ioOveruseConfiguration.getAppCategorySpecificThresholds(),
2292                         ioOveruseConfiguration.getSystemWideThresholds())
2293                         .build())
2294                 .build();
2295     }
2296 
2297     private ResourceOveruseConfiguration.Builder constructResourceOveruseConfigurationBuilder(
2298             ResourceOveruseConfiguration configuration) {
2299         return new ResourceOveruseConfiguration.Builder(configuration.getComponentType(),
2300                 configuration.getSafeToKillPackages(),
2301                 configuration.getVendorPackagePrefixes(),
2302                 configuration.getPackagesToAppCategoryTypes())
2303                 .setIoOveruseConfiguration(configuration.getIoOveruseConfiguration());
2304     }
2305 
2306     private void controlWatchdogProcessHealthCheck(String[] args, IndentingPrintWriter writer) {
2307         if (args.length != 2) {
2308             showInvalidArguments(writer);
2309             return;
2310         }
2311         if (!args[1].equals("enable") && !args[1].equals("disable")) {
2312             writer.println("Failed to parse argument. Valid arguments: enable | disable");
2313             return;
2314         }
2315         mCarWatchdogService.controlProcessHealthCheck(args[1].equals("disable"));
2316         writer.printf("Watchdog health checking is now %sd \n", args[1]);
2317     }
2318 
2319     // Check if the given property is global
2320     private static boolean isPropertyAreaTypeGlobal(@Nullable String property) {
2321         if (property == null) {
2322             return false;
2323         }
2324         return (Integer.decode(property) & VehicleArea.MASK) == VehicleArea.GLOBAL;
2325     }
2326 }
2327