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.car.Car;
20 import android.car.ICar;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.os.IBinder;
24 import android.util.Log;
25 
26 import com.android.car.cluster.CarNavigationService;
27 import com.android.car.cluster.InstrumentClusterService;
28 import com.android.car.hal.VehicleHal;
29 import com.android.car.pm.CarPackageManagerService;
30 import com.android.internal.annotations.GuardedBy;
31 
32 import java.io.PrintWriter;
33 
34 public class ICarImpl extends ICar.Stub {
35 
36     public static final String INTERNAL_INPUT_SERVICE =  "internal_input";
37 
38     // load jni for all services here
39     static {
40         System.loadLibrary("jni_car_service");
41     }
42 
43     @GuardedBy("ICarImpl.class")
44     private static ICarImpl sInstance = null;
45 
46     private final Context mContext;
47     private final VehicleHal mHal;
48 
49     private final CarPowerManagementService mCarPowerManagementService;
50     private final CarPackageManagerService mCarPackageManagerService;
51     private final CarInputService mCarInputService;
52     private final CarSensorService mCarSensorService;
53     private final CarInfoService mCarInfoService;
54     private final CarAudioService mCarAudioService;
55     private final CarProjectionService mCarProjectionService;
56     private final CarCameraService mCarCameraService;
57     private final CarHvacService mCarHvacService;
58     private final CarRadioService mCarRadioService;
59     private final CarNightService mCarNightService;
60     private final AppContextService mAppContextService;
61     private final GarageModeService mGarageModeService;
62     private final CarNavigationService mCarNavigationService;
63     private final InstrumentClusterService mInstrumentClusterService;
64 
65     /** Test only service. Populate it only when necessary. */
66     @GuardedBy("this")
67     private CarTestService mCarTestService;
68     private final CarServiceBase[] mAllServices;
69 
getInstance(Context serviceContext)70     public synchronized static ICarImpl getInstance(Context serviceContext) {
71         if (sInstance == null) {
72             sInstance = new ICarImpl(serviceContext);
73             sInstance.init();
74         }
75         return sInstance;
76     }
77 
releaseInstance()78     public synchronized static void releaseInstance() {
79         if (sInstance == null) {
80             return;
81         }
82         sInstance.release();
83         sInstance = null;
84     }
85 
ICarImpl(Context serviceContext)86     public ICarImpl(Context serviceContext) {
87         mContext = serviceContext;
88         mHal = VehicleHal.getInstance();
89         mCarPowerManagementService = new CarPowerManagementService(serviceContext);
90         mCarInputService = new CarInputService(serviceContext);
91         mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService);
92         mGarageModeService = new GarageModeService(mContext, mCarPowerManagementService);
93         mCarInfoService = new CarInfoService(serviceContext);
94         mAppContextService = new AppContextService(serviceContext);
95         mCarSensorService = new CarSensorService(serviceContext);
96         mCarAudioService = new CarAudioService(serviceContext);
97         mCarHvacService = new CarHvacService(serviceContext);
98         mCarRadioService = new CarRadioService(serviceContext);
99         mCarCameraService = new CarCameraService(serviceContext);
100         mCarNightService = new CarNightService(serviceContext);
101         mCarPackageManagerService = new CarPackageManagerService(serviceContext);
102         mInstrumentClusterService = new InstrumentClusterService(serviceContext);
103         mCarNavigationService = new CarNavigationService(
104                 serviceContext, mAppContextService, mInstrumentClusterService);
105 
106         // Be careful with order. Service depending on other service should be inited later.
107         mAllServices = new CarServiceBase[] {
108                 mCarPowerManagementService,
109                 mCarPackageManagerService,
110                 mCarInputService,
111                 mGarageModeService,
112                 mCarInfoService,
113                 mAppContextService,
114                 mCarSensorService,
115                 mCarAudioService,
116                 mCarHvacService,
117                 mCarRadioService,
118                 mCarCameraService,
119                 mCarNightService,
120                 mInstrumentClusterService,
121                 mCarProjectionService,
122                 mCarNavigationService,
123                 };
124     }
125 
init()126     private void init() {
127         for (CarServiceBase service: mAllServices) {
128             service.init();
129         }
130     }
131 
release()132     private void release() {
133         // release done in opposite order from init
134         for (int i = mAllServices.length - 1; i >= 0; i--) {
135             mAllServices[i].release();
136         }
137         VehicleHal.releaseInstance();
138     }
139 
140     /** Only for CarTestService */
startMocking()141     void startMocking() {
142         reinitServices();
143     }
144 
145     /** Only for CarTestService */
stopMocking()146     void stopMocking() {
147         reinitServices();
148     }
149 
150     /** Reset all services when starting / stopping vehicle hal mocking */
reinitServices()151     private void reinitServices() {
152         for (int i = mAllServices.length - 1; i >= 0; i--) {
153             mAllServices[i].release();
154         }
155         for (CarServiceBase service: mAllServices) {
156             service.init();
157         }
158     }
159 
160     @Override
getCarService(String serviceName)161     public IBinder getCarService(String serviceName) {
162         switch (serviceName) {
163             case Car.AUDIO_SERVICE:
164                 return mCarAudioService;
165             case Car.SENSOR_SERVICE:
166                 return mCarSensorService;
167             case Car.INFO_SERVICE:
168                 return mCarInfoService;
169             case Car.APP_CONTEXT_SERVICE:
170                 return mAppContextService;
171             case Car.PACKAGE_SERVICE:
172                 return mCarPackageManagerService;
173             case Car.CAMERA_SERVICE:
174                 assertCameraPermission(mContext);
175                 return mCarCameraService;
176             case Car.HVAC_SERVICE:
177                 assertHvacPermission(mContext);
178                 return mCarHvacService;
179             case Car.RADIO_SERVICE:
180                 assertRadioPermission(mContext);
181                 return mCarRadioService;
182             case Car.CAR_NAVIGATION_SERVICE:
183                 assertNavigationManagerPermission(mContext);
184                 return mCarNavigationService;
185             case Car.PROJECTION_SERVICE:
186                 assertProjectionPermission(mContext);
187                 return mCarProjectionService;
188             case Car.TEST_SERVICE: {
189                 assertVehicleHalMockPermission(mContext);
190                 synchronized (this) {
191                     if (mCarTestService == null) {
192                         mCarTestService = new CarTestService(mContext, this);
193                     }
194                     return mCarTestService;
195                 }
196             }
197             default:
198                 Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName);
199                 return null;
200         }
201     }
202 
203     @Override
getCarConnectionType()204     public int getCarConnectionType() {
205         if (!isInMocking()) {
206             return Car.CONNECTION_TYPE_EMBEDDED;
207         } else {
208             return Car.CONNECTION_TYPE_EMBEDDED_MOCKING;
209         }
210     }
211 
getCarInternalService(String serviceName)212     public CarServiceBase getCarInternalService(String serviceName) {
213         switch (serviceName) {
214             case INTERNAL_INPUT_SERVICE:
215                 return mCarInputService;
216             default:
217                 Log.w(CarLog.TAG_SERVICE, "getCarInternalService for unknown service:" +
218                         serviceName);
219                 return null;
220         }
221     }
222 
223     /**
224      * Whether mocking underlying HAL or not.
225      * @return
226      */
isInMocking()227     public synchronized boolean isInMocking() {
228         if (mCarTestService == null) {
229             return false;
230         }
231         return mCarTestService.isInMocking();
232     }
233 
assertVehicleHalMockPermission(Context context)234     public static void assertVehicleHalMockPermission(Context context) {
235         if (context.checkCallingOrSelfPermission(Car.PERMISSION_MOCK_VEHICLE_HAL)
236                 != PackageManager.PERMISSION_GRANTED) {
237             throw new SecurityException("requires CAR_MOCK_VEHICLE_HAL permission");
238         }
239     }
240 
assertCameraPermission(Context context)241     public static void assertCameraPermission(Context context) {
242         if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_CAMERA)
243                 != PackageManager.PERMISSION_GRANTED) {
244             throw new SecurityException(
245                     "requires " + Car.PERMISSION_CAR_CAMERA);
246         }
247     }
248 
assertNavigationManagerPermission(Context context)249     public static void assertNavigationManagerPermission(Context context) {
250         if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_NAVIGATION_MANAGER)
251                 != PackageManager.PERMISSION_GRANTED) {
252             throw new SecurityException(
253                     "requires " + Car.PERMISSION_CAR_NAVIGATION_MANAGER);
254         }
255     }
256 
assertHvacPermission(Context context)257     public static void assertHvacPermission(Context context) {
258         if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_HVAC)
259                 != PackageManager.PERMISSION_GRANTED) {
260             throw new SecurityException(
261                     "requires " + Car.PERMISSION_CAR_HVAC);
262         }
263     }
264 
assertRadioPermission(Context context)265     private static void assertRadioPermission(Context context) {
266         if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_RADIO)
267             != PackageManager.PERMISSION_GRANTED) {
268             throw new SecurityException(
269                 "requires permission " + Car.PERMISSION_CAR_RADIO);
270         }
271     }
272 
assertProjectionPermission(Context context)273     public static void assertProjectionPermission(Context context) {
274         if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_PROJECTION)
275                 != PackageManager.PERMISSION_GRANTED) {
276             throw new SecurityException(
277                     "requires " + Car.PERMISSION_CAR_PROJECTION);
278         }
279     }
280 
dump(PrintWriter writer)281     void dump(PrintWriter writer) {
282         writer.println("*Dump all services*");
283         for (CarServiceBase service: mAllServices) {
284             service.dump(writer);
285         }
286         CarTestService testService = mCarTestService;
287         if (testService != null) {
288             testService.dump(writer);
289         }
290     }
291 }
292