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