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