1 /* 2 * Copyright (C) 2015 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 17 package com.android.car; 18 19 import android.annotation.MainThread; 20 import android.app.UiModeManager; 21 import android.car.Car; 22 import android.car.ICar; 23 import android.car.cluster.renderer.IInstrumentClusterNavigation; 24 import android.car.user.CarUserManagerHelper; 25 import android.content.Context; 26 import android.content.pm.PackageManager; 27 import android.hardware.automotive.vehicle.V2_0.IVehicle; 28 import android.hardware.automotive.vehicle.V2_0.VehicleArea; 29 import android.os.Binder; 30 import android.os.Build; 31 import android.os.IBinder; 32 import android.os.Process; 33 import android.os.Trace; 34 import android.util.Log; 35 import android.util.Slog; 36 import android.util.TimingsTraceLog; 37 38 import com.android.car.cluster.InstrumentClusterService; 39 import com.android.car.hal.VehicleHal; 40 import com.android.car.internal.FeatureConfiguration; 41 import com.android.car.pm.CarPackageManagerService; 42 import com.android.car.systeminterface.SystemInterface; 43 import com.android.car.user.CarUserService; 44 import com.android.internal.annotations.GuardedBy; 45 import com.android.internal.car.ICarServiceHelper; 46 47 import java.io.FileDescriptor; 48 import java.io.PrintWriter; 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.List; 52 53 public class ICarImpl extends ICar.Stub { 54 55 public static final String INTERNAL_INPUT_SERVICE = "internal_input"; 56 public static final String INTERNAL_SYSTEM_ACTIVITY_MONITORING_SERVICE = 57 "system_activity_monitoring"; 58 59 private final Context mContext; 60 private final VehicleHal mHal; 61 62 private final SystemInterface mSystemInterface; 63 64 private final SystemActivityMonitoringService mSystemActivityMonitoringService; 65 private final CarPowerManagementService mCarPowerManagementService; 66 private final CarPackageManagerService mCarPackageManagerService; 67 private final CarInputService mCarInputService; 68 private final CarDrivingStateService mCarDrivingStateService; 69 private final CarUxRestrictionsManagerService mCarUXRestrictionsService; 70 private final CarAudioService mCarAudioService; 71 private final CarProjectionService mCarProjectionService; 72 private final CarPropertyService mCarPropertyService; 73 private final CarNightService mCarNightService; 74 private final AppFocusService mAppFocusService; 75 private final GarageModeService mGarageModeService; 76 private final InstrumentClusterService mInstrumentClusterService; 77 private final CarLocationService mCarLocationService; 78 private final SystemStateControllerService mSystemStateControllerService; 79 private final CarBluetoothService mCarBluetoothService; 80 private final PerUserCarServiceHelper mPerUserCarServiceHelper; 81 private final CarDiagnosticService mCarDiagnosticService; 82 private final CarStorageMonitoringService mCarStorageMonitoringService; 83 private final CarConfigurationService mCarConfigurationService; 84 85 private final CarUserManagerHelper mUserManagerHelper; 86 private CarUserService mCarUserService; 87 private VmsSubscriberService mVmsSubscriberService; 88 private VmsPublisherService mVmsPublisherService; 89 90 private final CarServiceBase[] mAllServices; 91 92 private static final String TAG = "ICarImpl"; 93 private static final String VHAL_TIMING_TAG = "VehicleHalTiming"; 94 private static final TimingsTraceLog mBootTiming = new TimingsTraceLog(VHAL_TIMING_TAG, 95 Trace.TRACE_TAG_HAL); 96 97 /** Test only service. Populate it only when necessary. */ 98 @GuardedBy("this") 99 private CarTestService mCarTestService; 100 101 @GuardedBy("this") 102 private ICarServiceHelper mICarServiceHelper; 103 104 private final String mVehicleInterfaceName; 105 106 public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface, 107 CanBusErrorNotifier errorNotifier, String vehicleInterfaceName) { 108 mContext = serviceContext; 109 mSystemInterface = systemInterface; 110 mHal = new VehicleHal(vehicle); 111 mVehicleInterfaceName = vehicleInterfaceName; 112 mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext); 113 mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(), 114 systemInterface); 115 mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal()); 116 mCarDrivingStateService = new CarDrivingStateService(serviceContext, mCarPropertyService); 117 mCarUXRestrictionsService = new CarUxRestrictionsManagerService(serviceContext, 118 mCarDrivingStateService, mCarPropertyService); 119 mCarPackageManagerService = new CarPackageManagerService(serviceContext, 120 mCarUXRestrictionsService, 121 mSystemActivityMonitoringService); 122 mCarInputService = new CarInputService(serviceContext, mHal.getInputHal()); 123 mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService); 124 mGarageModeService = new GarageModeService(mContext, mCarPowerManagementService); 125 mCarLocationService = new CarLocationService(mContext, mCarPowerManagementService, 126 mCarPropertyService); 127 mAppFocusService = new AppFocusService(serviceContext, mSystemActivityMonitoringService); 128 mCarAudioService = new CarAudioService(serviceContext); 129 mCarNightService = new CarNightService(serviceContext, mCarPropertyService); 130 mInstrumentClusterService = new InstrumentClusterService(serviceContext, 131 mAppFocusService, mCarInputService); 132 mSystemStateControllerService = new SystemStateControllerService(serviceContext, 133 mCarPowerManagementService, mCarAudioService, this); 134 mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext); 135 mCarBluetoothService = new CarBluetoothService(serviceContext, mCarPropertyService, 136 mPerUserCarServiceHelper, mCarUXRestrictionsService); 137 mVmsSubscriberService = new VmsSubscriberService(serviceContext, mHal.getVmsHal()); 138 mVmsPublisherService = new VmsPublisherService(serviceContext, mHal.getVmsHal()); 139 mCarDiagnosticService = new CarDiagnosticService(serviceContext, mHal.getDiagnosticHal()); 140 mCarStorageMonitoringService = new CarStorageMonitoringService(serviceContext, 141 systemInterface); 142 mCarConfigurationService = 143 new CarConfigurationService(serviceContext, new JsonReaderImpl()); 144 mUserManagerHelper = new CarUserManagerHelper(serviceContext); 145 146 // Be careful with order. Service depending on other service should be inited later. 147 List<CarServiceBase> allServices = new ArrayList<>(); 148 allServices.add(mSystemActivityMonitoringService); 149 allServices.add(mCarPowerManagementService); 150 allServices.add(mCarPropertyService); 151 allServices.add(mCarDrivingStateService); 152 allServices.add(mCarUXRestrictionsService); 153 allServices.add(mCarPackageManagerService); 154 allServices.add(mCarInputService); 155 allServices.add(mCarLocationService); 156 allServices.add(mGarageModeService); 157 allServices.add(mAppFocusService); 158 allServices.add(mCarAudioService); 159 allServices.add(mCarNightService); 160 allServices.add(mInstrumentClusterService); 161 allServices.add(mCarProjectionService); 162 allServices.add(mSystemStateControllerService); 163 allServices.add(mCarBluetoothService); 164 allServices.add(mCarDiagnosticService); 165 allServices.add(mPerUserCarServiceHelper); 166 allServices.add(mCarStorageMonitoringService); 167 allServices.add(mCarConfigurationService); 168 allServices.add(mVmsSubscriberService); 169 allServices.add(mVmsPublisherService); 170 171 if (mUserManagerHelper.isHeadlessSystemUser()) { 172 mCarUserService = new CarUserService(serviceContext, mUserManagerHelper); 173 allServices.add(mCarUserService); 174 } 175 176 mAllServices = allServices.toArray(new CarServiceBase[allServices.size()]); 177 } 178 179 @MainThread 180 void init() { 181 traceBegin("VehicleHal.init"); 182 mHal.init(); 183 traceEnd(); 184 traceBegin("CarService.initAllServices"); 185 for (CarServiceBase service : mAllServices) { 186 service.init(); 187 } 188 traceEnd(); 189 } 190 191 void release() { 192 // release done in opposite order from init 193 for (int i = mAllServices.length - 1; i >= 0; i--) { 194 mAllServices[i].release(); 195 } 196 mHal.release(); 197 } 198 199 void vehicleHalReconnected(IVehicle vehicle) { 200 mHal.vehicleHalReconnected(vehicle); 201 for (CarServiceBase service : mAllServices) { 202 service.vehicleHalReconnected(); 203 } 204 } 205 206 @Override 207 public void setCarServiceHelper(IBinder helper) { 208 int uid = Binder.getCallingUid(); 209 if (uid != Process.SYSTEM_UID) { 210 throw new SecurityException("Only allowed from system"); 211 } 212 synchronized (this) { 213 mICarServiceHelper = ICarServiceHelper.Stub.asInterface(helper); 214 mSystemInterface.setCarServiceHelper(mICarServiceHelper); 215 } 216 } 217 218 @Override 219 public IBinder getCarService(String serviceName) { 220 switch (serviceName) { 221 case Car.AUDIO_SERVICE: 222 return mCarAudioService; 223 case Car.APP_FOCUS_SERVICE: 224 return mAppFocusService; 225 case Car.PACKAGE_SERVICE: 226 return mCarPackageManagerService; 227 case Car.DIAGNOSTIC_SERVICE: 228 assertAnyDiagnosticPermission(mContext); 229 return mCarDiagnosticService; 230 case Car.POWER_SERVICE: 231 assertPowerPermission(mContext); 232 return mCarPowerManagementService; 233 case Car.CABIN_SERVICE: 234 case Car.HVAC_SERVICE: 235 case Car.INFO_SERVICE: 236 case Car.PROPERTY_SERVICE: 237 case Car.SENSOR_SERVICE: 238 case Car.VENDOR_EXTENSION_SERVICE: 239 return mCarPropertyService; 240 case Car.CAR_NAVIGATION_SERVICE: 241 assertNavigationManagerPermission(mContext); 242 IInstrumentClusterNavigation navService = 243 mInstrumentClusterService.getNavigationService(); 244 return navService == null ? null : navService.asBinder(); 245 case Car.CAR_INSTRUMENT_CLUSTER_SERVICE: 246 assertClusterManagerPermission(mContext); 247 return mInstrumentClusterService.getManagerService(); 248 case Car.PROJECTION_SERVICE: 249 assertProjectionPermission(mContext); 250 return mCarProjectionService; 251 case Car.VMS_SUBSCRIBER_SERVICE: 252 assertVmsSubscriberPermission(mContext); 253 return mVmsSubscriberService; 254 case Car.TEST_SERVICE: { 255 assertPermission(mContext, Car.PERMISSION_CAR_TEST_SERVICE); 256 synchronized (this) { 257 if (mCarTestService == null) { 258 mCarTestService = new CarTestService(mContext, this); 259 } 260 return mCarTestService; 261 } 262 } 263 case Car.BLUETOOTH_SERVICE: 264 return mCarBluetoothService; 265 case Car.STORAGE_MONITORING_SERVICE: 266 assertPermission(mContext, Car.PERMISSION_STORAGE_MONITORING); 267 return mCarStorageMonitoringService; 268 case Car.CAR_DRIVING_STATE_SERVICE: 269 assertDrivingStatePermission(mContext); 270 return mCarDrivingStateService; 271 case Car.CAR_UX_RESTRICTION_SERVICE: 272 return mCarUXRestrictionsService; 273 case Car.CAR_CONFIGURATION_SERVICE: 274 return mCarConfigurationService; 275 default: 276 Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName); 277 return null; 278 } 279 } 280 281 @Override 282 public int getCarConnectionType() { 283 return Car.CONNECTION_TYPE_EMBEDDED; 284 } 285 286 public CarServiceBase getCarInternalService(String serviceName) { 287 switch (serviceName) { 288 case INTERNAL_INPUT_SERVICE: 289 return mCarInputService; 290 case INTERNAL_SYSTEM_ACTIVITY_MONITORING_SERVICE: 291 return mSystemActivityMonitoringService; 292 default: 293 Log.w(CarLog.TAG_SERVICE, "getCarInternalService for unknown service:" + 294 serviceName); 295 return null; 296 } 297 } 298 299 public static void assertVehicleHalMockPermission(Context context) { 300 assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL); 301 } 302 303 public static void assertNavigationManagerPermission(Context context) { 304 assertPermission(context, Car.PERMISSION_CAR_NAVIGATION_MANAGER); 305 } 306 307 public static void assertClusterManagerPermission(Context context) { 308 assertPermission(context, Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL); 309 } 310 311 public static void assertPowerPermission(Context context) { 312 assertPermission(context, Car.PERMISSION_CAR_POWER); 313 } 314 315 public static void assertProjectionPermission(Context context) { 316 assertPermission(context, Car.PERMISSION_CAR_PROJECTION); 317 } 318 319 public static void assertAnyDiagnosticPermission(Context context) { 320 assertAnyPermission(context, 321 Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL, 322 Car.PERMISSION_CAR_DIAGNOSTIC_CLEAR); 323 } 324 325 public static void assertDrivingStatePermission(Context context) { 326 assertPermission(context, Car.PERMISSION_CAR_DRIVING_STATE); 327 } 328 329 public static void assertVmsPublisherPermission(Context context) { 330 assertPermission(context, Car.PERMISSION_VMS_PUBLISHER); 331 } 332 333 public static void assertVmsSubscriberPermission(Context context) { 334 assertPermission(context, Car.PERMISSION_VMS_SUBSCRIBER); 335 } 336 337 public static void assertPermission(Context context, String permission) { 338 if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { 339 throw new SecurityException("requires " + permission); 340 } 341 } 342 343 /** 344 * Checks to see if the caller has a permission. 345 * @param context 346 * @param permission 347 * 348 * @return boolean TRUE if caller has the permission. 349 */ 350 public static boolean hasPermission(Context context, String permission) { 351 return context.checkCallingOrSelfPermission(permission) 352 == PackageManager.PERMISSION_GRANTED; 353 } 354 355 public static void assertAnyPermission(Context context, String... permissions) { 356 for (String permission : permissions) { 357 if (context.checkCallingOrSelfPermission(permission) == 358 PackageManager.PERMISSION_GRANTED) { 359 return; 360 } 361 } 362 throw new SecurityException("requires any of " + Arrays.toString(permissions)); 363 } 364 365 @Override 366 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 367 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 368 != PackageManager.PERMISSION_GRANTED) { 369 writer.println("Permission Denial: can't dump CarService from from pid=" 370 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 371 + " without permission " + android.Manifest.permission.DUMP); 372 return; 373 } 374 if (args == null || args.length == 0) { 375 writer.println("*dump car service*"); 376 377 writer.println("*FutureConfig, DEFAULT:" + FeatureConfiguration.DEFAULT); 378 writer.println("*Dump all services*"); 379 for (CarServiceBase service : mAllServices) { 380 dumpService(service, writer); 381 } 382 if (mCarTestService != null) { 383 dumpService(mCarTestService, writer); 384 } 385 writer.println("*Dump Vehicle HAL*"); 386 writer.println("Vehicle HAL Interface: " + mVehicleInterfaceName); 387 try { 388 // TODO dump all feature flags by creating a dumpable interface 389 mHal.dump(writer); 390 } catch (Exception e) { 391 writer.println("Failed dumping: " + mHal.getClass().getName()); 392 e.printStackTrace(writer); 393 } 394 } else if (Build.IS_USERDEBUG || Build.IS_ENG) { 395 execShellCmd(args, writer); 396 } else { 397 writer.println("Commands not supported in " + Build.TYPE); 398 } 399 } 400 401 private void dumpService(CarServiceBase service, PrintWriter writer) { 402 try { 403 service.dump(writer); 404 } catch (Exception e) { 405 writer.println("Failed dumping: " + service.getClass().getName()); 406 e.printStackTrace(writer); 407 } 408 } 409 410 void execShellCmd(String[] args, PrintWriter writer) { 411 new CarShellCommand().exec(args, writer); 412 } 413 414 @MainThread 415 private static void traceBegin(String name) { 416 Slog.i(TAG, name); 417 mBootTiming.traceBegin(name); 418 } 419 420 @MainThread 421 private static void traceEnd() { 422 mBootTiming.traceEnd(); 423 } 424 425 private class CarShellCommand { 426 private static final String COMMAND_HELP = "-h"; 427 private static final String COMMAND_DAY_NIGHT_MODE = "day-night-mode"; 428 private static final String COMMAND_INJECT_VHAL_EVENT = "inject-vhal-event"; 429 private static final String COMMAND_ENABLE_UXR = "enable-uxr"; 430 private static final String COMMAND_GARAGE_MODE = "garage-mode"; 431 private static final String COMMAND_GET_DO_ACTIVITIES = "get-do-activities"; 432 433 private static final String PARAM_DAY_MODE = "day"; 434 private static final String PARAM_NIGHT_MODE = "night"; 435 private static final String PARAM_SENSOR_MODE = "sensor"; 436 private static final String PARAM_VEHICLE_PROPERTY_AREA_GLOBAL = "0"; 437 private static final String PARAM_ON_MODE = "on"; 438 private static final String PARAM_OFF_MODE = "off"; 439 private static final String PARAM_QUERY_MODE = "query"; 440 441 442 private void dumpHelp(PrintWriter pw) { 443 pw.println("Car service commands:"); 444 pw.println("\t-h"); 445 pw.println("\t Print this help text."); 446 pw.println("\tday-night-mode [day|night|sensor]"); 447 pw.println("\t Force into day/night mode or restore to auto."); 448 pw.println("\tinject-vhal-event property [zone] data(can be comma separated list)"); 449 pw.println("\t Inject a vehicle property for testing"); 450 pw.println("\tdisable-uxr true|false"); 451 pw.println("\t Disable UX restrictions and App blocking."); 452 pw.println("\tgarage-mode [on|off|query]"); 453 pw.println("\t Force into garage mode or check status."); 454 pw.println("\tget-do-activities pkgname"); 455 pw.println("\t Get Distraction Optimized activities in given package"); 456 } 457 458 public void exec(String[] args, PrintWriter writer) { 459 String arg = args[0]; 460 switch (arg) { 461 case COMMAND_HELP: 462 dumpHelp(writer); 463 break; 464 case COMMAND_DAY_NIGHT_MODE: { 465 String value = args.length < 1 ? "" : args[1]; 466 forceDayNightMode(value, writer); 467 break; 468 } 469 case COMMAND_GARAGE_MODE: { 470 String value = args.length < 1 ? "" : args[1]; 471 forceGarageMode(value, writer); 472 break; 473 } 474 case COMMAND_INJECT_VHAL_EVENT: 475 String zone = PARAM_VEHICLE_PROPERTY_AREA_GLOBAL; 476 String data; 477 if (args.length < 3) { 478 writer.println("Incorrect number of arguments."); 479 dumpHelp(writer); 480 break; 481 } else if (args.length > 3) { 482 // Zoned 483 zone = args[2]; 484 data = args[3]; 485 } else { 486 // Global 487 data = args[2]; 488 } 489 injectVhalEvent(args[1], zone, data, writer); 490 break; 491 case COMMAND_ENABLE_UXR: 492 if (args.length < 2) { 493 writer.println("Incorrect number of arguments"); 494 dumpHelp(writer); 495 break; 496 } 497 boolean enableBlocking = Boolean.valueOf(args[1]); 498 if (mCarPackageManagerService != null) { 499 mCarPackageManagerService.setEnableActivityBlocking(enableBlocking); 500 } 501 break; 502 case COMMAND_GET_DO_ACTIVITIES: 503 if (args.length < 2) { 504 writer.println("Incorrect number of arguments"); 505 dumpHelp(writer); 506 break; 507 } 508 String pkgName = args[1].toLowerCase(); 509 if (mCarPackageManagerService != null) { 510 String[] doActivities = 511 mCarPackageManagerService.getDistractionOptimizedActivities( 512 pkgName); 513 if (doActivities != null) { 514 writer.println("DO Activities for " + pkgName); 515 for (String a : doActivities) { 516 writer.println(a); 517 } 518 } else { 519 writer.println("No DO Activities for " + pkgName); 520 } 521 } 522 break; 523 default: 524 writer.println("Unknown command."); 525 dumpHelp(writer); 526 } 527 } 528 529 private void forceDayNightMode(String arg, PrintWriter writer) { 530 int mode; 531 switch (arg) { 532 case PARAM_DAY_MODE: 533 mode = CarNightService.FORCED_DAY_MODE; 534 break; 535 case PARAM_NIGHT_MODE: 536 mode = CarNightService.FORCED_NIGHT_MODE; 537 break; 538 case PARAM_SENSOR_MODE: 539 mode = CarNightService.FORCED_SENSOR_MODE; 540 break; 541 default: 542 writer.println("Unknown value. Valid argument: " + PARAM_DAY_MODE + "|" 543 + PARAM_NIGHT_MODE + "|" + PARAM_SENSOR_MODE); 544 return; 545 } 546 int current = mCarNightService.forceDayNightMode(mode); 547 String currentMode = null; 548 switch (current) { 549 case UiModeManager.MODE_NIGHT_AUTO: 550 currentMode = PARAM_SENSOR_MODE; 551 break; 552 case UiModeManager.MODE_NIGHT_YES: 553 currentMode = PARAM_NIGHT_MODE; 554 break; 555 case UiModeManager.MODE_NIGHT_NO: 556 currentMode = PARAM_DAY_MODE; 557 break; 558 } 559 writer.println("DayNightMode changed to: " + currentMode); 560 } 561 562 private void forceGarageMode(String arg, PrintWriter writer) { 563 switch (arg) { 564 case PARAM_ON_MODE: 565 mGarageModeService.onPrepareShutdown(false); 566 break; 567 case PARAM_OFF_MODE: 568 mGarageModeService.onSleepEntry(); 569 break; 570 case PARAM_QUERY_MODE: 571 // Nothing to do. Always query at the end anyway. 572 break; 573 default: 574 writer.println("Unknown value. Valid argument: " + PARAM_ON_MODE + "|" 575 + PARAM_OFF_MODE + "|" + PARAM_QUERY_MODE); 576 return; 577 } 578 writer.println("Garage mode: " + mGarageModeService.isInGarageMode()); 579 } 580 581 /** 582 * Inject a fake VHAL event 583 * 584 * @param property the Vehicle property Id as defined in the HAL 585 * @param zone Zone that this event services 586 * @param value Data value of the event 587 * @param writer PrintWriter 588 */ 589 private void injectVhalEvent(String property, String zone, String value, 590 PrintWriter writer) { 591 if (zone != null && (zone.equalsIgnoreCase(PARAM_VEHICLE_PROPERTY_AREA_GLOBAL))) { 592 if (!isPropertyAreaTypeGlobal(property)) { 593 writer.println("Property area type inconsistent with given zone"); 594 return; 595 } 596 } 597 try { 598 mHal.injectVhalEvent(property, zone, value); 599 } catch (NumberFormatException e) { 600 writer.println("Invalid property Id zone Id or value" + e); 601 dumpHelp(writer); 602 } 603 } 604 605 // Check if the given property is global 606 private boolean isPropertyAreaTypeGlobal(String property) { 607 if (property == null) { 608 return false; 609 } 610 return (Integer.decode(property) & VehicleArea.MASK) == VehicleArea.GLOBAL; 611 } 612 } 613 } 614