/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.car; import static android.car.CarLibLog.TAG_CAR; import static android.car.feature.Flags.FLAG_ANDROID_VIC_VEHICLE_PROPERTIES; import static android.car.feature.Flags.FLAG_CLUSTER_HEALTH_MONITORING; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.Activity; import android.app.Service; import android.car.admin.CarDevicePolicyManager; import android.car.annotation.MandatoryFeature; import android.car.annotation.OptionalFeature; import android.car.app.CarActivityManager; import android.car.app.CarDisplayCompatManager; import android.car.builtin.os.BuildHelper; import android.car.builtin.os.ServiceManagerHelper; import android.car.cluster.CarInstrumentClusterManager; import android.car.cluster.ClusterActivityState; import android.car.cluster.ClusterHomeManager; import android.car.content.pm.CarPackageManager; import android.car.diagnostic.CarDiagnosticManager; import android.car.drivingstate.CarDrivingStateManager; import android.car.drivingstate.CarUxRestrictionsManager; import android.car.evs.CarEvsManager; import android.car.feature.Flags; import android.car.hardware.CarSensorManager; import android.car.hardware.CarVendorExtensionManager; import android.car.hardware.cabin.CarCabinManager; import android.car.hardware.hvac.CarHvacManager; import android.car.hardware.power.CarPowerManager; import android.car.hardware.property.CarPropertyManager; import android.car.hardware.property.ICarProperty; import android.car.input.CarInputManager; import android.car.media.CarAudioManager; import android.car.media.CarMediaIntents; import android.car.media.CarMediaManager; import android.car.navigation.CarNavigationStatusManager; import android.car.occupantawareness.OccupantAwarenessManager; import android.car.occupantconnection.CarOccupantConnectionManager; import android.car.os.CarPerformanceManager; import android.car.remoteaccess.CarRemoteAccessManager; import android.car.storagemonitoring.CarStorageMonitoringManager; import android.car.telemetry.CarTelemetryManager; import android.car.test.CarTestManager; import android.car.user.CarUserManager; import android.car.user.ExperimentalCarUserManager; import android.car.vms.VmsClientManager; import android.car.vms.VmsSubscriberManager; import android.car.watchdog.CarWatchdogManager; import android.car.wifi.CarWifiManager; import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.TransactionTooLargeException; import android.util.ArrayMap; import android.util.Slog; import com.android.car.internal.ICarBase; import com.android.car.internal.VisibleForHiddenApiCheck; import com.android.car.internal.common.CommonConstants; import com.android.car.internal.dep.SystemProperties; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; /** * Top level car API for Android Automotive OS deployments. * This API works only for devices with {@link PackageManager#FEATURE_AUTOMOTIVE} * Calling this API on a device with no such feature will lead to an exception. */ public final class Car implements ICarBase { /** * System property to define platform minor version. * *

Value is int string. Check {@link #PROPERTY_PLATFORM_MINOR_INT} for further details. * If not set, default value of {@code 0} is assumed. */ private static final String PROPERTY_PLATFORM_MINOR_VERSION = "ro.android.car.version.platform_minor"; /** * @deprecated - This does not return the correct version. Use * {@code getCarVersion().getMajorVersion()} instead. */ @Deprecated public static final int API_VERSION_MAJOR_INT = 34; /** * @deprecated - This does not return the correct version. Use * {@code getCarVersion().getMinorVersion()} instead */ @Deprecated public static final int API_VERSION_MINOR_INT = 0; /** * @deprecated - use {@code getPlatformApiVersion().getMinorVersion()} instead */ @Deprecated public static final int PLATFORM_VERSION_MINOR_INT = SystemProperties .getInt(PROPERTY_PLATFORM_MINOR_VERSION, /* def= */ 0); // These are the actual car api versions. Due to legacy reasons, we cannot modfiy // API_VERSION_MAJOR_INT and API_VERSION_MINOR_INT because they were exposed as public. private static final int ACTUAL_API_VERSION_MAJOR_INT = Build.VERSION.SDK_INT; private static final int ACTUAL_API_VERSION_MINOR_INT = 0; private static final CarVersion CAR_VERSION = CarVersion.newInstance("Car.CAR_VERSION", ACTUAL_API_VERSION_MAJOR_INT, ACTUAL_API_VERSION_MINOR_INT); private static final PlatformVersion PLATFORM_VERSION; /** * @hide */ @TestApi public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR = "com.android.car.internal.debug.platform_major_version"; /** * @hide */ @TestApi public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MINOR = "com.android.car.internal.debug.platform_minor_version"; static { PlatformVersion emulated = null; if (!BuildHelper.isUserBuild()) { int major = SystemProperties.getInt(PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR, -1); if (major != -1) { int minor = SystemProperties.getInt(PROPERTY_EMULATED_PLATFORM_VERSION_MINOR, PLATFORM_VERSION_MINOR_INT); emulated = android.car.PlatformVersion.newInstance("EMULATED", major, minor); Slog.i(TAG_CAR, "Emulating PLATFORM_VERSION version: " + emulated); } } PLATFORM_VERSION = emulated != null ? emulated : PlatformVersion.getCurrentPlatformVersionForMinor( "Car.PLATFORM_VERSION", PLATFORM_VERSION_MINOR_INT); } // Car service registry information. // This information never changes after the static initialization completes. private static final Map, String> CAR_SERVICE_NAMES = new ArrayMap, String>(38); /** * Binder service name of car service registered to service manager. * * @hide */ @VisibleForHiddenApiCheck public static final String CAR_SERVICE_BINDER_SERVICE_NAME = "car_service"; /** * This represents AndroidManifest meta-data to tell that {@code Activity} is optimized for * driving distraction. * *

Activities without this meta-data can be blocked while car is in moving / driving state. * *

Note that having this flag does not guarantee that the {@code Activity} will be always * allowed for all driving states. * *

For this meta-data, android:value can be {@code true} (=optimized) or {@code false}. * *

Example usage: * */ @SuppressLint("IntentName") public static final String META_DATA_DISTRACTION_OPTIMIZED = "distractionOptimized"; /** * This represents AndroidManifest meta-data to tell that {@code Application} requires specific * car features to work. * *

Apps like launcher or installer app can use this information to filter out apps * not usable in a specific car. This meta-data is not necessary for mandatory features. * *

For this meta-data, android:value should contain the feature name string defined by * {@code OptionalFeature} or {@code ExperimentalFeature} annotations. * *

Example usage: * */ @SuppressLint("IntentName") public static final String META_DATA_REQUIRES_CAR_FEATURE = "requires-car-feature"; /** * Service name for {@link CarSensorManager}, to be used in {@link #getCarManager(String)}. * * @deprecated {@link CarSensorManager} is deprecated. Use {@link CarPropertyManager} instead. */ @MandatoryFeature @Deprecated public static final String SENSOR_SERVICE = "sensor"; /** Service name for {@link CarInfoManager}, to be used in {@link #getCarManager(String)}. */ @MandatoryFeature public static final String INFO_SERVICE = "info"; /** Service name for {@link CarAppFocusManager}. */ @MandatoryFeature public static final String APP_FOCUS_SERVICE = "app_focus"; /** Service name for {@link CarPackageManager} */ @MandatoryFeature public static final String PACKAGE_SERVICE = "package"; /** Service name for {@link CarAudioManager} */ @MandatoryFeature public static final String AUDIO_SERVICE = "audio"; /** Service name for {@code CarNavigationStatusManager} */ @OptionalFeature public static final String CAR_NAVIGATION_SERVICE = "car_navigation_service"; /** * Service name for {@link CarOccupantConnectionManager}. * * @hide */ @OptionalFeature @SystemApi public static final String CAR_OCCUPANT_CONNECTION_SERVICE = "car_occupant_connection_service"; /** * Service name for {@link CarRemoteDeviceManager}. * * @hide */ @OptionalFeature @SystemApi public static final String CAR_REMOTE_DEVICE_SERVICE = "car_remote_device_service"; /** Service name for {@link CarOccupantZoneManager} */ @MandatoryFeature public static final String CAR_OCCUPANT_ZONE_SERVICE = "car_occupant_zone_service"; /** * Service name for {@link CarUserManager} * * @hide */ @MandatoryFeature @SystemApi public static final String CAR_USER_SERVICE = "car_user_service"; /** * Service name for {@link ExperimentalCarUserManager} * * @hide * @deprecated {@link ExperimentalCarUserManager} was an experimental feature and is no longer * supported. It will be marked {@code @removed} in the next major release and hard removed in * the release after that. */ @Deprecated @OptionalFeature public static final String EXPERIMENTAL_CAR_USER_SERVICE = "experimental_car_user_service"; /** * Service name for ExperimentalCarKeyguardService * * @hide */ @OptionalFeature public static final String EXPERIMENTAL_CAR_KEYGUARD_SERVICE = "experimental_car_keyguard_service"; /** * Service name for {@link CarDevicePolicyManager} * * @hide */ @MandatoryFeature @SystemApi public static final String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service"; /** * Service name for {@link CarInstrumentClusterManager} * * @deprecated CarInstrumentClusterManager is being deprecated * @hide */ @OptionalFeature @Deprecated public static final String CAR_INSTRUMENT_CLUSTER_SERVICE = "cluster_service"; /** * Service name for {@link CarCabinManager}. * * @deprecated {@link CarCabinManager} is deprecated. Use {@link CarPropertyManager} instead. * @hide */ @MandatoryFeature @Deprecated @SystemApi public static final String CABIN_SERVICE = "cabin"; /** * Service name for {@link android.car.diagnostic.CarDiagnosticManager}. * @hide */ @OptionalFeature @SystemApi public static final String DIAGNOSTIC_SERVICE = "diagnostic"; /** * Service name for {@link CarHvacManager} * @deprecated {@link CarHvacManager} is deprecated. Use {@link CarPropertyManager} instead. * @hide */ @MandatoryFeature @Deprecated @SystemApi public static final String HVAC_SERVICE = "hvac"; /** * Service name for {@link CarPowerManager} */ @MandatoryFeature public static final String POWER_SERVICE = "power"; /** * Service name for {@link android.car.CarProjectionManager} * @hide */ @MandatoryFeature @SystemApi public static final String PROJECTION_SERVICE = "projection"; /** * Service name for {@link CarPropertyManager} */ @MandatoryFeature public static final String PROPERTY_SERVICE = "property"; /** * Service name for {@link CarVendorExtensionManager} * * @deprecated {@link CarVendorExtensionManager} is deprecated. * Use {@link CarPropertyManager} instead. * @hide */ @MandatoryFeature @Deprecated @SystemApi public static final String VENDOR_EXTENSION_SERVICE = "vendor_extension"; /** * Service name for {@link VmsClientManager} * * @hide */ @OptionalFeature @SystemApi public static final String VEHICLE_MAP_SERVICE = "vehicle_map_service"; /** * Service name for {@link VmsSubscriberManager} * * @deprecated {@link VmsSubscriberManager} is deprecated. Use {@link VmsClientManager} instead. * @hide */ @OptionalFeature @Deprecated @SystemApi public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service"; /** * Service name for {@link CarDrivingStateManager} * @hide */ @MandatoryFeature @SystemApi public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate"; /** * Service name for {@link CarUxRestrictionsManager} */ public static final String CAR_UX_RESTRICTION_SERVICE = "uxrestriction"; /** * Service name for {@link android.car.occupantawareness.OccupantAwarenessManager} * @hide */ @OptionalFeature @SystemApi public static final String OCCUPANT_AWARENESS_SERVICE = "occupant_awareness"; /** * Service name for {@link android.car.media.CarMediaManager} * @hide */ @MandatoryFeature @SystemApi public static final String CAR_MEDIA_SERVICE = "car_media"; /** * Service name for {@link android.car.CarBugreportManager} * @hide */ @MandatoryFeature @SystemApi public static final String CAR_BUGREPORT_SERVICE = "car_bugreport"; /** * Service name for {@link android.car.storagemonitoring.CarStorageMonitoringManager} * @hide */ @OptionalFeature @SystemApi public static final String STORAGE_MONITORING_SERVICE = "storage_monitoring"; /** * Service name for {@link android.car.watchdog.CarWatchdogManager} */ @MandatoryFeature public static final String CAR_WATCHDOG_SERVICE = "car_watchdog"; /** * Service name for {@link android.car.os.CarPerformanceManager} * * @hide */ @MandatoryFeature @SystemApi public static final String CAR_PERFORMANCE_SERVICE = "car_performance"; /** * Service name for {@link android.car.input.CarInputManager} * @hide */ @MandatoryFeature @SystemApi public static final String CAR_INPUT_SERVICE = "android.car.input"; /** * Service name for {@link android.car.cluster.ClusterHomeManager} * @hide */ @OptionalFeature public static final String CLUSTER_HOME_SERVICE = "cluster_home_service"; /** * Service for testing. This is system app only feature. * Service name for {@link CarTestManager}, to be used in {@link #getCarManager(String)}. * @hide */ @MandatoryFeature @SystemApi public static final String TEST_SERVICE = "car-service-test"; /** * Service name for {@link android.car.evs.CarEvsManager} * * @hide */ @OptionalFeature @SystemApi public static final String CAR_EVS_SERVICE = "car_evs_service"; /** * Service name for {@link android.car.telemetry.CarTelemetryManager} * * @hide */ @OptionalFeature @SystemApi public static final String CAR_TELEMETRY_SERVICE = "car_telemetry_service"; /** * Service name for {@link android.car.app.CarActivityManager} * * @hide */ @MandatoryFeature @SystemApi public static final String CAR_ACTIVITY_SERVICE = "car_activity_service"; /** * Service name for {@link android.car.remoteaccess.CarRemoteAccessManager} * * @hide */ @OptionalFeature @SystemApi public static final String CAR_REMOTE_ACCESS_SERVICE = "car_remote_access_service"; /** * Service name for {@link android.car.wifi.CarWifiManager} * * @hide */ @MandatoryFeature @SystemApi @FlaggedApi(Flags.FLAG_PERSIST_AP_SETTINGS) public static final String CAR_WIFI_SERVICE = "car_wifi_service"; /** * Permission necessary to read driver monitoring systems settings information. * * Examples of settings include the ENABLED properties for the supported driver monitoring * features. * @hide */ @SystemApi public static final String PERMISSION_READ_DRIVER_MONITORING_SETTINGS = "android.car.permission.READ_DRIVER_MONITORING_SETTINGS"; /** * Permission necessary to control driver monitoring systems settings information. * * Examples of settings include the ENABLED properties for the supported driver monitoring * features. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_DRIVER_MONITORING_SETTINGS = "android.car.permission.CONTROL_DRIVER_MONITORING_SETTINGS"; /** * Permission necessary to read driver monitoring systems states information. * * Examples of states include the STATE and WARNING properties for the supported driver * monitoring features. * * This is different from {@link PERMISSION_READ_DRIVER_MONITORING_SETTINGS}, which allows an * app to read the system settings, such as whether the system is enabled or disabled. * @hide */ @SystemApi public static final String PERMISSION_READ_DRIVER_MONITORING_STATES = "android.car.permission.READ_DRIVER_MONITORING_STATES"; /** Permission necessary to access car's mileage information. * @hide */ @SystemApi public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE"; /** Permission necessary to access car's energy information. */ public static final String PERMISSION_ENERGY = "android.car.permission.CAR_ENERGY"; /** Permission necessary to control car's EV charge settings. */ public static final String PERMISSION_CONTROL_CAR_ENERGY = "android.car.permission.CONTROL_CAR_ENERGY"; /** * Permission necessary to change value of car's range remaining. * @hide */ @SystemApi public static final String PERMISSION_ADJUST_RANGE_REMAINING = "android.car.permission.ADJUST_RANGE_REMAINING"; /** Permission necessary to access car's VIN information */ public static final String PERMISSION_IDENTIFICATION = "android.car.permission.CAR_IDENTIFICATION"; /** Permission necessary to access car's speed. */ public static final String PERMISSION_SPEED = "android.car.permission.CAR_SPEED"; /** Permission necessary to access car's dynamics state. * @hide */ @SystemApi public static final String PERMISSION_CAR_DYNAMICS_STATE = "android.car.permission.CAR_DYNAMICS_STATE"; /** Permission necessary to control car's dynamics state. * @hide */ @FlaggedApi(Flags.FLAG_ANDROID_VIC_VEHICLE_PROPERTIES) @SystemApi public static final String PERMISSION_CONTROL_CAR_DYNAMICS_STATE = "android.car.permission.CONTROL_CAR_DYNAMICS_STATE"; /** Permission necessary to access car's fuel door and ev charge port. */ public static final String PERMISSION_ENERGY_PORTS = "android.car.permission.CAR_ENERGY_PORTS"; /** * Permission necessary to control car's fuel door and ev charge port. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_ENERGY_PORTS = "android.car.permission.CONTROL_CAR_ENERGY_PORTS"; /** * Permission necessary to read car's exterior lights information. * @hide */ @SystemApi public static final String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS"; /** * Permission necessary to read car's interior lights information. */ public static final String PERMISSION_READ_INTERIOR_LIGHTS = "android.car.permission.READ_CAR_INTERIOR_LIGHTS"; /** Permission necessary to control car's exterior lights. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"; /** * Permission necessary to control car's interior lights. */ public static final String PERMISSION_CONTROL_INTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_INTERIOR_LIGHTS"; /** Permission necessary to access car's powertrain information.*/ public static final String PERMISSION_POWERTRAIN = "android.car.permission.CAR_POWERTRAIN"; /** * Permission necessary to control car's powertrain information. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_POWERTRAIN = "android.car.permission.CONTROL_CAR_POWERTRAIN"; /** * Permission necessary to change car audio volume through {@link CarAudioManager}. */ public static final String PERMISSION_CAR_CONTROL_AUDIO_VOLUME = "android.car.permission.CAR_CONTROL_AUDIO_VOLUME"; /** * Permission necessary to change car audio settings through {@link CarAudioManager}. */ public static final String PERMISSION_CAR_CONTROL_AUDIO_SETTINGS = "android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"; /** * Permission necessary to receive full audio ducking events from car audio focus handler. * * @hide */ @SystemApi public static final String PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS = "android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS"; /** * Permission necessary to use {@code CarNavigationStatusManager}. */ public static final String PERMISSION_CAR_NAVIGATION_MANAGER = "android.car.permission.CAR_NAVIGATION_MANAGER"; /** * Permission necessary to start activities in the instrument cluster through * {@link CarInstrumentClusterManager} * * @hide */ @SystemApi public static final String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL = "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"; /** * Permission necessary to listen for the instrument cluster's navigation state changes. * * @hide */ @FlaggedApi(FLAG_CLUSTER_HEALTH_MONITORING) @SystemApi public static final String PERMISSION_CAR_MONITOR_CLUSTER_NAVIGATION_STATE = "android.car.permission.CAR_MONITOR_CLUSTER_NAVIGATION_STATE"; /** * Application must have this permission in order to be launched in the instrument cluster * display. * * @hide */ @VisibleForHiddenApiCheck public static final String PERMISSION_CAR_DISPLAY_IN_CLUSTER = "android.car.permission.CAR_DISPLAY_IN_CLUSTER"; /** Permission necessary to use {@link CarInfoManager}. */ public static final String PERMISSION_CAR_INFO = "android.car.permission.CAR_INFO"; /** Permission necessary to access privileged car info. */ public static final String PERMISSION_PRIVILEGED_CAR_INFO = "android.car.permission.PRIVILEGED_CAR_INFO"; /** * Permission necessary to read information of vendor properties' permissions. * @hide */ @SystemApi public static final String PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO = "android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO"; /** Permission necessary to read temperature of car's exterior environment. */ public static final String PERMISSION_EXTERIOR_ENVIRONMENT = "android.car.permission.CAR_EXTERIOR_ENVIRONMENT"; /** * Permission necessary to access car specific communication channel. * @hide */ @SystemApi public static final String PERMISSION_VENDOR_EXTENSION = "android.car.permission.CAR_VENDOR_EXTENSION"; /** * @hide */ @SystemApi public static final String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING"; /** * Permission necessary to access car's engine information. * @hide */ @SystemApi public static final String PERMISSION_CAR_ENGINE_DETAILED = "android.car.permission.CAR_ENGINE_DETAILED"; /** * Permission necessary to access car's tire pressure information. * @hide */ @SystemApi public static final String PERMISSION_TIRES = "android.car.permission.CAR_TIRES"; /** * Permission necessary to access car's property {@link VehiclePropertyIds#EPOCH_TIME}. * @hide */ @SystemApi public static final String PERMISSION_CAR_EPOCH_TIME = "android.car.permission.CAR_EPOCH_TIME"; /** * Permission necessary to access car's steering angle information. */ public static final String PERMISSION_READ_STEERING_STATE = "android.car.permission.READ_CAR_STEERING"; /** * Permission necessary to read and write display units for distance, fuel volume, tire pressure * and ev battery. */ public static final String PERMISSION_READ_DISPLAY_UNITS = "android.car.permission.READ_CAR_DISPLAY_UNITS"; /** * Permission necessary to control display units for distance, fuel volume, tire pressure * and ev battery. Currently, all display unit properties require both {@code * PERMISSION_CONTROL_DISPLAY_UNITS} and {@code PERMISSION_VENDOR_EXTENSION} to be granted in * order to write to them. */ public static final String PERMISSION_CONTROL_DISPLAY_UNITS = "android.car.permission.CONTROL_CAR_DISPLAY_UNITS"; /** * Permission necessary to control car's door. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_DOORS = "android.car.permission.CONTROL_CAR_DOORS"; /** * Permission necessary to control car's windows. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_WINDOWS = "android.car.permission.CONTROL_CAR_WINDOWS"; /** * Permission necessary to control car glove box. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_GLOVE_BOX = "android.car.permission.CONTROL_GLOVE_BOX"; /** * Permission necessary to control car's seats. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_SEATS = "android.car.permission.CONTROL_CAR_SEATS"; /** * Permission necessary to control car's mirrors. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_MIRRORS = "android.car.permission.CONTROL_CAR_MIRRORS"; /** * Permission necessary to access Car HVAC APIs. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_CLIMATE = "android.car.permission.CONTROL_CAR_CLIMATE"; /** * Permission necessary to enable/disable a seat's ability to deploy airbag(s) when triggered * (e.g. by a crash). * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_AIRBAGS = "android.car.permission.CONTROL_CAR_AIRBAGS"; /** * Permission necessary to access restrictive car power management APIs. * @hide */ @SystemApi public static final String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER"; /** * Permission necessary to read the current power policy or be notified of power policy change. */ public static final String PERMISSION_READ_CAR_POWER_POLICY = "android.car.permission.READ_CAR_POWER_POLICY"; /** * Permission necessary to apply a new power policy. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_POWER_POLICY = "android.car.permission.CONTROL_CAR_POWER_POLICY"; /** * Permission necessary to adjust the shutdown process. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_SHUTDOWN_PROCESS = "android.car.permission.CONTROL_SHUTDOWN_PROCESS"; /** * Permission necessary to access Car PROJECTION system APIs. * @hide */ @SystemApi public static final String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION"; /** * Permission necessary to access projection status. * @hide */ @SystemApi public static final String PERMISSION_CAR_PROJECTION_STATUS = "android.car.permission.ACCESS_CAR_PROJECTION_STATUS"; /** * Permission necessary to mock vehicle hal for testing. * @hide * @deprecated mocking vehicle HAL in car service is no longer supported. */ @Deprecated @SystemApi public static final String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL"; /** * Permission necessary to access CarTestService. * @hide */ @SystemApi public static final String PERMISSION_CAR_TEST_SERVICE = "android.car.permission.CAR_TEST_SERVICE"; /** * Permission necessary to access CarDrivingStateService to get a Car's driving state. * @hide */ @SystemApi public static final String PERMISSION_CAR_DRIVING_STATE = "android.car.permission.CAR_DRIVING_STATE"; /** * Permission necessary to access VMS client service. * * @hide */ @VisibleForHiddenApiCheck public static final String PERMISSION_BIND_VMS_CLIENT = "android.car.permission.BIND_VMS_CLIENT"; /** * Permissions necessary to access VMS publisher APIs. * * @hide */ @SystemApi public static final String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER"; /** * Permissions necessary to access VMS subscriber APIs. * * @hide */ @SystemApi public static final String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER"; /** * Permission necessary to read ultrasonics sensor data. * @hide */ @FlaggedApi(FLAG_ANDROID_VIC_VEHICLE_PROPERTIES) @SystemApi public static final String PERMISSION_READ_ULTRASONICS_SENSOR_DATA = "android.car.permission.READ_ULTRASONICS_SENSOR_DATA"; /** * Permissions necessary to read diagnostic information, including vendor-specific bits. * * @hide */ @SystemApi public static final String PERMISSION_CAR_DIAGNOSTIC_READ_ALL = "android.car.permission.CAR_DIAGNOSTICS"; /** * Permissions necessary to clear diagnostic information. * * @hide */ @SystemApi public static final String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.CLEAR_CAR_DIAGNOSTICS"; /** * Permission necessary to configure UX restrictions through {@link CarUxRestrictionsManager}. * * @hide */ @VisibleForHiddenApiCheck @SystemApi public static final String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION = "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION"; /** * Permission necessary to listen to occupant awareness state {@link OccupantAwarenessManager}. * * @hide */ @SystemApi public static final String PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE = "android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE"; /** * Permission necessary to access private display id. * * @hide */ @SystemApi public static final String ACCESS_PRIVATE_DISPLAY_ID = "android.car.permission.ACCESS_PRIVATE_DISPLAY_ID"; /** * @deprecated This permission is not used by any service. * * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM = "android.car.permission.CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM"; /** * Permissions necessary to clear diagnostic information. * * @hide */ @SystemApi public static final String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING"; /** * Permission necessary to dynamically enable / disable optional car features. * * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_FEATURES = "android.car.permission.CONTROL_CAR_FEATURES"; /** * Permission necessary to be car watchdog clients. * * @hide */ @SystemApi public static final String PERMISSION_USE_CAR_WATCHDOG = "android.car.permission.USE_CAR_WATCHDOG"; /** * Permission necessary to monitor Car input events. * * @hide */ @SystemApi public static final String PERMISSION_CAR_MONITOR_INPUT = "android.car.permission.CAR_MONITOR_INPUT"; /** * Permission necessary to request CarEvsService to launch the special activity to show the * camera preview. * * @hide */ @SystemApi public static final String PERMISSION_REQUEST_CAR_EVS_ACTIVITY = "android.car.permission.REQUEST_CAR_EVS_ACTIVITY"; /** * Permission necessary to control the special activity to show the camera preview. * * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_EVS_ACTIVITY = "android.car.permission.CONTROL_CAR_EVS_ACTIVITY"; /** * Permission necessary to use the camera streams via CarEvsService. * * @hide */ @SystemApi public static final String PERMISSION_USE_CAR_EVS_CAMERA = "android.car.permission.USE_CAR_EVS_CAMERA"; /** * Permission necessary to monitor the status of CarEvsService. * * @hide */ @SystemApi public static final String PERMISSION_MONITOR_CAR_EVS_STATUS = "android.car.permission.MONITOR_CAR_EVS_STATUS"; /** * Permission necessary to use the CarTelemetryService. * * @hide */ @SystemApi public static final String PERMISSION_USE_CAR_TELEMETRY_SERVICE = "android.car.permission.USE_CAR_TELEMETRY_SERVICE"; /** * Type of car connection: platform runs directly in car. * * @deprecated connection type constants are no longer used */ @Deprecated public static final int CONNECTION_TYPE_EMBEDDED = 5; /** * Permission necessary to be able to render template-based UI metadata on behalf of another * application. * * @hide */ @SystemApi public static final String PERMISSION_TEMPLATE_RENDERER = "android.car.permission.TEMPLATE_RENDERER"; /** * Permission necessary to set or retrieve car watchdog configurations. * * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG = "android.car.permission.CONTROL_CAR_WATCHDOG_CONFIG"; /** * Permission necessary to collect metrics from car watchdog. * * @hide */ @SystemApi public static final String PERMISSION_COLLECT_CAR_WATCHDOG_METRICS = "android.car.permission.COLLECT_CAR_WATCHDOG_METRICS"; /** * Permission necessary to fetch car CPU information. * * @hide */ public static final String PERMISSION_COLLECT_CAR_CPU_INFO = "android.car.permission.COLLECT_CAR_CPU_INFO"; /** * Permission necessary to control launching applications in Car. * * @hide */ @SystemApi public static final String PERMISSION_CONTROL_CAR_APP_LAUNCH = "android.car.permission.CONTROL_CAR_APP_LAUNCH"; /** * Permission necessary to setting and getting thread scheduling policy and priority. * * @hide */ @SystemApi public static final String PERMISSION_MANAGE_THREAD_PRIORITY = "android.car.permission.MANAGE_THREAD_PRIORITY"; /** * Permission necessary to modify occupant zone settings. Will be used in * {@link CarOccupantZoneManager}. * * @hide */ @SystemApi public static final String PERMISSION_MANAGE_OCCUPANT_ZONE = "android.car.permission.MANAGE_OCCUPANT_ZONE"; /** * Permission necessary to use remote access. */ public static final String PERMISSION_USE_REMOTE_ACCESS = "android.car.permission.USE_REMOTE_ACCESS"; /** * Permission necessary to control remote access. * * @hide */ @SystemApi public static final String PERMISSION_CONTROL_REMOTE_ACCESS = "android.car.permission.CONTROL_REMOTE_ACCESS"; /** * Permission necessary to control car's steering wheel. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_STEERING_WHEEL = "android.car.permission.CONTROL_STEERING_WHEEL"; /** * Permission necessary to read ADAS settings information. * * Examples of settings include the ENABLED properties for the supported ADAS features. * * @hide */ @SystemApi public static final String PERMISSION_READ_ADAS_SETTINGS = "android.car.permission.READ_ADAS_SETTINGS"; /** * Permission necessary to control ADAS settings information. * * Examples of settings include the ENABLED properties for the supported ADAS features. * * @hide */ @SystemApi public static final String PERMISSION_CONTROL_ADAS_SETTINGS = "android.car.permission.CONTROL_ADAS_SETTINGS"; /** * Permission necessary to read ADAS states information. * * Examples include the STATE properties for the supported ADAS features. * * @hide */ @SystemApi public static final String PERMISSION_READ_ADAS_STATES = "android.car.permission.READ_ADAS_STATES"; /** * Permission necessary to control ADAS states information. * * Examples include the STATE properties for the supported ADAS features. * * @hide */ @SystemApi public static final String PERMISSION_CONTROL_ADAS_STATES = "android.car.permission.CONTROL_ADAS_STATES"; /** * Permission necessary to monitor the states of other occupant zones in the car and peer apps * (apps that have the same package name as the caller) installed in those zones, * and manage the power of those zones. * * @hide */ @SystemApi public static final String PERMISSION_MANAGE_REMOTE_DEVICE = "android.car.permission.MANAGE_REMOTE_DEVICE"; /** * Permission necessary to establish connection and communicate to peer apps (apps that have * the same package name as the caller) installed in other occupant zones in the car. * * @hide */ @SystemApi public static final String PERMISSION_MANAGE_OCCUPANT_CONNECTION = "android.car.permission.MANAGE_OCCUPANT_CONNECTION"; /** * Permission to access the mirrored Surface using the Token generated by * {@link CarActivityManager#createTaskMirroringToken(int)}. * * @hide */ @SystemApi public static final String PERMISSION_ACCESS_MIRRORRED_SURFACE = "android.car.permission.ACCESS_MIRRORED_SURFACE"; /** * Permission to create the mirroring token for the Display. * See {@link CarActivityManager#createDisplayMirroringToken(int)} (int)}. * * @hide */ @SystemApi public static final String PERMISSION_MIRROR_DISPLAY = "android.car.permission.MIRROR_DISPLAY"; /** * Permission necessary to read car's windshield wipers. * @hide */ @SystemApi public static final String PERMISSION_READ_WINDSHIELD_WIPERS = "android.car.permission.READ_WINDSHIELD_WIPERS"; /** * Permission necessary to control car's windshield wipers. * @hide */ @SystemApi public static final String PERMISSION_CONTROL_WINDSHIELD_WIPERS = "android.car.permission.CONTROL_WINDSHIELD_WIPERS"; /** * Permission necessary to register a {@link SystemUIProxy} that can be used by other apps to * manage the system ui and create task views. * * @hide */ @SystemApi public static final String PERMISSION_REGISTER_CAR_SYSTEM_UI_PROXY = "android.car.permission.REGISTER_CAR_SYSTEM_UI_PROXY"; /** * Permission necessary to communicate with the car system ui for creating task views or * getting notified about system ui changes. * @hide */ @SystemApi public static final String PERMISSION_MANAGE_CAR_SYSTEM_UI = "android.car.permission.MANAGE_CAR_SYSTEM_UI"; /** * Permission necessary to manage packages that requires launching in automotive compatibility * mode. * @hide */ @FlaggedApi(Flags.FLAG_DISPLAY_COMPATIBILITY) @SystemApi public static final String PERMISSION_MANAGE_DISPLAY_COMPATIBILITY = "android.car.permission.MANAGE_DISPLAY_COMPATIBILITY"; /** * Permission necessary to read state of car airbags. * @hide */ @FlaggedApi(Flags.FLAG_ANDROID_VIC_VEHICLE_PROPERTIES) @SystemApi public static final String PERMISSION_READ_CAR_AIRBAGS = "android.car.permission.READ_CAR_AIRBAGS"; /** * Permission necessary to read state of seat belts. * @hide */ @FlaggedApi(Flags.FLAG_ANDROID_VIC_VEHICLE_PROPERTIES) @SystemApi public static final String PERMISSION_READ_CAR_SEAT_BELTS = "android.car.permission.READ_CAR_SEAT_BELTS"; /** * Permission necessary to read impact sensors information. * @hide */ @FlaggedApi(Flags.FLAG_ANDROID_VIC_VEHICLE_PROPERTIES) @SystemApi public static final String PERMISSION_READ_IMPACT_SENSORS = "android.car.permission.READ_IMPACT_SENSORS"; /** * Permission necessary to read valet mode * @hide */ @FlaggedApi(Flags.FLAG_ANDROID_VIC_VEHICLE_PROPERTIES) @SystemApi public static final String PERMISSION_READ_VALET_MODE = "android.car.permission.READ_VALET_MODE"; /** * Permission necessary to control valet mode * @hide */ @FlaggedApi(Flags.FLAG_ANDROID_VIC_VEHICLE_PROPERTIES) @SystemApi public static final String PERMISSION_CONTROL_VALET_MODE = "android.car.permission.CONTROL_VALET_MODE"; /** * Permission necessary to read head up display status (e.g. whether the head up display is * enabled) * * @hide */ @FlaggedApi(Flags.FLAG_ANDROID_VIC_VEHICLE_PROPERTIES) @SystemApi public static final String PERMISSION_READ_HEAD_UP_DISPLAY_STATUS = "android.car.permission.READ_HEAD_UP_DISPLAY_STATUS"; /** * Permission necessary to control head up display * @hide */ @FlaggedApi(Flags.FLAG_ANDROID_VIC_VEHICLE_PROPERTIES) @SystemApi public static final String PERMISSION_CONTROL_HEAD_UP_DISPLAY = "android.car.permission.CONTROL_HEAD_UP_DISPLAY"; /** * Permission necessary to read persist tethering settings. * @hide */ @FlaggedApi(Flags.FLAG_PERSIST_AP_SETTINGS) @SystemApi public static final String PERMISSION_READ_PERSIST_TETHERING_SETTINGS = "android.car.permission.READ_PERSIST_TETHERING_SETTINGS"; /** * Permission necessary to bind with app card providers. * @hide */ @FlaggedApi(Flags.FLAG_CAR_APP_CARD) @SystemApi public static final String PERMISSION_BIND_APP_CARD_PROVIDER = "android.car.permission.BIND_APP_CARD_PROVIDER"; /** * Intent for connecting to the template renderer. Services that handle this intent must also * hold {@link #PERMISSION_TEMPLATE_RENDERER}. Applications would not bind to this service * directly, but instead they would use * * Android for Cars App Library. * * @hide */ @SdkConstant(SdkConstantType.SERVICE_ACTION) public static final String CAR_TEMPLATE_HOST_RENDERER_SERVICE = "android.car.template.host.RendererService"; /** @hide */ @IntDef({CONNECTION_TYPE_EMBEDDED}) @Retention(RetentionPolicy.SOURCE) public @interface ConnectionType {} /** * @deprecated Use {@link CarMediaIntents#ACTION_MEDIA_TEMPLATE} instead. */ @Deprecated @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String CAR_INTENT_ACTION_MEDIA_TEMPLATE = "android.car.intent.action.MEDIA_TEMPLATE"; /** * @deprecated Use {@link CarMediaIntents#EXTRA_MEDIA_COMPONENT} instead. */ @Deprecated public static final String CAR_EXTRA_MEDIA_COMPONENT = "android.car.intent.extra.MEDIA_COMPONENT"; /** * * @deprecated Use {@link #CAR_EXTRA_MEDIA_COMPONENT} instead. * @removed Using this for specifying MediaBrowserService was not supported since API level 29 * and above. Apps must use {@link #CAR_EXTRA_MEDIA_COMPONENT} instead. */ @Deprecated public static final String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE"; /** * Used as a string extra field of media session to specify the service corresponding to the * session. */ public static final String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION = "android.media.session.BROWSE_SERVICE"; /** * Intent for being recognized as a remote task client service. * *

Services that use this intent must have a {@code PERMISSION_CONTROL_REMOTE_ACCESS}. * * @hide */ @SystemApi public static final String CAR_REMOTEACCESS_REMOTE_TASK_CLIENT_SERVICE = "android.car.remoteaccess.RemoteTaskClientService"; /** * Intent for binding the implementation of {@link * android.car.occupantconnection.AbstractReceiverService} in the app. * * @hide */ @SdkConstant(SdkConstantType.SERVICE_ACTION) public static final String CAR_INTENT_ACTION_RECEIVER_SERVICE = "android.car.intent.action.RECEIVER_SERVICE"; /** @hide */ @VisibleForHiddenApiCheck public static final String CAR_SERVICE_INTERFACE_NAME = CommonConstants.CAR_SERVICE_INTERFACE; private static final String CAR_SERVICE_PACKAGE = "com.android.car"; private static final String CAR_SERVICE_CLASS = "com.android.car.CarService"; /** * Category used by navigation applications to indicate which activity should be launched on * the instrument cluster when such application holds * {@link CarAppFocusManager#APP_FOCUS_TYPE_NAVIGATION} focus. * * @hide */ @VisibleForHiddenApiCheck public static final String CAR_CATEGORY_NAVIGATION = "android.car.cluster.NAVIGATION"; /** * When an activity is launched in the cluster, it will receive {@link ClusterActivityState} in * the intent's extra under this key, containing instrument cluster information such as * unobscured area, visibility, etc. * * @hide */ @SystemApi public static final String CAR_EXTRA_CLUSTER_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState"; /** * @hide */ @OptionalFeature @FlaggedApi(Flags.FLAG_DISPLAY_COMPATIBILITY) @SystemApi public static final String CAR_DISPLAY_COMPAT_SERVICE = "car_display_compat_service"; /** * Callback to notify the Lifecycle of car service. * *

Access to car service should happen * after {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} call with * {@code ready} set {@code true}.

* *

When {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} is * called with ready set to false, access to car service should stop until car service is ready * again from {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} call * with {@code ready} set to {@code true}.

*/ public interface CarServiceLifecycleListener { /** * Car service has gone through status change. * *

This is always called in the main thread context.

* * @param car {@code Car} object that was originally associated with this lister from * {@link #createCar(Context, Handler, long, Car.CarServiceLifecycleListener)} * call. * @param ready when {@code true}, car service is ready and all accesses are ok * Otherwise car service has crashed or killed and will be restarted */ void onLifecycleChanged(@NonNull Car car, boolean ready); } /** * {@link #createCar(Context, Handler, long, CarServiceLifecycleListener)}'s * waitTimeoutMs value to use to wait forever inside the call until car service is ready. */ public static final long CAR_WAIT_TIMEOUT_WAIT_FOREVER = -1; /** * {@link #createCar(Context, Handler, long, CarServiceLifecycleListener)}'s * waitTimeoutMs value to use to skip any waiting inside the call. */ public static final long CAR_WAIT_TIMEOUT_DO_NOT_WAIT = 0; private static final long CAR_SERVICE_BIND_RETRY_INTERVAL_MS = 500; private static final long CAR_SERVICE_BIND_MAX_RETRY = 20; private static final long CAR_SERVICE_BINDER_POLLING_INTERVAL_MS = 50; private static final long CAR_SERVICE_BINDER_POLLING_MAX_RETRY = 100; private static final int STATE_DISCONNECTED = 0; private static final int STATE_CONNECTING = 1; private static final int STATE_CONNECTED = 2; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "STATE_", value = { STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, }) @Target({ElementType.TYPE_USE}) public @interface StateTypeEnum {} /** * The enabling request was successful and requires reboot to take effect. * @hide */ @SystemApi public static final int FEATURE_REQUEST_SUCCESS = 0; /** * The requested feature is already enabled or disabled as requested. No need to reboot the * system. * @hide */ @SystemApi public static final int FEATURE_REQUEST_ALREADY_IN_THE_STATE = 1; /** * The requested feature is mandatory cannot be enabled or disabled. It is always enabled. * @hide */ @SystemApi public static final int FEATURE_REQUEST_MANDATORY = 2; /** * The requested feature is not available and cannot be enabled or disabled. * @hide */ @SystemApi public static final int FEATURE_REQUEST_NOT_EXISTING = 3; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "FEATURE_REQUEST_", value = { FEATURE_REQUEST_SUCCESS, FEATURE_REQUEST_ALREADY_IN_THE_STATE, FEATURE_REQUEST_MANDATORY, FEATURE_REQUEST_NOT_EXISTING, }) @Target({ElementType.TYPE_USE}) public @interface FeaturerRequestEnum {} private final Context mContext; private final Exception mConstructionStack; private final Object mLock = new Object(); @GuardedBy("mLock") private ICar mService; @GuardedBy("mLock") private boolean mServiceBound; @GuardedBy("mLock") @StateTypeEnum private int mConnectionState; @GuardedBy("mLock") private int mConnectionRetryCount; private final Runnable mConnectionRetryRunnable = new Runnable() { @Override public void run() { startCarService(); } }; private final Runnable mConnectionRetryFailedRunnable = new Runnable() { @Override public void run() { mServiceConnectionListener.onServiceDisconnected(new ComponentName(CAR_SERVICE_PACKAGE, CAR_SERVICE_CLASS)); } }; private final ServiceConnection mServiceConnectionListener = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { synchronized (mLock) { ICar newService = ICar.Stub.asInterface(service); if (newService == null) { Slog.wtf(TAG_CAR, "null binder service", new RuntimeException()); return; // should not happen. } if (mService != null && mService.asBinder().equals(newService.asBinder())) { // already connected. return; } mConnectionState = STATE_CONNECTED; mService = newService; } if (mStatusChangeCallback != null) { mStatusChangeCallback.onLifecycleChanged(Car.this, true); } else if (mServiceConnectionListenerClient != null) { mServiceConnectionListenerClient.onServiceConnected(name, service); } } @Override public void onServiceDisconnected(ComponentName name) { // Car service can pick up feature changes after restart. mFeatures.resetCache(); synchronized (mLock) { if (mConnectionState == STATE_DISCONNECTED) { // can happen when client calls disconnect before onServiceDisconnected call. return; } handleCarDisconnectLocked(); } if (mStatusChangeCallback != null) { mStatusChangeCallback.onLifecycleChanged(Car.this, false); } else if (mServiceConnectionListenerClient != null) { mServiceConnectionListenerClient.onServiceDisconnected(name); } else { // This client does not handle car service restart, so should be terminated. finishClient(); } } }; @Nullable private final ServiceConnection mServiceConnectionListenerClient; /** Can be added after ServiceManagerHelper.getService call */ @Nullable private final CarServiceLifecycleListener mStatusChangeCallback; @GuardedBy("mLock") private final HashMap mServiceMap = new HashMap<>(); /** Handler for generic event dispatching. */ private final Handler mEventHandler; private final Handler mMainThreadEventHandler; private final CarFeatures mFeatures = new CarFeatures(); static { CAR_SERVICE_NAMES.put(CarSensorManager.class, SENSOR_SERVICE); CAR_SERVICE_NAMES.put(CarInfoManager.class, INFO_SERVICE); CAR_SERVICE_NAMES.put(CarAppFocusManager.class, APP_FOCUS_SERVICE); CAR_SERVICE_NAMES.put(CarPackageManager.class, PACKAGE_SERVICE); CAR_SERVICE_NAMES.put(CarAudioManager.class, AUDIO_SERVICE); CAR_SERVICE_NAMES.put(CarNavigationStatusManager.class, CAR_NAVIGATION_SERVICE); CAR_SERVICE_NAMES.put(CarOccupantZoneManager.class, CAR_OCCUPANT_ZONE_SERVICE); CAR_SERVICE_NAMES.put(CarUserManager.class, CAR_USER_SERVICE); CAR_SERVICE_NAMES.put(ExperimentalCarUserManager.class, EXPERIMENTAL_CAR_USER_SERVICE); CAR_SERVICE_NAMES.put(CarDevicePolicyManager.class, CAR_DEVICE_POLICY_SERVICE); CAR_SERVICE_NAMES.put(CarInstrumentClusterManager.class, CAR_INSTRUMENT_CLUSTER_SERVICE); CAR_SERVICE_NAMES.put(CarCabinManager.class, CABIN_SERVICE); CAR_SERVICE_NAMES.put(CarDiagnosticManager.class, DIAGNOSTIC_SERVICE); CAR_SERVICE_NAMES.put(CarHvacManager.class, HVAC_SERVICE); CAR_SERVICE_NAMES.put(CarPowerManager.class, POWER_SERVICE); CAR_SERVICE_NAMES.put(CarProjectionManager.class, PROJECTION_SERVICE); CAR_SERVICE_NAMES.put(CarPropertyManager.class, PROPERTY_SERVICE); CAR_SERVICE_NAMES.put(CarVendorExtensionManager.class, VENDOR_EXTENSION_SERVICE); CAR_SERVICE_NAMES.put(VmsClientManager.class, VEHICLE_MAP_SERVICE); CAR_SERVICE_NAMES.put(VmsSubscriberManager.class, VMS_SUBSCRIBER_SERVICE); CAR_SERVICE_NAMES.put(CarDrivingStateManager.class, CAR_DRIVING_STATE_SERVICE); CAR_SERVICE_NAMES.put(CarUxRestrictionsManager.class, CAR_UX_RESTRICTION_SERVICE); CAR_SERVICE_NAMES.put(OccupantAwarenessManager.class, OCCUPANT_AWARENESS_SERVICE); CAR_SERVICE_NAMES.put(CarMediaManager.class, CAR_MEDIA_SERVICE); CAR_SERVICE_NAMES.put(CarBugreportManager.class, CAR_BUGREPORT_SERVICE); CAR_SERVICE_NAMES.put(CarStorageMonitoringManager.class, STORAGE_MONITORING_SERVICE); CAR_SERVICE_NAMES.put(CarWatchdogManager.class, CAR_WATCHDOG_SERVICE); CAR_SERVICE_NAMES.put(CarPerformanceManager.class, CAR_PERFORMANCE_SERVICE); CAR_SERVICE_NAMES.put(CarInputManager.class, CAR_INPUT_SERVICE); CAR_SERVICE_NAMES.put(ClusterHomeManager.class, CLUSTER_HOME_SERVICE); CAR_SERVICE_NAMES.put(CarTestManager.class, TEST_SERVICE); CAR_SERVICE_NAMES.put(CarEvsManager.class, CAR_EVS_SERVICE); CAR_SERVICE_NAMES.put(CarTelemetryManager.class, CAR_TELEMETRY_SERVICE); CAR_SERVICE_NAMES.put(CarActivityManager.class, CAR_ACTIVITY_SERVICE); CAR_SERVICE_NAMES.put(CarRemoteAccessManager.class, CAR_REMOTE_ACCESS_SERVICE); CAR_SERVICE_NAMES.put(CarOccupantConnectionManager.class, CAR_OCCUPANT_CONNECTION_SERVICE); CAR_SERVICE_NAMES.put(CarRemoteDeviceManager.class, CAR_REMOTE_DEVICE_SERVICE); if (Flags.persistApSettings()) { CAR_SERVICE_NAMES.put(CarWifiManager.class, CAR_WIFI_SERVICE); } if (Flags.displayCompatibility()) { CAR_SERVICE_NAMES.put(CarDisplayCompatManager.class, CAR_DISPLAY_COMPAT_SERVICE); } // Note: if a new entry is added here, the capacity of CAR_SERVICE_NAMES should be increased // as well. } /** * Defines the {@link CarVersion version} of the {@code Car} APIs in the device. * *

Starting on {@link android.os.Build.VERSION_CODES#TIRAMISU Android 13}, the {@code Car} * APIs can be upgraded without an OTA, so it's possible that these APIs are higher than the * {@link #getPlatformVersion() platform's}. * * @deprecated - use {@code android.os.Build.VERSION#SDK_INT} instead */ @NonNull @Deprecated public static android.car.CarVersion getCarVersion() { return CAR_VERSION; } /** * Defines the {@link PlatformVersion version} of the standard {@code SDK} APIs in the * device. * *

Its {@link ApiVersion#getMajorVersion() major version} will be the same as * {@link android.os.Build.VERSION#SDK_INT} for released build but will be * {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT} for platform still under development. * * @deprecated - use {@code android.os.Build.VERSION#SDK_INT} instead */ @NonNull @Deprecated public static android.car.PlatformVersion getPlatformVersion() { return PLATFORM_VERSION; } /** * @deprecated - use {@code getCarApiVersion().isAtLeast(CarVersion.forMajorAndMinorVersions( * requiredApiVersionMajor))} instead */ @Deprecated public static boolean isApiVersionAtLeast(int requiredApiVersionMajor) { return getCarVersion().isAtLeast(CarVersion.forMajorVersion(requiredApiVersionMajor)); } /** * @deprecated - use {@code getCarVersion().isAtLeast(CarVersion.forMajorAndMinorVersions( * requiredApiVersionMajor, requiredApiVersionMinor)} instead */ @Deprecated public static boolean isApiVersionAtLeast(int requiredApiVersionMajor, int requiredApiVersionMinor) { return getCarVersion() .isAtLeast(CarVersion.forMajorAndMinorVersions(requiredApiVersionMajor, requiredApiVersionMinor)); } /** * @deprecated - use * {@code getCarVersion().isAtLeast(CarVersion.forMajorVersion(requiredApiVersionMajor)) * && getPlatformVersion().isAtLeast(PlatformVersion.forMajorVersion(minPlatformSdkInt))} * instead. */ @Deprecated public static boolean isApiAndPlatformVersionAtLeast(int requiredApiVersionMajor, int minPlatformSdkInt) { return getCarVersion().isAtLeast(CarVersion.forMajorVersion(requiredApiVersionMajor)) && getPlatformVersion() .isAtLeast(PlatformVersion.forMajorVersion(minPlatformSdkInt)); } /** * @deprecated - use {@code getCarVersion().isAtLeast(CarVersion.forMajorAndMinorVersions( * requiredApiVersionMajor, requiredApiVersionMinor)) && getPlatformVersion().isAtLeast( * PlatformVersion.forMajorVersion(minPlatformSdkInt))} instead. */ @Deprecated public static boolean isApiAndPlatformVersionAtLeast(int requiredApiVersionMajor, int requiredApiVersionMinor, int minPlatformSdkInt) { return getCarVersion() .isAtLeast(CarVersion.forMajorAndMinorVersions(requiredApiVersionMajor, requiredApiVersionMinor)) && getPlatformVersion() .isAtLeast(PlatformVersion.forMajorVersion(minPlatformSdkInt)); } /** * A factory method that creates Car instance for all Car API access. * *

Instance created with this should be disconnected from car service by calling * {@link #disconnect()} before the passed {@code Context} is released. * * @param context This should not be {@code null}. If you are passing {@link ContextWrapper}, * make sure that its {@link ContextWrapper#getBaseContext() base context} is not * {@code null} as well. * Otherwise it will throw {@link java.lang.NullPointerException}. * @param serviceConnectionListener listener for monitoring service connection. * @param handler the handler on which the callback should execute, or null to execute on the * service's main thread. Note: the service connection listener will be always on the main * thread regardless of the handler given. * @return Car instance if system is in car environment and returns {@code null} otherwise. * * @deprecated use {@link #createCar(Context, Handler)} instead. */ @Deprecated public static Car createCar(Context context, ServiceConnection serviceConnectionListener, @Nullable Handler handler) { assertNonNullContext(context); if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { Slog.e(TAG_CAR, "FEATURE_AUTOMOTIVE not declared while android.car is used"); return null; } try { return new Car(context, /* service= */ null , serviceConnectionListener, /* statusChangeListener= */ null, handler); } catch (IllegalArgumentException e) { // Expected when car service loader is not available. } return null; } /** * A factory method that creates Car instance for all Car API access using main thread {@code * Looper}. * *

Instance created with this should be disconnected from car service by calling * {@link #disconnect()} before the passed {@code Context} is released. * * @see #createCar(Context, ServiceConnection, Handler) * * @deprecated use {@link #createCar(Context, Handler)} instead. */ @Deprecated public static Car createCar(Context context, ServiceConnection serviceConnectionListener) { return createCar(context, serviceConnectionListener, null); } /** * Creates new {@link Car} object which connected synchronously to Car Service and ready to use. * *

Instance created with this should be disconnected from car service by calling * {@link #disconnect()} before the passed {@code Context} is released. * * @param context application's context * * @return Car object if operation succeeded, otherwise null. */ @Nullable public static Car createCar(Context context) { return new CarBuilder().createCar(context); } /** * Creates new {@link Car} object which connected synchronously to Car Service and ready to use. * *

Instance created with this should be disconnected from car service by calling * {@link #disconnect()} before the passed {@code Context} is released. * * @param context This should not be {@code null}. If you are passing {@link ContextWrapper}, * make sure that its {@link ContextWrapper#getBaseContext() base context} is not * {@code null} as well. * Otherwise it will throw {@link java.lang.NullPointerException}. * @param handler the handler on which the manager's callbacks will be executed, or null to * execute on the application's main thread. * * @return Car object if operation succeeded, otherwise null. */ @Nullable public static Car createCar(Context context, @Nullable Handler handler) { return new CarBuilder().createCar(context, handler); } /** * Creates new {@link Car} object with {@link CarServiceLifecycleListener}. * *

Instance created with this should be disconnected from car service by calling * {@link #disconnect()} before the passed {@code Context} is released. * *

If car service is ready inside this call and if the caller is running in the main thread, * {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} will be called * with ready set to be true. Otherwise, * {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} will be called * from the main thread later.

* *

This call can block up to specified waitTimeoutMs to wait for car service to be ready. * If car service is not ready within the given time, it will return a Car instance in * disconnected state. Blocking main thread forever can lead into getting ANR (Application Not * Responding) killing from system and should not be used if the app is supposed to survive * across the crash / restart of car service. It can be still useful in case the app cannot do * anything without car service being ready. In any waiting, if the thread is getting * interrupted, it will return immediately. *

* *

Note that returned {@link Car} object is not guaranteed to be connected when there is * a limited timeout. Regardless of returned car being connected or not, it is recommended to * implement all car related initialization inside * {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} and avoid the * needs to check if returned {@link Car} is connected or not from returned {@link Car}.

* * @param context This should not be {@code null}. If you are passing {@link ContextWrapper}, * make sure that its {@link ContextWrapper#getBaseContext() base context} is not * {@code null} as well. * Otherwise it will throw {@link java.lang.NullPointerException}. * @param handler dispatches all Car*Manager events to this Handler. Exception is * {@link CarServiceLifecycleListener} which will be always dispatched to main * thread. Passing null leads into dispatching all Car*Manager callbacks to main * thread as well. * @param waitTimeoutMs Setting this to {@link #CAR_WAIT_TIMEOUT_DO_NOT_WAIT} will guarantee * that the API does not wait for the car service at all. Setting this to * to {@link #CAR_WAIT_TIMEOUT_WAIT_FOREVER} will block the call forever * until the car service is ready. Setting any positive value will be * interpreted as timeout value. */ @NonNull public static Car createCar(@NonNull Context context, @Nullable Handler handler, long waitTimeoutMs, @NonNull CarServiceLifecycleListener statusChangeListener) { return new CarBuilder().createCar(context, handler, waitTimeoutMs, statusChangeListener); } /** * A wrapper around {@code createCar} functions that allows injecting deps for testing. * * @hide */ @VisibleForTesting public static final class CarBuilder { /** * The service manager functions we access in this class. */ public interface ServiceManager { /** Check {@link ServiceManager#getService(String)} */ IBinder getService(String name); } private ServiceManager mServiceManager = new ServiceManager() { @Override public IBinder getService(String name) { return ServiceManagerHelper.getService(name); } }; /** * Sets the fake service manager for testing. */ public CarBuilder setServiceManager(ServiceManager serviceManager) { mServiceManager = serviceManager; return this; } /** * See {@link Car#createCar}. */ public Car createCar(Context context) { return createCar(context, (Handler) null); } /** * See {@link Car#createCar}. */ public Car createCar(Context context, @Nullable Handler handler) { assertNonNullContext(context); Car car = null; IBinder service = null; boolean started = false; int retryCount = 0; while (true) { service = mServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME); if (car == null) { // service can be still null. The constructor is safe for null service. car = new Car(context, ICar.Stub.asInterface(service), null /*serviceConnectionListener*/, null /*statusChangeListener*/, handler); } if (service != null) { if (!started) { // specialization for most common case. // Do this to crash client when car service crashes. car.startCarService(); return car; } break; } if (!started) { car.startCarService(); started = true; } retryCount++; if (retryCount > CAR_SERVICE_BINDER_POLLING_MAX_RETRY) { Slog.e(TAG_CAR, "cannot get car_service, waited for car service (ms):" + CAR_SERVICE_BINDER_POLLING_INTERVAL_MS * CAR_SERVICE_BINDER_POLLING_MAX_RETRY, new RuntimeException()); return null; } try { Thread.sleep(CAR_SERVICE_BINDER_POLLING_INTERVAL_MS); } catch (InterruptedException e) { Slog.e(CarLibLog.TAG_CAR, "interrupted while waiting for car_service", new RuntimeException()); return null; } } // Can be accessed from mServiceConnectionListener in main thread. synchronized (car.mLock) { if (car.mService == null) { car.mService = ICar.Stub.asInterface(service); Slog.w(TAG_CAR, "waited for car_service (ms):" + CAR_SERVICE_BINDER_POLLING_INTERVAL_MS * retryCount, new RuntimeException()); } car.mConnectionState = STATE_CONNECTED; } return car; } /** * See {@link Car#createCar}. */ @NonNull public Car createCar(@NonNull Context context, @Nullable Handler handler, long waitTimeoutMs, @NonNull CarServiceLifecycleListener statusChangeListener) { assertNonNullContext(context); Objects.requireNonNull(statusChangeListener); Car car = null; IBinder service = null; boolean started = false; int retryCount = 0; long maxRetryCount = 0; if (waitTimeoutMs > 0) { maxRetryCount = waitTimeoutMs / CAR_SERVICE_BINDER_POLLING_INTERVAL_MS; // at least wait once if it is positive value. if (maxRetryCount == 0) { maxRetryCount = 1; } } boolean isMainThread = Looper.myLooper() == Looper.getMainLooper(); while (true) { service = mServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME); if (car == null) { // service can be still null. The constructor is safe for null service. car = new Car(context, ICar.Stub.asInterface(service), null, statusChangeListener, handler); } if (service != null) { // specialization for most common case : car service already ready if (!started) { car.dispatchCarReadyToMainThread(isMainThread); // Needs this for CarServiceLifecycleListener. Note that ServiceConnection // will skip the callback as valid mService is set already. car.startCarService(); return car; } // service available after starting. break; } if (!started) { car.startCarService(); started = true; } retryCount++; if (waitTimeoutMs < 0 && retryCount >= CAR_SERVICE_BINDER_POLLING_MAX_RETRY && retryCount % CAR_SERVICE_BINDER_POLLING_MAX_RETRY == 0) { // Log warning if car service is not alive even for waiting forever case. Slog.w(TAG_CAR, "car_service not ready, waited for car service (ms):" + retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS, new RuntimeException()); } else if (waitTimeoutMs >= 0 && retryCount > maxRetryCount) { if (waitTimeoutMs > 0) { Slog.w(TAG_CAR, "car_service not ready, waited for car service (ms):" + waitTimeoutMs, new RuntimeException()); } return car; } try { Thread.sleep(CAR_SERVICE_BINDER_POLLING_INTERVAL_MS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Slog.w(TAG_CAR, "interrupted", new RuntimeException()); return car; } } // Can be accessed from mServiceConnectionListener in main thread. synchronized (car.mLock) { Slog.w(TAG_CAR, "waited for car_service (ms):" + retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS, new RuntimeException()); // ServiceConnection has handled everything. if (car.mService != null) { return car; } // mService check in ServiceConnection prevents calling // onLifecycleChanged. So onLifecycleChanged should be called explicitly // but do it outside lock. car.mService = ICar.Stub.asInterface(service); car.mConnectionState = STATE_CONNECTED; } car.dispatchCarReadyToMainThread(isMainThread); return car; } } private static void assertNonNullContext(Context context) { Objects.requireNonNull(context); if (context instanceof ContextWrapper && ((ContextWrapper) context).getBaseContext() == null) { throw new NullPointerException( "ContextWrapper with null base passed as Context, forgot to set base Context?"); } } private void dispatchCarReadyToMainThread(boolean isMainThread) { if (isMainThread) { mStatusChangeCallback.onLifecycleChanged(this, true); } else { // should dispatch to main thread. mMainThreadEventHandler.post( () -> mStatusChangeCallback.onLifecycleChanged(this, true)); } } private Car(Context context, @Nullable ICar service, @Nullable ServiceConnection serviceConnectionListener, @Nullable CarServiceLifecycleListener statusChangeListener, @Nullable Handler handler) { mContext = context; mEventHandler = determineEventHandler(handler); mMainThreadEventHandler = determineMainThreadEventHandler(mEventHandler); mService = service; if (service != null) { mConnectionState = STATE_CONNECTED; } else { mConnectionState = STATE_DISCONNECTED; } mServiceConnectionListenerClient = serviceConnectionListener; mStatusChangeCallback = statusChangeListener; // Store construction stack so that client can get help when it crashes when car service // crashes. if (serviceConnectionListener == null && statusChangeListener == null) { mConstructionStack = new RuntimeException(); } else { mConstructionStack = null; } } /** * Car constructor when ICar binder is already available. The binder can be null. * @hide */ public Car(Context context, @Nullable ICar service, @Nullable Handler handler) { this(context, service, null /*serviceConnectionListener*/, null /*statusChangeListener*/, handler); } private static Handler determineMainThreadEventHandler(Handler eventHandler) { Looper mainLooper = Looper.getMainLooper(); return (eventHandler.getLooper() == mainLooper) ? eventHandler : new Handler(mainLooper); } private static Handler determineEventHandler(@Nullable Handler eventHandler) { Handler handler = eventHandler; if (handler == null) { Looper looper = Looper.getMainLooper(); handler = new Handler(looper); } return handler; } /** * Connect to car service. This can be called while it is disconnected. * @throws IllegalStateException If connection is still on-going from previous * connect call or it is already connected * * @deprecated this method is not need if this object is created via * {@link #createCar(Context, Handler)}. */ @Deprecated public void connect() throws IllegalStateException { synchronized (mLock) { if (mConnectionState != STATE_DISCONNECTED) { throw new IllegalStateException("already connected or connecting"); } mConnectionState = STATE_CONNECTING; startCarService(); } } @GuardedBy("mLock") private void handleCarDisconnectLocked() { if (mConnectionState == STATE_DISCONNECTED) { // can happen when client calls disconnect with onServiceDisconnected already // called. return; } mEventHandler.removeCallbacks(mConnectionRetryRunnable); mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable); mConnectionRetryCount = 0; tearDownCarManagersLocked(); mService = null; mConnectionState = STATE_DISCONNECTED; } /** * Disconnect from car service. This can be called while disconnected. Once disconnect is * called, all Car*Managers from this instance become invalid, and * {@link Car#getCarManager(String)} or {@link Car#getCarManager(Class)} will return a * different instance if it is connected again. */ public void disconnect() { synchronized (mLock) { handleCarDisconnectLocked(); if (mServiceBound) { mContext.unbindService(mServiceConnectionListener); mServiceBound = false; } } } @Override @SuppressWarnings("GenericException") protected void finalize() throws Throwable { if (mLock == null) { // There's no point of trying anything - even logging - when the object state is already // cleared super.finalize(); return; } try { Slog.v(TAG_CAR, "Calling disconnect() on finalize()"); disconnect(); } finally { super.finalize(); } } /** * Tells if it is connected to the service or not. This will return false if it is still * connecting. * @return {@code true} if service is connected */ public boolean isConnected() { synchronized (mLock) { return mService != null; } } /** * Tells if this instance is already connecting to car service or not. * @return {@code true} if instance is connecting to a service */ public boolean isConnecting() { synchronized (mLock) { return mConnectionState == STATE_CONNECTING; } } /** @hide */ @VisibleForTesting public ServiceConnection getServiceConnectionListener() { return mServiceConnectionListener; } /** * Get car specific service manager as in {@link Context#getSystemService(String)}. Returned * {@link Object} should be type-casted to the desired service manager. * *

For example, to get the manager for sensor service, * * CarSensorManager carSensorManager = (CarSensorManager) car.getCarManager(Car.SENSOR_SERVICE); * * * @param serviceName Name of service that should be created like {@link #SENSOR_SERVICE}. * @return Matching service manager or null if there is no such service. */ @Nullable public Object getCarManager(String serviceName) { CarManagerBase manager; synchronized (mLock) { if (mService == null) { Slog.w(TAG_CAR, "getCarManager not working while car service not ready"); return null; } manager = mServiceMap.get(serviceName); if (manager == null) { try { IBinder binder = mService.getCarService(serviceName); if (binder == null) { Slog.w(TAG_CAR, "getCarManager could not get binder for service:" + serviceName); return null; } manager = createCarManagerLocked(serviceName, binder); if (manager == null) { Slog.w(TAG_CAR, "getCarManager could not create manager for service:" + serviceName); return null; } mServiceMap.put(serviceName, manager); } catch (RemoteException e) { handleRemoteExceptionFromCarService(e); } } } return manager; } /** * Get car specific service manager by class as in {@link Context#getSystemService(Class)}. * Returns the desired service. No type casting is needed. * *

For example, to get the manager for sensor service, * CarSensorManager carSensorManager = car.getCarManager(CarSensorManager.class); * * @param serviceClass The class of the desired service. * @return Matching service manager or {@code null} if there is no such service. */ @Nullable public T getCarManager(@NonNull Class serviceClass) { String serviceName = CAR_SERVICE_NAMES.get(serviceClass); return serviceName != null ? (T) getCarManager(serviceName) : null; } /** * @return the type of currently connected car. * * @deprecated connection type will be always {@link #CONNECTION_TYPE_EMBEDDED} */ @ConnectionType @Deprecated public int getCarConnectionType() { return CONNECTION_TYPE_EMBEDDED; } /** * Checks if {@code featureName} is enabled in this car. * *

For optional features, this can return false if the car cannot support it. Optional * features should be used only when they are supported.

* *

For mandatory features, this will always return true. */ public boolean isFeatureEnabled(@NonNull String featureName) { ICar service; synchronized (mLock) { if (mService == null) { return false; } service = mService; } return mFeatures.isFeatureEnabled(service, featureName); } /** * Enables the requested car feature. It becomes no-op if the feature is already enabled. The * change take effects after reboot. * * @return true if the feature is enabled or was enabled before. * * @hide */ @SystemApi @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES) @FeaturerRequestEnum public int enableFeature(@NonNull String featureName) { ICar service; synchronized (mLock) { if (mService == null) { return FEATURE_REQUEST_NOT_EXISTING; } service = mService; } try { return service.enableFeature(featureName); } catch (RemoteException e) { return handleRemoteExceptionFromCarService(e, FEATURE_REQUEST_NOT_EXISTING); } } /** * Disables the requested car feature. It becomes no-op if the feature is already disabled. The * change take effects after reboot. * * @return true if the request succeeds or if it was already disabled. * * @hide */ @SystemApi @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES) @FeaturerRequestEnum public int disableFeature(@NonNull String featureName) { ICar service; synchronized (mLock) { if (mService == null) { return FEATURE_REQUEST_NOT_EXISTING; } service = mService; } try { return service.disableFeature(featureName); } catch (RemoteException e) { return handleRemoteExceptionFromCarService(e, FEATURE_REQUEST_NOT_EXISTING); } } /** * Returns all =enabled features at the moment including mandatory, optional, and * experimental features. * * @hide */ @SystemApi @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES) @NonNull public List getAllEnabledFeatures() { ICar service; synchronized (mLock) { if (mService == null) { return Collections.EMPTY_LIST; } service = mService; } try { return service.getAllEnabledFeatures(); } catch (RemoteException e) { return handleRemoteExceptionFromCarService(e, Collections.EMPTY_LIST); } } /** * Returns the list of disabled features which are not effective yet. Those features will be * disabled when system restarts later. * * @hide */ @SystemApi @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES) @NonNull public List getAllPendingDisabledFeatures() { ICar service; synchronized (mLock) { if (mService == null) { return Collections.EMPTY_LIST; } service = mService; } try { return service.getAllPendingDisabledFeatures(); } catch (RemoteException e) { return handleRemoteExceptionFromCarService(e, Collections.EMPTY_LIST); } } /** * Returns the list of enabled features which are not effective yet. Those features will be * enabled when system restarts later. * * @hide */ @SystemApi @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES) @NonNull public List getAllPendingEnabledFeatures() { ICar service; synchronized (mLock) { if (mService == null) { return Collections.EMPTY_LIST; } service = mService; } try { return service.getAllPendingEnabledFeatures(); } catch (RemoteException e) { return handleRemoteExceptionFromCarService(e, Collections.EMPTY_LIST); } } /** @hide */ @VisibleForHiddenApiCheck public Context getContext() { return mContext; } /** @hide */ @VisibleForTesting public Handler getEventHandler() { return mEventHandler; } /** @hide */ @VisibleForTesting public T handleRemoteExceptionFromCarService(RemoteException e, T returnValue) { handleRemoteExceptionFromCarService(e); return returnValue; } /** @hide */ @VisibleForHiddenApiCheck public void handleRemoteExceptionFromCarService(RemoteException e) { if (e instanceof TransactionTooLargeException) { Slog.w(TAG_CAR, "Car service threw TransactionTooLargeException", e); throw new CarTransactionException(e, "Car service threw TransactionTooLargeException"); } else { Slog.w(TAG_CAR, "Car service has crashed", e); } } private void finishClient() { if (mContext == null) { throw new IllegalStateException("Car service has crashed, null Context"); } if (mContext instanceof Activity) { Activity activity = (Activity) mContext; if (!activity.isFinishing()) { Slog.w(TAG_CAR, "Car service crashed, client not handling it, finish Activity, created " + "from " + mConstructionStack); activity.finish(); } return; } else if (mContext instanceof Service) { Service service = (Service) mContext; killClient(service.getPackageName() + "," + service.getClass().getSimpleName()); } else { killClient(/* clientInfo= */ null); } } private void killClient(@Nullable String clientInfo) { Slog.w(TAG_CAR, "**Car service has crashed. Client(" + clientInfo + ") is not handling it." + " Client should use Car.createCar(..., CarServiceLifecycleListener, .." + ".) to handle it properly. Check printed callstack to check where other " + "version of Car.createCar() was called. Killing the client process**", mConstructionStack); Process.killProcess(Process.myPid()); } /** @hide */ @VisibleForHiddenApiCheck public static T handleRemoteExceptionFromCarService(Service service, RemoteException e, T returnValue) { handleRemoteExceptionFromCarService(service, e); return returnValue; } /** @hide */ @VisibleForHiddenApiCheck public static void handleRemoteExceptionFromCarService(Service service, RemoteException e) { if (e instanceof TransactionTooLargeException) { Slog.w(TAG_CAR, "Car service threw TransactionTooLargeException, client:" + service.getPackageName() + "," + service.getClass().getSimpleName(), e); throw new CarTransactionException(e, "Car service threw TransactionTooLargeException, " + "client: %s, %s", service.getPackageName(), service.getClass().getSimpleName()); } else { Slog.w(TAG_CAR, "Car service has crashed, client:" + service.getPackageName() + "," + service.getClass().getSimpleName(), e); service.stopSelf(); } } @Nullable private CarManagerBase createCarManagerLocked(String serviceName, IBinder binder) { CarManagerBase manager = null; switch (serviceName) { case AUDIO_SERVICE: manager = new CarAudioManager(this, binder); break; case SENSOR_SERVICE: manager = new CarSensorManager(this, binder); break; case INFO_SERVICE: manager = new CarInfoManager(this, binder); break; case APP_FOCUS_SERVICE: manager = new CarAppFocusManager(this, binder); break; case PACKAGE_SERVICE: manager = new CarPackageManager(this, binder); break; case CAR_OCCUPANT_ZONE_SERVICE: manager = new CarOccupantZoneManager(this, binder); break; case CAR_NAVIGATION_SERVICE: manager = new CarNavigationStatusManager(this, binder); break; case CABIN_SERVICE: manager = new CarCabinManager(this, binder); break; case DIAGNOSTIC_SERVICE: manager = new CarDiagnosticManager(this, binder); break; case HVAC_SERVICE: manager = new CarHvacManager(this, binder); break; case POWER_SERVICE: manager = new CarPowerManager(this, binder); break; case PROJECTION_SERVICE: manager = new CarProjectionManager(this, binder); break; case PROPERTY_SERVICE: manager = new CarPropertyManager(this, ICarProperty.Stub.asInterface(binder)); break; case VENDOR_EXTENSION_SERVICE: manager = new CarVendorExtensionManager(this, binder); break; case CAR_INSTRUMENT_CLUSTER_SERVICE: manager = new CarInstrumentClusterManager(this, binder); break; case TEST_SERVICE: /* CarTestManager exist in static library. So instead of constructing it here, * only pass binder wrapper so that CarTestManager can be constructed outside. */ manager = new CarTestManager(this, binder); break; case VEHICLE_MAP_SERVICE: manager = new VmsClientManager(this, binder); break; case VMS_SUBSCRIBER_SERVICE: manager = VmsSubscriberManager.wrap(this, (VmsClientManager) getCarManager(VEHICLE_MAP_SERVICE)); break; case STORAGE_MONITORING_SERVICE: manager = new CarStorageMonitoringManager(this, binder); break; case CAR_DRIVING_STATE_SERVICE: manager = new CarDrivingStateManager(this, binder); break; case CAR_UX_RESTRICTION_SERVICE: manager = new CarUxRestrictionsManager(this, binder); break; case OCCUPANT_AWARENESS_SERVICE: manager = new OccupantAwarenessManager(this, binder); break; case CAR_MEDIA_SERVICE: manager = new CarMediaManager(this, binder); break; case CAR_BUGREPORT_SERVICE: manager = new CarBugreportManager(this, binder); break; case CAR_USER_SERVICE: manager = new CarUserManager(this, binder); break; case EXPERIMENTAL_CAR_USER_SERVICE: manager = new ExperimentalCarUserManager(this, binder); break; case CAR_WATCHDOG_SERVICE: manager = new CarWatchdogManager(this, binder); break; case CAR_INPUT_SERVICE: manager = new CarInputManager(this, binder); break; case CAR_DEVICE_POLICY_SERVICE: manager = new CarDevicePolicyManager(this, binder); break; case CLUSTER_HOME_SERVICE: manager = new ClusterHomeManager(this, binder); break; case CAR_EVS_SERVICE: manager = new CarEvsManager(this, binder, /* featureFlags= */ null); break; case CAR_TELEMETRY_SERVICE: manager = new CarTelemetryManager(this, binder); break; case CAR_ACTIVITY_SERVICE: manager = new CarActivityManager(this, binder); break; case CAR_PERFORMANCE_SERVICE: manager = new CarPerformanceManager(this, binder); break; case CAR_REMOTE_ACCESS_SERVICE: manager = new CarRemoteAccessManager(this, binder); break; case CAR_OCCUPANT_CONNECTION_SERVICE: manager = new CarOccupantConnectionManager(this, binder); break; case CAR_REMOTE_DEVICE_SERVICE: manager = new CarRemoteDeviceManager(this, binder); break; default: // Experimental or non-existing if (Flags.displayCompatibility()) { if (serviceName.equals(CAR_DISPLAY_COMPAT_SERVICE)) { manager = new CarDisplayCompatManager(this, binder); break; } } if (Flags.persistApSettings()) { if (serviceName.equals(CAR_WIFI_SERVICE)) { manager = new CarWifiManager(this, binder); break; } } String className = null; try { synchronized (mLock) { className = mService.getCarManagerClassForFeature(serviceName); } } catch (RemoteException e) { handleRemoteExceptionFromCarService(e); return null; } if (className == null) { Slog.e(TAG_CAR, "Cannot construct CarManager for service:" + serviceName + " : no class defined"); return null; } manager = constructCarManager(className, binder); break; } return manager; } private CarManagerBase constructCarManager(String className, IBinder binder) { try { // Should use class loader for the Context as class loader for car api does not // see the class. ClassLoader loader = mContext.getClassLoader(); Class managerClass = loader.loadClass(className); Constructor constructor = managerClass.getConstructor(Car.class, IBinder.class); CarManagerBase manager = (CarManagerBase) constructor.newInstance(this, binder); return manager; } catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException e) { Slog.e(TAG_CAR, "Cannot construct CarManager, class:" + className, e); return null; } } private void startCarService() { Intent intent = new Intent(); intent.setPackage(CAR_SERVICE_PACKAGE); intent.setAction(Car.CAR_SERVICE_INTERFACE_NAME); boolean bound = mContext.bindService(intent, mServiceConnectionListener, Context.BIND_AUTO_CREATE); synchronized (mLock) { if (!bound) { mConnectionRetryCount++; if (mConnectionRetryCount > CAR_SERVICE_BIND_MAX_RETRY) { Slog.w(TAG_CAR, "cannot bind to car service after max retry"); mMainThreadEventHandler.post(mConnectionRetryFailedRunnable); } else { mEventHandler.postDelayed(mConnectionRetryRunnable, CAR_SERVICE_BIND_RETRY_INTERVAL_MS); } } else { mEventHandler.removeCallbacks(mConnectionRetryRunnable); mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable); mConnectionRetryCount = 0; mServiceBound = true; } } } @GuardedBy("mLock") private void tearDownCarManagersLocked() { // All disconnected handling should be only doing its internal cleanup. for (CarManagerBase manager : mServiceMap.values()) { manager.onCarDisconnected(); } mServiceMap.clear(); } }