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