Home | History | Annotate | Download | only in car
      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.app.UiModeManager;
     20 import android.car.Car;
     21 import android.car.ICar;
     22 import android.car.annotation.FutureFeature;
     23 import android.car.cluster.renderer.IInstrumentClusterNavigation;
     24 import android.content.Context;
     25 import android.content.pm.PackageManager;
     26 import android.hardware.automotive.vehicle.V2_0.IVehicle;
     27 import android.os.Binder;
     28 import android.os.IBinder;
     29 import android.os.Process;
     30 import android.os.Trace;
     31 import android.util.Log;
     32 import android.util.Slog;
     33 import android.util.TimingsTraceLog;
     34 import com.android.car.cluster.InstrumentClusterService;
     35 import com.android.car.hal.VehicleHal;
     36 import com.android.car.internal.FeatureConfiguration;
     37 import com.android.car.internal.FeatureUtil;
     38 import com.android.car.pm.CarPackageManagerService;
     39 import com.android.internal.annotations.GuardedBy;
     40 import com.android.internal.car.ICarServiceHelper;
     41 import java.io.PrintWriter;
     42 import java.util.ArrayList;
     43 import java.util.Arrays;
     44 import java.util.List;
     45 
     46 public class ICarImpl extends ICar.Stub {
     47 
     48     public static final String INTERNAL_INPUT_SERVICE = "internal_input";
     49     public static final String INTERNAL_SYSTEM_ACTIVITY_MONITORING_SERVICE =
     50             "system_activity_monitoring";
     51 
     52     private final Context mContext;
     53     private final VehicleHal mHal;
     54 
     55     private final SystemActivityMonitoringService mSystemActivityMonitoringService;
     56     private final CarPowerManagementService mCarPowerManagementService;
     57     private final CarPackageManagerService mCarPackageManagerService;
     58     private final CarInputService mCarInputService;
     59     private final CarSensorService mCarSensorService;
     60     private final CarInfoService mCarInfoService;
     61     private final CarAudioService mCarAudioService;
     62     private final CarProjectionService mCarProjectionService;
     63     private final CarCabinService mCarCabinService;
     64     private final CarHvacService mCarHvacService;
     65     private final CarRadioService mCarRadioService;
     66     private final CarNightService mCarNightService;
     67     private final AppFocusService mAppFocusService;
     68     private final GarageModeService mGarageModeService;
     69     private final InstrumentClusterService mInstrumentClusterService;
     70     private final SystemStateControllerService mSystemStateControllerService;
     71     private final CarVendorExtensionService mCarVendorExtensionService;
     72     private final CarBluetoothService mCarBluetoothService;
     73     private final PerUserCarServiceHelper mPerUserCarServiceHelper;
     74     private CarDiagnosticService mCarDiagnosticService;
     75 
     76     private final CarServiceBase[] mAllServices;
     77 
     78     private static final String TAG = "ICarImpl";
     79     private static final String VHAL_TIMING_TAG = "VehicleHalTiming";
     80     private static final TimingsTraceLog mBootTiming = new TimingsTraceLog(VHAL_TIMING_TAG,
     81         Trace.TRACE_TAG_HAL);
     82 
     83     /** Test only service. Populate it only when necessary. */
     84     @GuardedBy("this")
     85     private CarTestService mCarTestService;
     86 
     87     @GuardedBy("this")
     88     private ICarServiceHelper mICarServiceHelper;
     89 
     90     public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
     91             CanBusErrorNotifier errorNotifier) {
     92         mContext = serviceContext;
     93         mHal = new VehicleHal(vehicle);
     94         mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);
     95         mCarPowerManagementService = new CarPowerManagementService(
     96                 mHal.getPowerHal(), systemInterface);
     97         mCarSensorService = new CarSensorService(serviceContext, mHal.getSensorHal());
     98         mCarPackageManagerService = new CarPackageManagerService(serviceContext, mCarSensorService,
     99                 mSystemActivityMonitoringService);
    100         mCarInputService = new CarInputService(serviceContext, mHal.getInputHal());
    101         mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService);
    102         mGarageModeService = new GarageModeService(mContext, mCarPowerManagementService);
    103         mCarInfoService = new CarInfoService(serviceContext, mHal.getInfoHal());
    104         mAppFocusService = new AppFocusService(serviceContext, mSystemActivityMonitoringService);
    105         mCarAudioService = new CarAudioService(serviceContext, mHal.getAudioHal(),
    106                 mCarInputService, errorNotifier);
    107         mCarCabinService = new CarCabinService(serviceContext, mHal.getCabinHal());
    108         mCarHvacService = new CarHvacService(serviceContext, mHal.getHvacHal());
    109         mCarRadioService = new CarRadioService(serviceContext, mHal.getRadioHal());
    110         mCarNightService = new CarNightService(serviceContext, mCarSensorService);
    111         mInstrumentClusterService = new InstrumentClusterService(serviceContext,
    112                 mAppFocusService, mCarInputService);
    113         mSystemStateControllerService = new SystemStateControllerService(serviceContext,
    114                 mCarPowerManagementService, mCarAudioService, this);
    115         mCarVendorExtensionService = new CarVendorExtensionService(serviceContext,
    116                 mHal.getVendorExtensionHal());
    117         mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext);
    118         mCarBluetoothService = new CarBluetoothService(serviceContext, mCarCabinService,
    119                 mCarSensorService, mPerUserCarServiceHelper);
    120         mCarDiagnosticService = new CarDiagnosticService(serviceContext, mHal.getDiagnosticHal());
    121 
    122         // Be careful with order. Service depending on other service should be inited later.
    123         List<CarServiceBase> allServices = new ArrayList<>(Arrays.asList(
    124                 mSystemActivityMonitoringService,
    125                 mCarPowerManagementService,
    126                 mCarSensorService,
    127                 mCarPackageManagerService,
    128                 mCarInputService,
    129                 mGarageModeService,
    130                 mCarInfoService,
    131                 mAppFocusService,
    132                 mCarAudioService,
    133                 mCarCabinService,
    134                 mCarHvacService,
    135                 mCarRadioService,
    136                 mCarNightService,
    137                 mInstrumentClusterService,
    138                 mCarProjectionService,
    139                 mSystemStateControllerService,
    140                 mCarVendorExtensionService,
    141                 mCarBluetoothService,
    142                 mCarDiagnosticService,
    143                 mPerUserCarServiceHelper
    144         ));
    145         mAllServices = allServices.toArray(new CarServiceBase[0]);
    146     }
    147 
    148     public void init() {
    149         traceBegin("VehicleHal.init");
    150         mHal.init();
    151         traceEnd();
    152         traceBegin("CarService.initAllServices");
    153         for (CarServiceBase service : mAllServices) {
    154             service.init();
    155         }
    156         traceEnd();
    157     }
    158 
    159     public void release() {
    160         // release done in opposite order from init
    161         for (int i = mAllServices.length - 1; i >= 0; i--) {
    162             mAllServices[i].release();
    163         }
    164         mHal.release();
    165     }
    166 
    167     public void vehicleHalReconnected(IVehicle vehicle) {
    168         mHal.vehicleHalReconnected(vehicle);
    169         for (CarServiceBase service : mAllServices) {
    170             service.vehicleHalReconnected();
    171         }
    172     }
    173 
    174     @Override
    175     public void setCarServiceHelper(IBinder helper) {
    176         int uid = Binder.getCallingUid();
    177         if (uid != Process.SYSTEM_UID) {
    178             throw new SecurityException("Only allowed from system");
    179         }
    180         synchronized (this) {
    181             mICarServiceHelper = ICarServiceHelper.Stub.asInterface(helper);
    182         }
    183     }
    184 
    185     @Override
    186     public IBinder getCarService(String serviceName) {
    187         switch (serviceName) {
    188             case Car.AUDIO_SERVICE:
    189                 return mCarAudioService;
    190             case Car.SENSOR_SERVICE:
    191                 return mCarSensorService;
    192             case Car.INFO_SERVICE:
    193                 return mCarInfoService;
    194             case Car.APP_FOCUS_SERVICE:
    195                 return mAppFocusService;
    196             case Car.PACKAGE_SERVICE:
    197                 return mCarPackageManagerService;
    198             case Car.CABIN_SERVICE:
    199                 assertCabinPermission(mContext);
    200                 return mCarCabinService;
    201             case Car.DIAGNOSTIC_SERVICE:
    202                 assertAnyDiagnosticPermission(mContext);
    203                 return mCarDiagnosticService;
    204             case Car.HVAC_SERVICE:
    205                 assertHvacPermission(mContext);
    206                 return mCarHvacService;
    207             case Car.RADIO_SERVICE:
    208                 assertRadioPermission(mContext);
    209                 return mCarRadioService;
    210             case Car.CAR_NAVIGATION_SERVICE:
    211                 assertNavigationManagerPermission(mContext);
    212                 IInstrumentClusterNavigation navService =
    213                         mInstrumentClusterService.getNavigationService();
    214                 return navService == null ? null : navService.asBinder();
    215             case Car.CAR_INSTRUMENT_CLUSTER_SERVICE:
    216                 assertClusterManagerPermission(mContext);
    217                 return mInstrumentClusterService.getManagerService();
    218             case Car.PROJECTION_SERVICE:
    219                 assertProjectionPermission(mContext);
    220                 return mCarProjectionService;
    221             case Car.VENDOR_EXTENSION_SERVICE:
    222                 assertVendorExtensionPermission(mContext);
    223                 return mCarVendorExtensionService;
    224             case Car.TEST_SERVICE: {
    225                 assertPermission(mContext, Car.PERMISSION_CAR_TEST_SERVICE);
    226                 synchronized (this) {
    227                     if (mCarTestService == null) {
    228                         mCarTestService = new CarTestService(mContext, this);
    229                     }
    230                     return mCarTestService;
    231                 }
    232             }
    233             case Car.BLUETOOTH_SERVICE:
    234                 return mCarBluetoothService;
    235             default:
    236                 Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName);
    237                 return null;
    238         }
    239     }
    240 
    241     @Override
    242     public int getCarConnectionType() {
    243         return Car.CONNECTION_TYPE_EMBEDDED;
    244     }
    245 
    246     public CarServiceBase getCarInternalService(String serviceName) {
    247         switch (serviceName) {
    248             case INTERNAL_INPUT_SERVICE:
    249                 return mCarInputService;
    250             case INTERNAL_SYSTEM_ACTIVITY_MONITORING_SERVICE:
    251                 return mSystemActivityMonitoringService;
    252             default:
    253                 Log.w(CarLog.TAG_SERVICE, "getCarInternalService for unknown service:" +
    254                         serviceName);
    255                 return null;
    256         }
    257     }
    258 
    259     public static void assertVehicleHalMockPermission(Context context) {
    260         assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL);
    261     }
    262 
    263     public static void assertCabinPermission(Context context) {
    264         assertPermission(context, Car.PERMISSION_CAR_CABIN);
    265     }
    266 
    267     public static void assertNavigationManagerPermission(Context context) {
    268         assertPermission(context, Car.PERMISSION_CAR_NAVIGATION_MANAGER);
    269     }
    270 
    271     public static void assertClusterManagerPermission(Context context) {
    272         assertPermission(context, Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
    273     }
    274 
    275     public static void assertHvacPermission(Context context) {
    276         assertPermission(context, Car.PERMISSION_CAR_HVAC);
    277     }
    278 
    279     private static void assertRadioPermission(Context context) {
    280         assertPermission(context, Car.PERMISSION_CAR_RADIO);
    281     }
    282 
    283     public static void assertProjectionPermission(Context context) {
    284         assertPermission(context, Car.PERMISSION_CAR_PROJECTION);
    285     }
    286 
    287     public static void assertVendorExtensionPermission(Context context) {
    288         assertPermission(context, Car.PERMISSION_VENDOR_EXTENSION);
    289     }
    290 
    291     public static void assertAnyDiagnosticPermission(Context context) {
    292         assertAnyPermission(context,
    293                 Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL,
    294                 Car.PERMISSION_CAR_DIAGNOSTIC_CLEAR);
    295     }
    296 
    297     public static void assertPermission(Context context, String permission) {
    298         if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
    299             throw new SecurityException("requires " + permission);
    300         }
    301     }
    302 
    303     public static void assertAnyPermission(Context context, String... permissions) {
    304         for (String permission : permissions) {
    305             if (context.checkCallingOrSelfPermission(permission) ==
    306                     PackageManager.PERMISSION_GRANTED) {
    307                 return;
    308             }
    309         }
    310         throw new SecurityException("requires any of " + Arrays.toString(permissions));
    311     }
    312 
    313     void dump(PrintWriter writer) {
    314         writer.println("*FutureConfig, DEFAULT:" + FeatureConfiguration.DEFAULT);
    315         //TODO dump all feature flags by reflection
    316         writer.println("*Dump all services*");
    317         for (CarServiceBase service : mAllServices) {
    318             service.dump(writer);
    319         }
    320         if (mCarTestService != null) {
    321             mCarTestService.dump(writer);
    322         }
    323         writer.println("*Dump Vehicle HAL*");
    324         mHal.dump(writer);
    325     }
    326 
    327     void execShellCmd(String[] args, PrintWriter writer) {
    328         new CarShellCommand().exec(args, writer);
    329     }
    330 
    331     private static void traceBegin(String name) {
    332         Slog.i(TAG, name);
    333         mBootTiming.traceBegin(name);
    334     }
    335 
    336     private static void traceEnd() {
    337         mBootTiming.traceEnd();
    338     }
    339 
    340     private class CarShellCommand {
    341         private static final String COMMAND_HELP = "-h";
    342         private static final String COMMAND_DAY_NIGHT_MODE = "day-night-mode";
    343         private static final String COMMAND_INJECT_EVENT = "inject-event";
    344 
    345         private static final String PARAM_DAY_MODE = "day";
    346         private static final String PARAM_NIGHT_MODE = "night";
    347         private static final String PARAM_SENSOR_MODE = "sensor";
    348         private static final String PARAM_ZONED_BOOLEAN = "zoned-boolean";
    349         private static final String PARAM_GLOBAL_INT = "global-integer";
    350 
    351         private void dumpHelp(PrintWriter pw) {
    352             pw.println("Car service commands:");
    353             pw.println("\t-h");
    354             pw.println("\t  Print this help text.");
    355             pw.println("\tday-night-mode [day|night|sensor]");
    356             pw.println("\t  Force into day/night mode or restore to auto.");
    357             pw.println("\tinject-event zoned-boolean propertyType zone [true|false]");
    358             pw.println("\t  Inject a Boolean HAL Event. ");
    359         }
    360 
    361         public void exec(String[] args, PrintWriter writer) {
    362             String arg = args[0];
    363             switch (arg) {
    364                 case COMMAND_HELP:
    365                     dumpHelp(writer);
    366                     break;
    367                 case COMMAND_DAY_NIGHT_MODE:
    368                     String value = args.length < 1 ? "" : args[1];
    369                     forceDayNightMode(value, writer);
    370                     break;
    371                 case COMMAND_INJECT_EVENT:
    372                     String eventType;
    373                     if (args.length > 1) {
    374                         eventType = args[1].toLowerCase();
    375                         switch (eventType) {
    376                             case PARAM_ZONED_BOOLEAN:
    377                                 if (args.length < 5) {
    378                                     writer.println("Incorrect number of arguments.");
    379                                     dumpHelp(writer);
    380                                     break;
    381                                 }
    382                                 inject_zoned_boolean_event(args[2], args[3], args[4], writer);
    383                                 break;
    384 
    385                             case PARAM_GLOBAL_INT:
    386                                 if (args.length < 4) {
    387                                     writer.println("Incorrect number of Arguments");
    388                                     dumpHelp(writer);
    389                                     break;
    390                                 }
    391                                 inject_global_integer_event(args[2], args[3], writer);
    392                                 break;
    393 
    394                             default:
    395                                 writer.println("Unsupported event type");
    396                                 dumpHelp(writer);
    397                                 break;
    398                         }
    399                     }
    400                     break;
    401                 default:
    402                     writer.println("Unknown command.");
    403                     dumpHelp(writer);
    404             }
    405         }
    406 
    407         private void forceDayNightMode(String arg, PrintWriter writer) {
    408             int mode;
    409             switch (arg) {
    410                 case PARAM_DAY_MODE:
    411                     mode = CarNightService.FORCED_DAY_MODE;
    412                     break;
    413                 case PARAM_NIGHT_MODE:
    414                     mode = CarNightService.FORCED_NIGHT_MODE;
    415                     break;
    416                 case PARAM_SENSOR_MODE:
    417                     mode = CarNightService.FORCED_SENSOR_MODE;
    418                     break;
    419                 default:
    420                     writer.println("Unknown value. Valid argument: " + PARAM_DAY_MODE + "|"
    421                             + PARAM_NIGHT_MODE + "|" + PARAM_SENSOR_MODE);
    422                     return;
    423             }
    424             int current = mCarNightService.forceDayNightMode(mode);
    425             String currentMode = null;
    426             switch (current) {
    427                 case UiModeManager.MODE_NIGHT_AUTO:
    428                     currentMode = PARAM_SENSOR_MODE;
    429                     break;
    430                 case UiModeManager.MODE_NIGHT_YES:
    431                     currentMode = PARAM_NIGHT_MODE;
    432                     break;
    433                 case UiModeManager.MODE_NIGHT_NO:
    434                     currentMode = PARAM_DAY_MODE;
    435                     break;
    436             }
    437             writer.println("DayNightMode changed to: " + currentMode);
    438         }
    439 
    440         /**
    441          * Inject a fake boolean HAL event to help testing.
    442          *
    443          * @param property - Vehicle Property
    444          * @param value    - boolean value for the property
    445          * @param writer   - Printwriter
    446          */
    447         private void inject_zoned_boolean_event(String property, String zone, String value,
    448                 PrintWriter writer) {
    449             Log.d(CarLog.TAG_SERVICE, "Injecting Boolean event");
    450             boolean event;
    451             int propId;
    452             int zoneId;
    453             if (value.equalsIgnoreCase("true")) {
    454                 event = true;
    455             } else {
    456                 event = false;
    457             }
    458             try {
    459                 propId = Integer.decode(property);
    460                 zoneId = Integer.decode(zone);
    461             } catch (NumberFormatException e) {
    462                 writer.println("Invalid property Id or Zone Id. Prefix hex values with 0x");
    463                 return;
    464             }
    465             mHal.injectBooleanEvent(propId, zoneId, event);
    466         }
    467 
    468         /**
    469          * Inject a fake Integer HAL event to help testing.
    470          *
    471          * @param property - Vehicle Property
    472          * @param value    - Integer value to inject
    473          * @param writer   - PrintWriter
    474          */
    475         private void inject_global_integer_event(String property, String value,
    476                 PrintWriter writer) {
    477             Log.d(CarLog.TAG_SERVICE, "Injecting integer event");
    478             int propId;
    479             int eventValue;
    480             try {
    481                 propId = Integer.decode(property);
    482                 eventValue = Integer.decode(value);
    483             } catch (NumberFormatException e) {
    484                 writer.println("Invalid property Id or event value.  Prefix hex values with 0x");
    485                 return;
    486             }
    487             mHal.injectIntegerEvent(propId, eventValue);
    488         }
    489 
    490     }
    491 }
    492