• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface, CanBusErrorNotifier errorNotifier)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 
init()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 
release()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 
vehicleHalReconnected(IVehicle vehicle)167     public void vehicleHalReconnected(IVehicle vehicle) {
168         mHal.vehicleHalReconnected(vehicle);
169         for (CarServiceBase service : mAllServices) {
170             service.vehicleHalReconnected();
171         }
172     }
173 
174     @Override
setCarServiceHelper(IBinder helper)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
getCarService(String serviceName)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
getCarConnectionType()242     public int getCarConnectionType() {
243         return Car.CONNECTION_TYPE_EMBEDDED;
244     }
245 
getCarInternalService(String serviceName)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 
assertVehicleHalMockPermission(Context context)259     public static void assertVehicleHalMockPermission(Context context) {
260         assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL);
261     }
262 
assertCabinPermission(Context context)263     public static void assertCabinPermission(Context context) {
264         assertPermission(context, Car.PERMISSION_CAR_CABIN);
265     }
266 
assertNavigationManagerPermission(Context context)267     public static void assertNavigationManagerPermission(Context context) {
268         assertPermission(context, Car.PERMISSION_CAR_NAVIGATION_MANAGER);
269     }
270 
assertClusterManagerPermission(Context context)271     public static void assertClusterManagerPermission(Context context) {
272         assertPermission(context, Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
273     }
274 
assertHvacPermission(Context context)275     public static void assertHvacPermission(Context context) {
276         assertPermission(context, Car.PERMISSION_CAR_HVAC);
277     }
278 
assertRadioPermission(Context context)279     private static void assertRadioPermission(Context context) {
280         assertPermission(context, Car.PERMISSION_CAR_RADIO);
281     }
282 
assertProjectionPermission(Context context)283     public static void assertProjectionPermission(Context context) {
284         assertPermission(context, Car.PERMISSION_CAR_PROJECTION);
285     }
286 
assertVendorExtensionPermission(Context context)287     public static void assertVendorExtensionPermission(Context context) {
288         assertPermission(context, Car.PERMISSION_VENDOR_EXTENSION);
289     }
290 
assertAnyDiagnosticPermission(Context context)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 
assertPermission(Context context, String permission)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 
assertAnyPermission(Context context, String... permissions)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 
dump(PrintWriter writer)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 
execShellCmd(String[] args, PrintWriter writer)327     void execShellCmd(String[] args, PrintWriter writer) {
328         new CarShellCommand().exec(args, writer);
329     }
330 
traceBegin(String name)331     private static void traceBegin(String name) {
332         Slog.i(TAG, name);
333         mBootTiming.traceBegin(name);
334     }
335 
traceEnd()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 
dumpHelp(PrintWriter pw)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 
exec(String[] args, PrintWriter writer)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 
forceDayNightMode(String arg, PrintWriter writer)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          */
inject_zoned_boolean_event(String property, String zone, String value, PrintWriter writer)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          */
inject_global_integer_event(String property, String value, PrintWriter writer)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