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