• 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 android.car;
18 
19 import android.annotation.IntDef;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.car.cluster.CarInstrumentClusterManager;
23 import android.car.content.pm.CarPackageManager;
24 import android.car.diagnostic.CarDiagnosticManager;
25 import android.car.drivingstate.CarDrivingStateManager;
26 import android.car.drivingstate.CarUxRestrictionsManager;
27 import android.car.hardware.CarSensorManager;
28 import android.car.hardware.CarVendorExtensionManager;
29 import android.car.hardware.cabin.CarCabinManager;
30 import android.car.hardware.hvac.CarHvacManager;
31 import android.car.hardware.power.CarPowerManager;
32 import android.car.hardware.property.CarPropertyManager;
33 import android.car.media.CarAudioManager;
34 import android.car.navigation.CarNavigationStatusManager;
35 import android.car.settings.CarConfigurationManager;
36 import android.car.storagemonitoring.CarStorageMonitoringManager;
37 import android.car.test.CarTestManagerBinderWrapper;
38 import android.car.vms.VmsSubscriberManager;
39 import android.content.ComponentName;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.ServiceConnection;
43 import android.content.pm.PackageManager;
44 import android.os.Handler;
45 import android.os.IBinder;
46 import android.os.Looper;
47 import android.os.RemoteException;
48 import android.os.UserHandle;
49 import android.util.Log;
50 
51 import com.android.internal.annotations.GuardedBy;
52 
53 import java.lang.annotation.Retention;
54 import java.lang.annotation.RetentionPolicy;
55 import java.util.HashMap;
56 
57 /**
58  *   Top level car API for embedded Android Auto deployments.
59  *   This API works only for devices with {@link PackageManager#FEATURE_AUTOMOTIVE}
60  *   Calling this API on a device with no such feature will lead to an exception.
61  */
62 public final class Car {
63 
64     /**
65      * Represent the version of Car API. This is only updated when there is API change.
66      * 1 : N
67      * 2 : O
68      * 3 : O-MR1
69      */
70     public static final int VERSION = 3;
71 
72     /** Service name for {@link CarSensorManager}, to be used in {@link #getCarManager(String)}. */
73     public static final String SENSOR_SERVICE = "sensor";
74 
75     /** Service name for {@link CarInfoManager}, to be used in {@link #getCarManager(String)}. */
76     public static final String INFO_SERVICE = "info";
77 
78     /** Service name for {@link CarAppFocusManager}. */
79     public static final String APP_FOCUS_SERVICE = "app_focus";
80 
81     /** Service name for {@link CarPackageManager} */
82     public static final String PACKAGE_SERVICE = "package";
83 
84     /** Service name for {@link CarAudioManager} */
85     public static final String AUDIO_SERVICE = "audio";
86 
87     /** Service name for {@link CarNavigationStatusManager} */
88     public static final String CAR_NAVIGATION_SERVICE = "car_navigation_service";
89 
90     /**
91      * Service name for {@link CarInstrumentClusterManager}
92      * @hide
93      */
94     public static final String CAR_INSTRUMENT_CLUSTER_SERVICE = "cluster_service";
95 
96     /**
97      * @hide
98      */
99     @SystemApi
100     public static final String CABIN_SERVICE = "cabin";
101 
102     /**
103      * @hide
104      */
105     @SystemApi
106     public static final String DIAGNOSTIC_SERVICE = "diagnostic";
107 
108     /**
109      * @hide
110      */
111     @SystemApi
112     public static final String HVAC_SERVICE = "hvac";
113 
114     /**
115      * @hide
116      */
117     @SystemApi
118     public static final String POWER_SERVICE = "power";
119 
120     /**
121      * @hide
122      */
123     @SystemApi
124     public static final String PROJECTION_SERVICE = "projection";
125 
126     /**
127      * @hide
128      */
129     @SystemApi
130     public static final String PROPERTY_SERVICE = "property";
131 
132     /**
133      * @hide
134      */
135     @SystemApi
136     public static final String VENDOR_EXTENSION_SERVICE = "vendor_extension";
137 
138     /**
139      * @hide
140      */
141     public static final String BLUETOOTH_SERVICE = "car_bluetooth";
142 
143     /**
144      * @hide
145      */
146     @SystemApi
147     public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
148 
149     /**
150      * Service name for {@link CarDrivingStateManager}
151      * @hide
152      */
153     @SystemApi
154     public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate";
155 
156     /**
157      * Service name for {@link CarUxRestrictionsManager}
158      */
159     public static final String CAR_UX_RESTRICTION_SERVICE = "uxrestriction";
160 
161     /**
162      * Service name for {@link android.car.settings.CarConfigurationManager}
163      */
164     public static final String CAR_CONFIGURATION_SERVICE = "configuration";
165 
166     /**
167      * @hide
168      */
169     @SystemApi
170     public static final String STORAGE_MONITORING_SERVICE = "storage_monitoring";
171 
172     /**
173      * Service for testing. This is system app only feature.
174      * Service name for {@link CarTestManager}, to be used in {@link #getCarManager(String)}.
175      * @hide
176      */
177     @SystemApi
178     public static final String TEST_SERVICE = "car-service-test";
179 
180     /** Permission necessary to access car's mileage information.
181      *  @hide
182      */
183     @SystemApi
184     public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
185 
186     /** Permission necessary to access car's energy information. */
187     public static final String PERMISSION_ENERGY = "android.car.permission.CAR_ENERGY";
188 
189     /** Permission necessary to access car's VIN information */
190     public static final String PERMISSION_IDENTIFICATION =
191             "android.car.permission.CAR_IDENTIFICATION";
192 
193     /** Permission necessary to access car's speed. */
194     public static final String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
195 
196     /** Permission necessary to access car's dynamics state.
197      *  @hide
198      */
199     @SystemApi
200     public static final String PERMISSION_CAR_DYNAMICS_STATE =
201             "android.car.permission.CAR_DYNAMICS_STATE";
202 
203     /** Permission necessary to access car's fuel door and ev charge port. */
204     public static final String PERMISSION_ENERGY_PORTS = "android.car.permission.CAR_ENERGY_PORTS";
205 
206     /** Permission necessary to read car's lights information.
207      *  @hide
208      */
209     @SystemApi
210     public static final String PERMISSION_EXTERIOR_LIGHTS =
211             "android.car.permission.CAR_EXTERIOR_LIGHTS";
212 
213     /** Permission necessary to control car's exterior lights.
214      *  @hide
215      */
216     @SystemApi
217     public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS =
218             "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
219 
220     /** Permission necessary to access car's powertrain information.*/
221     public static final String PERMISSION_POWERTRAIN = "android.car.permission.CAR_POWERTRAIN";
222 
223     /**
224      * Permission necessary to change car audio volume through {@link CarAudioManager}.
225      */
226     public static final String PERMISSION_CAR_CONTROL_AUDIO_VOLUME =
227             "android.car.permission.CAR_CONTROL_AUDIO_VOLUME";
228 
229     /**
230      * Permission necessary to change car audio settings through {@link CarAudioManager}.
231      * @hide
232      */
233     public static final String PERMISSION_CAR_CONTROL_AUDIO_SETTINGS =
234             "android.car.permission.CAR_CONTROL_AUDIO_SETTINGS";
235 
236     /**
237      * Permission necessary to use {@link CarNavigationStatusManager}.
238      */
239     public static final String PERMISSION_CAR_NAVIGATION_MANAGER =
240             "android.car.permission.CAR_NAVIGATION_MANAGER";
241 
242     /**
243      * Permission necessary to start activities in the instrument cluster through
244      * {@link CarInstrumentClusterManager}
245      *
246      * @hide
247      */
248     @SystemApi
249     public static final String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL =
250             "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL";
251 
252     /**
253      * Application must have this permission in order to be launched in the instrument cluster
254      * display.
255      *
256      * @hide
257      */
258     public static final String PERMISSION_CAR_DISPLAY_IN_CLUSTER =
259             "android.car.permission.CAR_DISPLAY_IN_CLUSTER";
260 
261     /** Permission necessary to use {@link CarInfoManager}. */
262     public static final String PERMISSION_CAR_INFO = "android.car.permission.CAR_INFO";
263 
264     /** Permission necessary to read temperature of car's exterior environment. */
265     public static final String PERMISSION_EXTERIOR_ENVIRONMENT =
266             "android.car.permission.CAR_EXTERIOR_ENVIRONMENT";
267 
268     /**
269      * Permission necessary to access car specific communication channel.
270      * @hide
271      */
272     @SystemApi
273     public static final String PERMISSION_VENDOR_EXTENSION =
274             "android.car.permission.CAR_VENDOR_EXTENSION";
275 
276     /**
277      * @hide
278      */
279     @SystemApi
280     public static final String PERMISSION_CONTROL_APP_BLOCKING =
281             "android.car.permission.CONTROL_APP_BLOCKING";
282 
283     /**
284      * Permission necessary to access Car Cabin APIs.
285      * @hide
286      */
287     @SystemApi
288     public static final String PERMISSION_ADJUST_CAR_CABIN =
289             "android.car.permission.ADJUST_CAR_CABIN";
290 
291     /**
292      * Permission necessary to access car's engine information.
293      * @hide
294      */
295     @SystemApi
296     public static final String PERMISSION_CAR_ENGINE_DETAILED =
297             "android.car.permission.CAR_ENGINE_DETAILED";
298 
299     /**
300      * Permission necessary to access car's tire pressure information.
301      * @hide
302      */
303     @SystemApi
304     public static final String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
305 
306     /**
307      * Permission necessary to control car's door.
308      * @hide
309      */
310     @SystemApi
311     public static final String PERMISSION_CONTROL_CAR_DOORS =
312             "android.car.permission.CONTROL_CAR_DOORS";
313 
314     /**
315      * Permission necessary to control car's windows.
316      * @hide
317      */
318     @SystemApi
319     public static final String PERMISSION_CONTROL_CAR_WINDOWS =
320             "android.car.permission.CONTROL_CAR_WINDOWS";
321 
322     /**
323      * Permission necessary to control car's seats.
324      * @hide
325      */
326     @SystemApi
327     public static final String PERMISSION_CONTROL_CAR_SEATS =
328             "android.car.permission.CONTROL_CAR_SEATS";
329 
330     /**
331      * Permission necessary to control car's mirrors.
332      * @hide
333      */
334     @SystemApi
335     public static final String PERMISSION_CONTROL_CAR_MIRRORS =
336             "android.car.permission.CONTROL_CAR_MIRRORS";
337 
338     /**
339      * Permission necessary to access Car HVAC APIs.
340      * @hide
341      */
342     @SystemApi
343     public static final String PERMISSION_CONTROL_CAR_CLIMATE =
344             "android.car.permission.CONTROL_CAR_CLIMATE";
345 
346     /**
347      * Permission necessary to access Car POWER APIs.
348      * @hide
349      */
350     @SystemApi
351     public static final String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER";
352 
353     /**
354      * Permission necessary to access Car PROJECTION system APIs.
355      * @hide
356      */
357     @SystemApi
358     public static final String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
359 
360     /**
361      * Permission necessary to mock vehicle hal for testing.
362      * @hide
363      * @deprecated mocking vehicle HAL in car service is no longer supported.
364      */
365     @SystemApi
366     public static final String PERMISSION_MOCK_VEHICLE_HAL =
367             "android.car.permission.CAR_MOCK_VEHICLE_HAL";
368 
369     /**
370      * Permission necessary to access CarTestService.
371      * @hide
372      */
373     @SystemApi
374     public static final String PERMISSION_CAR_TEST_SERVICE =
375             "android.car.permission.CAR_TEST_SERVICE";
376 
377     /**
378      * Permission necessary to access CarDrivingStateService to get a Car's driving state.
379      * @hide
380      */
381     @SystemApi
382     public static final String PERMISSION_CAR_DRIVING_STATE =
383             "android.car.permission.CAR_DRIVING_STATE";
384 
385     /**
386      * Permissions necessary to access VMS publisher APIs.
387      *
388      * @hide
389      */
390     @SystemApi
391     public static final String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER";
392 
393     /**
394      * Permissions necessary to access VMS subscriber APIs.
395      *
396      * @hide
397      */
398     @SystemApi
399     public static final String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
400 
401     /**
402      * Permissions necessary to read diagnostic information, including vendor-specific bits.
403      *
404      * @hide
405      */
406     @SystemApi
407     public static final String PERMISSION_CAR_DIAGNOSTIC_READ_ALL =
408         "android.car.permission.CAR_DIAGNOSTICS";
409 
410     /**
411      * Permissions necessary to clear diagnostic information.
412      *
413      * @hide
414      */
415     @SystemApi
416     public static final String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.CLEAR_CAR_DIAGNOSTICS";
417 
418     /**
419      * Permissions necessary to clear diagnostic information.
420      *
421      * @hide
422      */
423     @SystemApi
424     public static final String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
425 
426     /** Type of car connection: platform runs directly in car. */
427     public static final int CONNECTION_TYPE_EMBEDDED = 5;
428 
429 
430     /** @hide */
431     @IntDef({CONNECTION_TYPE_EMBEDDED})
432     @Retention(RetentionPolicy.SOURCE)
433     public @interface ConnectionType {}
434 
435     /**
436      * CarXyzService throws IllegalStateException with this message is re-thrown as
437      * {@link CarNotConnectedException}.
438      *
439      * @hide
440      */
441     public static final String CAR_NOT_CONNECTED_EXCEPTION_MSG = "CarNotConnected";
442 
443     /**
444      * Activity Action: Provide media playing through a media template app.
445      * <p>Input: String extra mapped by {@link android.app.SearchManager#QUERY} is the query
446      * used to start the media. String extra mapped by {@link #CAR_EXTRA_MEDIA_PACKAGE} is the
447      * package name of the media app which user wants to play media on.
448      * <p>Output: nothing.
449      */
450     public static final String CAR_INTENT_ACTION_MEDIA_TEMPLATE =
451             "android.car.intent.action.MEDIA_TEMPLATE";
452 
453     /**
454      * Used as a string extra field with {@link #CAR_INTENT_ACTION_MEDIA_TEMPLATE} to specify the
455      * media app that user wants to start the media on. Note: this is not the templated media app.
456      */
457     public static final String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
458 
459     /** @hide */
460     public static final String CAR_SERVICE_INTERFACE_NAME = "android.car.ICar";
461 
462     private static final String CAR_SERVICE_PACKAGE = "com.android.car";
463 
464     private static final String CAR_SERVICE_CLASS = "com.android.car.CarService";
465 
466     private static final long CAR_SERVICE_BIND_RETRY_INTERVAL_MS = 500;
467     private static final long CAR_SERVICE_BIND_MAX_RETRY = 20;
468 
469     private final Context mContext;
470     @GuardedBy("this")
471     private ICar mService;
472     private final boolean mOwnsService;
473     private static final int STATE_DISCONNECTED = 0;
474     private static final int STATE_CONNECTING = 1;
475     private static final int STATE_CONNECTED = 2;
476     @GuardedBy("this")
477     private int mConnectionState;
478     @GuardedBy("this")
479     private int mConnectionRetryCount;
480 
481     private final Runnable mConnectionRetryRunnable = new Runnable() {
482         @Override
483         public void run() {
484             startCarService();
485         }
486     };
487 
488     private final Runnable mConnectionRetryFailedRunnable = new Runnable() {
489         @Override
490         public void run() {
491             mServiceConnectionListener.onServiceDisconnected(new ComponentName(CAR_SERVICE_PACKAGE,
492                     CAR_SERVICE_CLASS));
493         }
494     };
495 
496     private final ServiceConnection mServiceConnectionListener =
497             new ServiceConnection () {
498         public void onServiceConnected(ComponentName name, IBinder service) {
499             synchronized (Car.this) {
500                 mService = ICar.Stub.asInterface(service);
501                 mConnectionState = STATE_CONNECTED;
502             }
503             mServiceConnectionListenerClient.onServiceConnected(name, service);
504         }
505 
506         public void onServiceDisconnected(ComponentName name) {
507             synchronized (Car.this) {
508                 mService = null;
509                 if (mConnectionState  == STATE_DISCONNECTED) {
510                     return;
511                 }
512                 mConnectionState = STATE_DISCONNECTED;
513             }
514             // unbind explicitly here.
515             disconnect();
516             mServiceConnectionListenerClient.onServiceDisconnected(name);
517         }
518     };
519 
520     private final ServiceConnection mServiceConnectionListenerClient;
521     private final Object mCarManagerLock = new Object();
522     @GuardedBy("mCarManagerLock")
523     private final HashMap<String, CarManagerBase> mServiceMap = new HashMap<>();
524 
525     /** Handler for generic event dispatching. */
526     private final Handler mEventHandler;
527 
528     private final Handler mMainThreadEventHandler;
529 
530     /**
531      * A factory method that creates Car instance for all Car API access.
532      * @param context
533      * @param serviceConnectionListener listener for monitoring service connection.
534      * @param handler the handler on which the callback should execute, or null to execute on the
535      * service's main thread. Note: the service connection listener will be always on the main
536      * thread regardless of the handler given.
537      * @return Car instance if system is in car environment and returns {@code null} otherwise.
538      */
createCar(Context context, ServiceConnection serviceConnectionListener, @Nullable Handler handler)539     public static Car createCar(Context context, ServiceConnection serviceConnectionListener,
540             @Nullable Handler handler) {
541         if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
542             Log.e(CarLibLog.TAG_CAR, "FEATURE_AUTOMOTIVE not declared while android.car is used");
543             return null;
544         }
545         try {
546           return new Car(context, serviceConnectionListener, handler);
547         } catch (IllegalArgumentException e) {
548           // Expected when car service loader is not available.
549         }
550         return null;
551     }
552 
553     /**
554      * A factory method that creates Car instance for all Car API access using main thread {@code
555      * Looper}.
556      *
557      * @see #createCar(Context, ServiceConnection, Handler)
558      */
createCar(Context context, ServiceConnection serviceConnectionListener)559     public static Car createCar(Context context, ServiceConnection serviceConnectionListener) {
560       return createCar(context, serviceConnectionListener, null);
561     }
562 
Car(Context context, ServiceConnection serviceConnectionListener, @Nullable Handler handler)563     private Car(Context context, ServiceConnection serviceConnectionListener,
564             @Nullable Handler handler) {
565         mContext = context;
566         mEventHandler = determineEventHandler(handler);
567         mMainThreadEventHandler = determineMainThreadEventHandler(mEventHandler);
568 
569         mService = null;
570         mOwnsService = true;
571         mServiceConnectionListenerClient = serviceConnectionListener;
572     }
573 
574 
575     /**
576      * Car constructor when ICar binder is already available.
577      * @hide
578      */
Car(Context context, ICar service, @Nullable Handler handler)579     public Car(Context context, ICar service, @Nullable Handler handler) {
580         mContext = context;
581         mEventHandler = determineEventHandler(handler);
582         mMainThreadEventHandler = determineMainThreadEventHandler(mEventHandler);
583 
584         mService = service;
585         mOwnsService = false;
586         mConnectionState = STATE_CONNECTED;
587         mServiceConnectionListenerClient = null;
588     }
589 
determineMainThreadEventHandler(Handler eventHandler)590     private static Handler determineMainThreadEventHandler(Handler eventHandler) {
591         Looper mainLooper = Looper.getMainLooper();
592         return (eventHandler.getLooper() == mainLooper) ? eventHandler : new Handler(mainLooper);
593     }
594 
determineEventHandler(@ullable Handler handler)595     private static Handler determineEventHandler(@Nullable Handler handler) {
596         if (handler == null) {
597             Looper looper = Looper.getMainLooper();
598             handler = new Handler(looper);
599         }
600         return handler;
601     }
602 
603     /**
604      * Connect to car service. This can be called while it is disconnected.
605      * @throws IllegalStateException If connection is still on-going from previous
606      *         connect call or it is already connected
607      */
connect()608     public void connect() throws IllegalStateException {
609         synchronized (this) {
610             if (mConnectionState != STATE_DISCONNECTED) {
611                 throw new IllegalStateException("already connected or connecting");
612             }
613             mConnectionState = STATE_CONNECTING;
614             startCarService();
615         }
616     }
617 
618     /**
619      * Disconnect from car service. This can be called while disconnected. Once disconnect is
620      * called, all Car*Managers from this instance becomes invalid, and
621      * {@link Car#getCarManager(String)} will return different instance if it is connected again.
622      */
disconnect()623     public void disconnect() {
624         synchronized (this) {
625             if (mConnectionState == STATE_DISCONNECTED) {
626                 return;
627             }
628             mEventHandler.removeCallbacks(mConnectionRetryRunnable);
629             mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable);
630             mConnectionRetryCount = 0;
631             tearDownCarManagers();
632             mService = null;
633             mConnectionState = STATE_DISCONNECTED;
634 
635             if (mOwnsService) {
636                 mContext.unbindService(mServiceConnectionListener);
637             }
638         }
639     }
640 
641     /**
642      * Tells if it is connected to the service or not. This will return false if it is still
643      * connecting.
644      * @return
645      */
isConnected()646     public boolean isConnected() {
647         synchronized (this) {
648             return mService != null;
649         }
650     }
651 
652     /**
653      * Tells if this instance is already connecting to car service or not.
654      * @return
655      */
isConnecting()656     public boolean isConnecting() {
657         synchronized (this) {
658             return mConnectionState == STATE_CONNECTING;
659         }
660     }
661 
662     /**
663      * Get car specific service as in {@link Context#getSystemService(String)}. Returned
664      * {@link Object} should be type-casted to the desired service.
665      * For example, to get sensor service,
666      * SensorManagerService sensorManagerService = car.getCarManager(Car.SENSOR_SERVICE);
667      * @param serviceName Name of service that should be created like {@link #SENSOR_SERVICE}.
668      * @return Matching service manager or null if there is no such service.
669      * @throws CarNotConnectedException if the connection to the car service has been lost.
670      */
getCarManager(String serviceName)671     public Object getCarManager(String serviceName) throws CarNotConnectedException {
672         CarManagerBase manager;
673         ICar service = getICarOrThrow();
674         synchronized (mCarManagerLock) {
675             manager = mServiceMap.get(serviceName);
676             if (manager == null) {
677                 try {
678                     IBinder binder = service.getCarService(serviceName);
679                     if (binder == null) {
680                         Log.w(CarLibLog.TAG_CAR, "getCarManager could not get binder for service:" +
681                                 serviceName);
682                         return null;
683                     }
684                     manager = createCarManager(serviceName, binder);
685                     if (manager == null) {
686                         Log.w(CarLibLog.TAG_CAR,
687                                 "getCarManager could not create manager for service:" +
688                                         serviceName);
689                         return null;
690                     }
691                     mServiceMap.put(serviceName, manager);
692                 } catch (RemoteException e) {
693                     handleRemoteException(e);
694                 }
695             }
696         }
697         return manager;
698     }
699 
700     /**
701      * Return the type of currently connected car.
702      * @return
703      */
704     @ConnectionType
getCarConnectionType()705     public int getCarConnectionType() {
706         return CONNECTION_TYPE_EMBEDDED;
707     }
708 
709     /**
710      * IllegalStateException from XyzCarService with special message is re-thrown as a different
711      * exception. If the IllegalStateException is not understood then this message will throw the
712      * original exception.
713      *
714      * @param e exception from XyzCarService.
715      * @throws CarNotConnectedException if the connection to the car service has been lost.
716      * @hide
717      */
checkCarNotConnectedExceptionFromCarService( IllegalStateException e)718     public static void checkCarNotConnectedExceptionFromCarService(
719             IllegalStateException e) throws CarNotConnectedException, IllegalStateException {
720         String message = e.getMessage();
721         if (CAR_NOT_CONNECTED_EXCEPTION_MSG.equals(message)) {
722             throw new CarNotConnectedException();
723         } else {
724             throw e;
725         }
726     }
727 
728     /** @hide */
hideCarNotConnectedExceptionFromCarService( IllegalStateException e)729     public static void hideCarNotConnectedExceptionFromCarService(
730             IllegalStateException e) throws IllegalStateException {
731         String message = e.getMessage();
732         if (CAR_NOT_CONNECTED_EXCEPTION_MSG.equals(message)) {
733             return; //ignore
734         } else {
735             throw e;
736         }
737     }
738 
createCarManager(String serviceName, IBinder binder)739     private CarManagerBase createCarManager(String serviceName, IBinder binder)
740             throws CarNotConnectedException {
741         CarManagerBase manager = null;
742         switch (serviceName) {
743             case AUDIO_SERVICE:
744                 manager = new CarAudioManager(binder, mContext, mEventHandler);
745                 break;
746             case SENSOR_SERVICE:
747                 manager = new CarSensorManager(binder, mContext, mEventHandler);
748                 break;
749             case INFO_SERVICE:
750                 manager = new CarInfoManager(binder);
751                 break;
752             case APP_FOCUS_SERVICE:
753                 manager = new CarAppFocusManager(binder, mEventHandler);
754                 break;
755             case PACKAGE_SERVICE:
756                 manager = new CarPackageManager(binder, mContext);
757                 break;
758             case CAR_NAVIGATION_SERVICE:
759                 manager = new CarNavigationStatusManager(binder);
760                 break;
761             case CABIN_SERVICE:
762                 manager = new CarCabinManager(binder, mContext, mEventHandler);
763                 break;
764             case DIAGNOSTIC_SERVICE:
765                 manager = new CarDiagnosticManager(binder, mContext, mEventHandler);
766                 break;
767             case HVAC_SERVICE:
768                 manager = new CarHvacManager(binder, mContext, mEventHandler);
769                 break;
770             case POWER_SERVICE:
771                 manager = new CarPowerManager(binder, mContext, mEventHandler);
772                 break;
773             case PROJECTION_SERVICE:
774                 manager = new CarProjectionManager(binder, mEventHandler);
775                 break;
776             case PROPERTY_SERVICE:
777                 manager = new CarPropertyManager(binder, mEventHandler, false,
778                                                  "CarPropertyManager");
779                 break;
780             case VENDOR_EXTENSION_SERVICE:
781                 manager = new CarVendorExtensionManager(binder, mEventHandler);
782                 break;
783             case CAR_INSTRUMENT_CLUSTER_SERVICE:
784                 manager = new CarInstrumentClusterManager(binder, mEventHandler);
785                 break;
786             case TEST_SERVICE:
787                 /* CarTestManager exist in static library. So instead of constructing it here,
788                  * only pass binder wrapper so that CarTestManager can be constructed outside. */
789                 manager = new CarTestManagerBinderWrapper(binder);
790                 break;
791             case VMS_SUBSCRIBER_SERVICE:
792                 manager = new VmsSubscriberManager(binder);
793                 break;
794             case BLUETOOTH_SERVICE:
795                 manager = new CarBluetoothManager(binder, mContext);
796                 break;
797             case STORAGE_MONITORING_SERVICE:
798                 manager = new CarStorageMonitoringManager(binder, mEventHandler);
799                 break;
800             case CAR_DRIVING_STATE_SERVICE:
801                 manager = new CarDrivingStateManager(binder, mContext, mEventHandler);
802                 break;
803             case CAR_UX_RESTRICTION_SERVICE:
804                 manager = new CarUxRestrictionsManager(binder, mContext, mEventHandler);
805                 break;
806             case CAR_CONFIGURATION_SERVICE:
807                 manager = new CarConfigurationManager(binder);
808                 break;
809             default:
810                 break;
811         }
812         return manager;
813     }
814 
startCarService()815     private void startCarService() {
816         Intent intent = new Intent();
817         intent.setPackage(CAR_SERVICE_PACKAGE);
818         intent.setAction(Car.CAR_SERVICE_INTERFACE_NAME);
819         boolean bound = mContext.bindServiceAsUser(intent, mServiceConnectionListener,
820                 Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF);
821         if (!bound) {
822             mConnectionRetryCount++;
823             if (mConnectionRetryCount > CAR_SERVICE_BIND_MAX_RETRY) {
824                 Log.w(CarLibLog.TAG_CAR, "cannot bind to car service after max retry");
825                 mMainThreadEventHandler.post(mConnectionRetryFailedRunnable);
826             } else {
827                 mEventHandler.postDelayed(mConnectionRetryRunnable,
828                         CAR_SERVICE_BIND_RETRY_INTERVAL_MS);
829             }
830         } else {
831             mConnectionRetryCount = 0;
832         }
833     }
834 
getICarOrThrow()835     private synchronized ICar getICarOrThrow() throws IllegalStateException {
836         if (mService == null) {
837             throw new IllegalStateException("not connected");
838         }
839         return mService;
840     }
841 
handleRemoteException(RemoteException e)842     private void handleRemoteException(RemoteException e) {
843         Log.w(CarLibLog.TAG_CAR, "RemoteException", e);
844         disconnect();
845     }
846 
tearDownCarManagers()847     private void tearDownCarManagers() {
848         synchronized (mCarManagerLock) {
849             for (CarManagerBase manager: mServiceMap.values()) {
850                 manager.onCarDisconnected();
851             }
852             mServiceMap.clear();
853         }
854     }
855 }
856