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