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 android.car;
18
19import android.annotation.IntDef;
20import android.annotation.Nullable;
21import android.annotation.SystemApi;
22import android.car.cluster.CarInstrumentClusterManager;
23import android.car.content.pm.CarPackageManager;
24import android.car.diagnostic.CarDiagnosticManager;
25import android.car.drivingstate.CarDrivingStateManager;
26import android.car.drivingstate.CarUxRestrictionsManager;
27import android.car.hardware.CarSensorManager;
28import android.car.hardware.CarVendorExtensionManager;
29import android.car.hardware.cabin.CarCabinManager;
30import android.car.hardware.hvac.CarHvacManager;
31import android.car.hardware.power.CarPowerManager;
32import android.car.hardware.property.CarPropertyManager;
33import android.car.media.CarAudioManager;
34import android.car.navigation.CarNavigationStatusManager;
35import android.car.settings.CarConfigurationManager;
36import android.car.storagemonitoring.CarStorageMonitoringManager;
37import android.car.test.CarTestManagerBinderWrapper;
38import android.car.vms.VmsSubscriberManager;
39import android.content.ComponentName;
40import android.content.Context;
41import android.content.Intent;
42import android.content.ServiceConnection;
43import android.content.pm.PackageManager;
44import android.os.Handler;
45import android.os.IBinder;
46import android.os.Looper;
47import android.os.RemoteException;
48import android.os.UserHandle;
49import android.util.Log;
50
51import com.android.internal.annotations.GuardedBy;
52
53import java.lang.annotation.Retention;
54import java.lang.annotation.RetentionPolicy;
55import 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 */
62public 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     */
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     */
559    public static Car createCar(Context context, ServiceConnection serviceConnectionListener) {
560      return createCar(context, serviceConnectionListener, null);
561    }
562
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     */
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
590    private static Handler determineMainThreadEventHandler(Handler eventHandler) {
591        Looper mainLooper = Looper.getMainLooper();
592        return (eventHandler.getLooper() == mainLooper) ? eventHandler : new Handler(mainLooper);
593    }
594
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     */
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     */
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     */
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     */
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     */
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
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     */
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 */
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
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
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
835    private synchronized ICar getICarOrThrow() throws IllegalStateException {
836        if (mService == null) {
837            throw new IllegalStateException("not connected");
838        }
839        return mService;
840    }
841
842    private void handleRemoteException(RemoteException e) {
843        Log.w(CarLibLog.TAG_CAR, "RemoteException", e);
844        disconnect();
845    }
846
847    private void tearDownCarManagers() {
848        synchronized (mCarManagerLock) {
849            for (CarManagerBase manager: mServiceMap.values()) {
850                manager.onCarDisconnected();
851            }
852            mServiceMap.clear();
853        }
854    }
855}
856