Merge "Add independent playback modes to CarMediaService" into rvc-dev
diff --git a/computepipe/runner/engine/DefaultEngine.cpp b/computepipe/runner/engine/DefaultEngine.cpp
index d93de2e..0f7c160 100644
--- a/computepipe/runner/engine/DefaultEngine.cpp
+++ b/computepipe/runner/engine/DefaultEngine.cpp
@@ -130,8 +130,16 @@
return Status::SUCCESS;
}
if (command.has_death_notification()) {
- mCurrentPhaseError = std::make_unique<ComponentError>(
- "ClientInterface", "Client death", mCurrentPhase, false);
+ if (mCurrentPhase == kResetPhase) {
+ /**
+ * The runner is already in reset state, no need to broadcast client death
+ * to components
+ */
+ LOG(INFO) << "client death notification with no configuration";
+ return Status::SUCCESS;
+ }
+ mCurrentPhaseError = std::make_unique<ComponentError>("ClientInterface", "Client death",
+ mCurrentPhase, false);
mWakeLooper.notify_all();
return Status::SUCCESS;
}
diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index 179623d..b051569 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -23,3 +23,6 @@
# Allow the driver to access kobject uevents
allow hal_evs_driver self:netlink_kobject_uevent_socket create_socket_perms_no_ioctl;
+# Allow the driver to use automotive display proxy service
+allow hal_evs_driver automotive_display_service_server:binder call;
+
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 348522d..b15ede5 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -59,6 +59,20 @@
@GuardedBy("mLock")
private @Nullable ICarWatchdog mCarWatchdogDaemon;
+ private final DeathRecipient mDeathRecipient = new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ Log.w(TAG_WATCHDOG, "Car watchdog daemon died: reconnecting");
+ unlinkToDeath();
+ synchronized (mLock) {
+ mCarWatchdogDaemon = null;
+ }
+ mMainHandler.postDelayed(() -> {
+ connectToDaemon(CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY);
+ }, CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS);
+ }
+ };
+
public CarWatchdogService(Context context) {
// Car watchdog daemon is found at init().
this(context, /* daemon= */ null);
@@ -81,12 +95,14 @@
if (daemon == null) {
connectToDaemon(CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY);
} else {
+ linkToDeath();
registerToDaemon(daemon);
}
}
@Override
public void release() {
+ unlinkToDeath();
ICarWatchdog daemon;
synchronized (mLock) {
daemon = mCarWatchdogDaemon;
@@ -149,23 +165,6 @@
Log.wtf(TAG_WATCHDOG,
"Finding car watchdog daemon took too long(" + elapsedTimeMs + "ms)");
}
- try {
- binder.linkToDeath(new DeathRecipient() {
- @Override
- public void binderDied() {
- Log.w(TAG_WATCHDOG, "Car watchdog daemon died: reconnecting");
- synchronized (mLock) {
- mCarWatchdogDaemon = null;
- }
- mMainHandler.postDelayed(() -> {
- connectToDaemon(CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY);
- }, CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS);
- }
- }, 0);
- } catch (RemoteException e) {
- Log.w(TAG_WATCHDOG, "Linking to binder death recipient failed: " + e);
- return false;
- }
ICarWatchdog daemon = ICarWatchdog.Stub.asInterface(binder);
if (daemon == null) {
@@ -175,6 +174,7 @@
synchronized (mLock) {
mCarWatchdogDaemon = daemon;
}
+ linkToDeath();
registerToDaemon(daemon);
return true;
}
@@ -211,6 +211,32 @@
});
}
+ private void linkToDeath() {
+ IBinder binder;
+ synchronized (mLock) {
+ if (mCarWatchdogDaemon == null) {
+ return;
+ }
+ binder = mCarWatchdogDaemon.asBinder();
+ }
+ try {
+ binder.linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG_WATCHDOG, "Linking to binder death recipient failed: " + e);
+ }
+ }
+
+ private void unlinkToDeath() {
+ IBinder binder;
+ synchronized (mLock) {
+ if (mCarWatchdogDaemon == null) {
+ return;
+ }
+ binder = mCarWatchdogDaemon.asBinder();
+ }
+ binder.unlinkToDeath(mDeathRecipient, 0);
+ }
+
private static final class ICarWatchdogClientImpl extends ICarWatchdogClient.Stub {
private final WeakReference<CarWatchdogService> mService;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/AbstractBluetoothA2dpPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/AbstractBluetoothA2dpPreferenceController.java
index d4afe48..1451f19 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/AbstractBluetoothA2dpPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/AbstractBluetoothA2dpPreferenceController.java
@@ -83,7 +83,10 @@
final BluetoothCodecConfig codecConfig = mBluetoothA2dpConfigStore.createCodecConfig();
synchronized (mBluetoothA2dpConfigStore) {
if (mBluetoothA2dp != null) {
- setCodecConfigPreference(null, codecConfig); // Use current active device
+ BluetoothDevice activeDevice = mBluetoothA2dp.getActiveDevice();
+ if (activeDevice != null) {
+ setCodecConfigPreference(mBluetoothA2dp.getActiveDevice(), codecConfig);
+ }
}
}
// Because the setting is not persisted into permanent storage, we cannot call update state
@@ -102,13 +105,14 @@
@Override
public void updateState(Preference preference) {
- if (getCodecConfig(null) == null || mPreference == null) { // Use current active device
+ BluetoothDevice activeDevice = mBluetoothA2dp.getActiveDevice();
+ if (activeDevice == null || getCodecConfig(activeDevice) == null || mPreference == null) {
return;
}
BluetoothCodecConfig codecConfig;
synchronized (mBluetoothA2dpConfigStore) {
- codecConfig = getCodecConfig(null); // Use current active device
+ codecConfig = getCodecConfig(activeDevice); // Use current active device
}
final int index = getCurrentA2dpSettingIndex(codecConfig);
@@ -178,13 +182,22 @@
@VisibleForTesting
void setCodecConfigPreference(BluetoothDevice device,
BluetoothCodecConfig config) {
- mBluetoothA2dp.setCodecConfigPreference(device, config);
+ BluetoothDevice bluetoothDevice =
+ (device != null) ? device : mBluetoothA2dp.getActiveDevice();
+ if (bluetoothDevice != null) {
+ mBluetoothA2dp.setCodecConfigPreference(bluetoothDevice, config);
+ }
}
@VisibleForTesting
BluetoothCodecConfig getCodecConfig(BluetoothDevice device) {
if (mBluetoothA2dp != null) {
- BluetoothCodecStatus codecStatus = mBluetoothA2dp.getCodecStatus(device);
+ BluetoothDevice bluetoothDevice =
+ (device != null) ? device : mBluetoothA2dp.getActiveDevice();
+ if (bluetoothDevice == null) {
+ return null;
+ }
+ BluetoothCodecStatus codecStatus = mBluetoothA2dp.getCodecStatus(bluetoothDevice);
if (codecStatus != null) {
return codecStatus.getCodecConfig();
}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/BluetoothAudioCodecPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/BluetoothAudioCodecPreferenceController.java
index 5cf9adc..74858b6 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/BluetoothAudioCodecPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/BluetoothAudioCodecPreferenceController.java
@@ -17,6 +17,7 @@
package com.android.car.developeroptions.development;
import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothDevice;
import android.content.Context;
import com.android.car.developeroptions.R;
@@ -109,14 +110,20 @@
case 6:
synchronized (mBluetoothA2dpConfigStore) {
if (mBluetoothA2dp != null) {
- mBluetoothA2dp.enableOptionalCodecs(null); // Use current active device
+ BluetoothDevice activeDevice = mBluetoothA2dp.getActiveDevice();
+ if (activeDevice != null) {
+ mBluetoothA2dp.enableOptionalCodecs(activeDevice);
+ }
}
}
return;
case 7:
synchronized (mBluetoothA2dpConfigStore) {
if (mBluetoothA2dp != null) {
- mBluetoothA2dp.disableOptionalCodecs(null); // Use current active device
+ BluetoothDevice activeDevice = mBluetoothA2dp.getActiveDevice();
+ if (activeDevice != null) {
+ mBluetoothA2dp.disableOptionalCodecs(activeDevice);
+ }
}
}
return;
diff --git a/tests/SecurityPermissionTest/Android.bp b/tests/SecurityPermissionTest/Android.bp
index f77d151..028875e 100644
--- a/tests/SecurityPermissionTest/Android.bp
+++ b/tests/SecurityPermissionTest/Android.bp
@@ -30,6 +30,7 @@
"androidx.test.core",
"androidx.test.ext.junit",
"androidx.test.rules",
+ "truth-prebuilt",
"car-frameworks-service",
"testng",
],
diff --git a/tests/SecurityPermissionTest/src/com/android/car/CarPropertyManagerPublicTest.java b/tests/SecurityPermissionTest/src/com/android/car/CarPropertyManagerPublicTest.java
new file mode 100644
index 0000000..111afe4
--- /dev/null
+++ b/tests/SecurityPermissionTest/src/com/android/car/CarPropertyManagerPublicTest.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2020 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 com.android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.Car;
+import android.car.VehicleAreaType;
+import android.car.VehiclePropertyIds;
+import android.car.VehiclePropertyType;
+import android.car.hardware.property.CarPropertyManager;
+import android.os.Handler;
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+
+/**
+ * This class contains security permission tests for the {@link CarPropertyManager}'s public APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarPropertyManagerPublicTest {
+ private Car mCar = null;
+ private CarPropertyManager mPropertyManager;
+ private HashSet<Integer> mProps = new HashSet<>();
+ private static final String TAG = CarPropertyManagerPublicTest.class.getSimpleName();
+ private static final Integer DUMMY_AREA_ID = VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+ @Before
+ public void setUp() throws Exception {
+ initAllPropertyIds();
+ mCar = Car.createCar(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), (Handler) null);
+ mPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
+ assertThat(mPropertyManager).isNotNull();
+ }
+
+ private synchronized void initAllPropertyIds() {
+ mProps.add(VehiclePropertyIds.DOOR_POS);
+ mProps.add(VehiclePropertyIds.DOOR_MOVE);
+ mProps.add(VehiclePropertyIds.DOOR_LOCK);
+ mProps.add(VehiclePropertyIds.MIRROR_Z_POS);
+ mProps.add(VehiclePropertyIds.MIRROR_Z_MOVE);
+ mProps.add(VehiclePropertyIds.MIRROR_Y_POS);
+ mProps.add(VehiclePropertyIds.MIRROR_Y_MOVE);
+ mProps.add(VehiclePropertyIds.MIRROR_LOCK);
+ mProps.add(VehiclePropertyIds.MIRROR_FOLD);
+ mProps.add(VehiclePropertyIds.SEAT_MEMORY_SELECT);
+ mProps.add(VehiclePropertyIds.SEAT_MEMORY_SET);
+ mProps.add(VehiclePropertyIds.SEAT_BELT_BUCKLED);
+ mProps.add(VehiclePropertyIds.SEAT_BELT_HEIGHT_POS);
+ mProps.add(VehiclePropertyIds.SEAT_BELT_HEIGHT_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_FORE_AFT_POS);
+ mProps.add(VehiclePropertyIds.SEAT_FORE_AFT_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_POS);
+ mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_POS);
+ mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_HEIGHT_POS);
+ mProps.add(VehiclePropertyIds.SEAT_HEIGHT_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_DEPTH_POS);
+ mProps.add(VehiclePropertyIds.SEAT_DEPTH_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_TILT_POS);
+ mProps.add(VehiclePropertyIds.SEAT_TILT_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_POS);
+ mProps.add(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_POS);
+ mProps.add(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_POS);
+ mProps.add(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_HEADREST_ANGLE_POS);
+ mProps.add(VehiclePropertyIds.SEAT_HEADREST_ANGLE_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_POS);
+ mProps.add(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_MOVE);
+ mProps.add(VehiclePropertyIds.SEAT_OCCUPANCY);
+ mProps.add(VehiclePropertyIds.WINDOW_POS);
+ mProps.add(VehiclePropertyIds.WINDOW_MOVE);
+ mProps.add(VehiclePropertyIds.WINDOW_LOCK);
+
+ // HVAC properties
+ mProps.add(VehiclePropertyIds.HVAC_FAN_SPEED);
+ mProps.add(VehiclePropertyIds.HVAC_FAN_DIRECTION);
+ mProps.add(VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT);
+ mProps.add(VehiclePropertyIds.HVAC_TEMPERATURE_SET);
+ mProps.add(VehiclePropertyIds.HVAC_DEFROSTER);
+ mProps.add(VehiclePropertyIds.HVAC_ELECTRIC_DEFROSTER_ON);
+ mProps.add(VehiclePropertyIds.HVAC_AC_ON);
+ mProps.add(VehiclePropertyIds.HVAC_MAX_AC_ON);
+ mProps.add(VehiclePropertyIds.HVAC_MAX_DEFROST_ON);
+ mProps.add(VehiclePropertyIds.HVAC_RECIRC_ON);
+ mProps.add(VehiclePropertyIds.HVAC_DUAL_ON);
+ mProps.add(VehiclePropertyIds.HVAC_AUTO_ON);
+ mProps.add(VehiclePropertyIds.HVAC_SEAT_TEMPERATURE);
+ mProps.add(VehiclePropertyIds.HVAC_SIDE_MIRROR_HEAT);
+ mProps.add(VehiclePropertyIds.HVAC_STEERING_WHEEL_HEAT);
+ mProps.add(VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS);
+ mProps.add(VehiclePropertyIds.HVAC_ACTUAL_FAN_SPEED_RPM);
+ mProps.add(VehiclePropertyIds.HVAC_POWER_ON);
+ mProps.add(VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE);
+ mProps.add(VehiclePropertyIds.HVAC_AUTO_RECIRC_ON);
+ mProps.add(VehiclePropertyIds.HVAC_SEAT_VENTILATION);
+
+ // Info properties
+ mProps.add(VehiclePropertyIds.INFO_VIN);
+ mProps.add(VehiclePropertyIds.INFO_MAKE);
+ mProps.add(VehiclePropertyIds.INFO_MODEL);
+ mProps.add(VehiclePropertyIds.INFO_MODEL_YEAR);
+ mProps.add(VehiclePropertyIds.INFO_FUEL_CAPACITY);
+ mProps.add(VehiclePropertyIds.INFO_FUEL_TYPE);
+ mProps.add(VehiclePropertyIds.INFO_EV_BATTERY_CAPACITY);
+ mProps.add(VehiclePropertyIds.INFO_EV_CONNECTOR_TYPE);
+ mProps.add(VehiclePropertyIds.INFO_FUEL_DOOR_LOCATION);
+ mProps.add(VehiclePropertyIds.INFO_MULTI_EV_PORT_LOCATIONS);
+ mProps.add(VehiclePropertyIds.INFO_EV_PORT_LOCATION);
+ mProps.add(VehiclePropertyIds.INFO_DRIVER_SEAT);
+ mProps.add(VehiclePropertyIds.INFO_EXTERIOR_DIMENSIONS);
+
+ // Sensor properties
+ mProps.add(VehiclePropertyIds.PERF_ODOMETER);
+ mProps.add(VehiclePropertyIds.PERF_VEHICLE_SPEED);
+ mProps.add(VehiclePropertyIds.PERF_VEHICLE_SPEED_DISPLAY);
+ mProps.add(VehiclePropertyIds.ENGINE_COOLANT_TEMP);
+ mProps.add(VehiclePropertyIds.ENGINE_OIL_LEVEL);
+ mProps.add(VehiclePropertyIds.ENGINE_OIL_TEMP);
+ mProps.add(VehiclePropertyIds.ENGINE_RPM);
+ mProps.add(VehiclePropertyIds.WHEEL_TICK);
+ mProps.add(VehiclePropertyIds.FUEL_LEVEL);
+ mProps.add(VehiclePropertyIds.FUEL_DOOR_OPEN);
+ mProps.add(VehiclePropertyIds.EV_BATTERY_LEVEL);
+ mProps.add(VehiclePropertyIds.EV_CHARGE_PORT_OPEN);
+ mProps.add(VehiclePropertyIds.EV_CHARGE_PORT_CONNECTED);
+ mProps.add(VehiclePropertyIds.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE);
+ mProps.add(VehiclePropertyIds.RANGE_REMAINING);
+ mProps.add(VehiclePropertyIds.TIRE_PRESSURE);
+ mProps.add(VehiclePropertyIds.PERF_STEERING_ANGLE);
+ mProps.add(VehiclePropertyIds.PERF_REAR_STEERING_ANGLE);
+ mProps.add(VehiclePropertyIds.GEAR_SELECTION);
+ mProps.add(VehiclePropertyIds.CURRENT_GEAR);
+ mProps.add(VehiclePropertyIds.PARKING_BRAKE_ON);
+ mProps.add(VehiclePropertyIds.PARKING_BRAKE_AUTO_APPLY);
+ mProps.add(VehiclePropertyIds.FUEL_LEVEL_LOW);
+ mProps.add(VehiclePropertyIds.NIGHT_MODE);
+ mProps.add(VehiclePropertyIds.TURN_SIGNAL_STATE);
+ mProps.add(VehiclePropertyIds.IGNITION_STATE);
+ mProps.add(VehiclePropertyIds.ABS_ACTIVE);
+ mProps.add(VehiclePropertyIds.TRACTION_CONTROL_ACTIVE);
+ mProps.add(VehiclePropertyIds.ENV_OUTSIDE_TEMPERATURE);
+ mProps.add(VehiclePropertyIds.HEADLIGHTS_STATE);
+ mProps.add(VehiclePropertyIds.HIGH_BEAM_LIGHTS_STATE);
+ mProps.add(VehiclePropertyIds.FOG_LIGHTS_STATE);
+ mProps.add(VehiclePropertyIds.HAZARD_LIGHTS_STATE);
+ mProps.add(VehiclePropertyIds.HEADLIGHTS_SWITCH);
+ mProps.add(VehiclePropertyIds.HIGH_BEAM_LIGHTS_SWITCH);
+ mProps.add(VehiclePropertyIds.FOG_LIGHTS_SWITCH);
+ mProps.add(VehiclePropertyIds.HAZARD_LIGHTS_SWITCH);
+ mProps.add(VehiclePropertyIds.READING_LIGHTS_STATE);
+ mProps.add(VehiclePropertyIds.CABIN_LIGHTS_STATE);
+ mProps.add(VehiclePropertyIds.READING_LIGHTS_SWITCH);
+ mProps.add(VehiclePropertyIds.CABIN_LIGHTS_SWITCH);
+ // Display_Units
+ mProps.add(VehiclePropertyIds.DISTANCE_DISPLAY_UNITS);
+ mProps.add(VehiclePropertyIds.FUEL_VOLUME_DISPLAY_UNITS);
+ mProps.add(VehiclePropertyIds.TIRE_PRESSURE_DISPLAY_UNITS);
+ mProps.add(VehiclePropertyIds.EV_BATTERY_DISPLAY_UNITS);
+ mProps.add(VehiclePropertyIds.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME);
+ mProps.add(VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS);
+ }
+
+ @After
+ public void tearDown() {
+ if (mCar != null) {
+ mCar.disconnect();
+ }
+ }
+
+ @Test
+ public void testCarPropertyManagerGetter() {
+ for (int propertyId : mProps) {
+ try {
+ switch (propertyId & VehiclePropertyType.MASK) {
+ case VehiclePropertyType.BOOLEAN:
+ // The areaId may not match with it in propertyConfig. CarService
+ // check the permission before checking valid areaId.
+ mPropertyManager.getBooleanProperty(propertyId, DUMMY_AREA_ID);
+ break;
+ case VehiclePropertyType.FLOAT:
+ mPropertyManager.getFloatProperty(propertyId, DUMMY_AREA_ID);
+ break;
+ case VehiclePropertyType.INT32_VEC:
+ mPropertyManager.getIntArrayProperty(propertyId, DUMMY_AREA_ID);
+ break;
+ case VehiclePropertyType.INT32:
+ mPropertyManager.getIntProperty(propertyId, DUMMY_AREA_ID);
+ break;
+ default:
+ mPropertyManager.getProperty(propertyId, DUMMY_AREA_ID);
+ }
+ } catch (Exception e) {
+ assertWithMessage("Get property: 0x" + Integer.toHexString(propertyId)
+ + " cause an unexpected exception: " + e)
+ .that(e).isInstanceOf(SecurityException.class);
+ continue;
+ }
+ assertPropertyNotImplementedInVhal(propertyId);
+ }
+ }
+
+ private void assertPropertyNotImplementedInVhal(int propertyId) {
+ assertWithMessage("Get property : 0x " + Integer.toHexString(propertyId)
+ + " without permission.")
+ .that(mPropertyManager.getProperty(propertyId, DUMMY_AREA_ID)).isNull();
+ Log.w(TAG, "Property id: 0x" + Integer.toHexString(propertyId)
+ + " does not exist in the VHAL implementation.");
+ }
+
+}
diff --git a/tests/carservice_test/src/com/android/car/watchdog/CarWatchdogManagerTest.java b/tests/carservice_test/src/com/android/car/watchdog/CarWatchdogManagerTest.java
new file mode 100644
index 0000000..345d7c3
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/watchdog/CarWatchdogManagerTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 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 com.android.car;
+
+import static android.car.watchdog.CarWatchdogManager.TIMEOUT_NORMAL;
+
+import static org.testng.Assert.assertThrows;
+
+import android.car.Car;
+import android.car.watchdog.CarWatchdogManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class CarWatchdogManagerTest extends MockedCarTestBase {
+
+ private static final String TAG = CarWatchdogManagerTest.class.getSimpleName();
+
+ private CarWatchdogManager mCarWatchdogManager;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mCarWatchdogManager = (CarWatchdogManager) getCar().getCarManager(Car.CAR_WATCHDOG_SERVICE);
+ }
+
+ @Test
+ public void testRegisterClient() throws Exception {
+ TestClient client = new TestClient();
+ mCarWatchdogManager.registerClient(getContext().getMainExecutor(), client, TIMEOUT_NORMAL);
+ mCarWatchdogManager.unregisterClient(client);
+ }
+
+ @Test
+ public void testUnregisterUnregisteredClient() throws Exception {
+ TestClient client = new TestClient();
+ mCarWatchdogManager.registerClient(getContext().getMainExecutor(), client, TIMEOUT_NORMAL);
+ mCarWatchdogManager.unregisterClient(client);
+ // The following call should not throw an exception.
+ mCarWatchdogManager.unregisterClient(client);
+ }
+
+ @Test
+ public void testRegisterMultipleClients() {
+ Executor executor = getContext().getMainExecutor();
+ TestClient client1 = new TestClient();
+ TestClient client2 = new TestClient();
+ mCarWatchdogManager.registerClient(executor, client1, TIMEOUT_NORMAL);
+ assertThrows(IllegalStateException.class,
+ () -> mCarWatchdogManager.registerClient(executor, client2, TIMEOUT_NORMAL));
+ }
+
+ public class TestClient extends CarWatchdogManager.CarWatchdogClientCallback {
+ @Override
+ public boolean onCheckHealthStatus(int sessionId, int timeout) {
+ return true;
+ }
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java
index dcc6f81..3ab03e5 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java
@@ -18,11 +18,16 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+
import android.automotive.watchdog.ICarWatchdog;
import android.automotive.watchdog.ICarWatchdogClient;
import android.automotive.watchdog.TimeoutLength;
import android.content.Context;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
@@ -47,6 +52,7 @@
private static final String TAG = CarWatchdogServiceTest.class.getSimpleName();
@Mock private Context mMockContext;
+ @Mock private IBinder mBinder;
private CarWatchdogService mCarWatchdogService;
private FakeCarWatchdog mFakeCarWatchdog;
@@ -71,6 +77,18 @@
assertThat(mFakeCarWatchdog.gotResponse()).isTrue();
}
+ @Test
+ public void testLinkUnlinkDeathRecipient() {
+ mCarWatchdogService.init();
+ try {
+ verify(mBinder).linkToDeath(any(), anyInt());
+ } catch (RemoteException e) {
+ // Do nothing
+ }
+ mCarWatchdogService.release();
+ verify(mBinder).unlinkToDeath(any(), anyInt());
+ }
+
// FakeCarWatchdog mimics ICarWatchdog daemon in local process.
final class FakeCarWatchdog extends ICarWatchdog.Default {
@@ -98,6 +116,11 @@
}
@Override
+ public IBinder asBinder() {
+ return mBinder;
+ }
+
+ @Override
public void registerMediator(ICarWatchdogClient mediator) throws RemoteException {
mClients.add(mediator);
mMainHandler.post(() -> {