Merge "Remove IBinder from CarProjectionManager API"
diff --git a/service/src/com/android/car/vms/VmsClientManager.java b/service/src/com/android/car/vms/VmsClientManager.java
index 0657cba..0cf62e7 100644
--- a/service/src/com/android/car/vms/VmsClientManager.java
+++ b/service/src/com/android/car/vms/VmsClientManager.java
@@ -23,7 +23,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.content.pm.UserInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -56,10 +55,10 @@
/**
* Called when a client connection is established or re-established.
*
- * @param clientName String that uniquely identifies the service and user.
- * @param binder Binder for communicating with the client.
+ * @param clientName String that uniquely identifies the service and user.
+ * @param clientService The IBinder of the client's communication channel.
*/
- void onClientConnected(String clientName, IBinder binder);
+ void onClientConnected(String clientName, IBinder clientService);
/**
* Called when a client connection is terminated.
@@ -114,7 +113,7 @@
/**
* Constructor for client managers.
*
- * @param context Context to use for registering receivers and binding services.
+ * @param context Context to use for registering receivers and binding services.
* @param userManagerHelper User manager for querying current user state.
*/
public VmsClientManager(Context context, CarUserManagerHelper userManagerHelper) {
@@ -142,10 +141,10 @@
mContext.unregisterReceiver(mBootCompletedReceiver);
mContext.unregisterReceiver(mUserSwitchReceiver);
synchronized (mSystemClients) {
- unbind(mSystemClients);
+ terminate(mSystemClients);
}
synchronized (mCurrentUserClients) {
- unbind(mCurrentUserClients);
+ terminate(mCurrentUserClients);
}
}
@@ -194,12 +193,12 @@
}
private void bindToCurrentUserClients() {
- UserInfo userInfo = mUserManagerHelper.getCurrentForegroundUserInfo();
+ int currentUserId = mUserManagerHelper.getCurrentForegroundUserId();
synchronized (mCurrentUserClients) {
- if (mCurrentUser != userInfo.id) {
- unbind(mCurrentUserClients);
+ if (mCurrentUser != currentUserId) {
+ terminate(mCurrentUserClients);
}
- mCurrentUser = userInfo.id;
+ mCurrentUser = currentUserId;
// To avoid the risk of double-binding, clients running as the system user must only
// ever be bound in bindToSystemClients().
@@ -212,8 +211,9 @@
String[] clientNames = mContext.getResources().getStringArray(
R.array.vmsPublisherUserClients);
Log.i(TAG, "Attempting to bind " + clientNames.length + " user client(s)");
+ UserHandle currentUserHandle = UserHandle.of(mCurrentUser);
for (String clientName : clientNames) {
- bind(mCurrentUserClients, clientName, userInfo.getUserHandle());
+ bind(mCurrentUserClients, clientName, currentUserHandle);
}
}
}
@@ -244,17 +244,17 @@
}
}
- private void unbind(Map<String, ClientConnection> connectionMap) {
+ private void terminate(Map<String, ClientConnection> connectionMap) {
for (ClientConnection connection : connectionMap.values()) {
- connection.unbind();
+ connection.terminate();
}
connectionMap.clear();
}
- private void notifyListenersOnClientConnected(String clientName, IBinder binder) {
+ private void notifyListenersOnClientConnected(String clientName, IBinder clientService) {
synchronized (mListeners) {
for (ConnectionListener listener : mListeners) {
- listener.onClientConnected(clientName, binder);
+ listener.onClientConnected(clientName, clientService);
}
}
}
@@ -272,7 +272,8 @@
private final UserHandle mUser;
private final String mFullName;
private boolean mIsBound = false;
- private IBinder mBinder;
+ private boolean mIsTerminated = false;
+ private IBinder mClientService;
ClientConnection(ComponentName name, UserHandle user) {
mName = name;
@@ -281,10 +282,12 @@
}
synchronized boolean bind() {
- // Ignore if already bound
if (mIsBound) {
return true;
}
+ if (mIsTerminated) {
+ return false;
+ }
if (DBG) Log.d(TAG, "binding: " + mFullName);
Intent intent = new Intent();
@@ -307,26 +310,34 @@
Log.e(TAG, "While unbinding " + mFullName, t);
}
mIsBound = false;
- if (mBinder != null) {
+ if (mClientService != null) {
notifyListenersOnClientDisconnected(mFullName);
}
- mBinder = null;
+ mClientService = null;
}
- void rebind() {
+ synchronized void rebind() {
unbind();
if (DBG) {
Log.d(TAG,
String.format("rebinding %s after %dms", mFullName, mMillisBeforeRebind));
}
- mHandler.postDelayed(this::bind, mMillisBeforeRebind);
+ if (!mIsTerminated) {
+ mHandler.postDelayed(this::bind, mMillisBeforeRebind);
+ }
+ }
+
+ synchronized void terminate() {
+ if (DBG) Log.d(TAG, "terminating: " + mFullName);
+ mIsTerminated = true;
+ unbind();
}
@Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
+ public void onServiceConnected(ComponentName name, IBinder service) {
if (DBG) Log.d(TAG, "onServiceConnected: " + mFullName);
- mBinder = binder;
- notifyListenersOnClientConnected(mFullName, mBinder);
+ mClientService = service;
+ notifyListenersOnClientConnected(mFullName, mClientService);
}
@Override
@@ -344,7 +355,7 @@
@Override
public void onNullBinding(ComponentName name) {
if (DBG) Log.d(TAG, "onNullBinding: " + mFullName);
- unbind();
+ terminate();
}
@Override
diff --git a/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java b/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
index a1ff59f..15e7feb 100644
--- a/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
@@ -23,6 +23,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -37,7 +38,6 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.os.Binder;
import android.os.Handler;
@@ -70,7 +70,7 @@
private Resources mResources;
@Mock
private CarUserManagerHelper mUserManager;
- private UserInfo mUserInfo;
+ private int mUserId;
@Mock
private VmsClientManager.ConnectionListener mConnectionListener;
@@ -89,16 +89,17 @@
5);
when(mResources.getStringArray(
com.android.car.R.array.vmsPublisherSystemClients)).thenReturn(
- new String[]{
- "com.google.android.apps.vms.test/.VmsSystemClient"
- });
+ new String[]{
+ "com.google.android.apps.vms.test/.VmsSystemClient"
+ });
when(mResources.getStringArray(
com.android.car.R.array.vmsPublisherUserClients)).thenReturn(
- new String[]{
- "com.google.android.apps.vms.test/.VmsUserClient"
- });
- mUserInfo = new UserInfo(10, "Driver", 0);
- when(mUserManager.getCurrentForegroundUserInfo()).thenReturn(mUserInfo);
+ new String[]{
+ "com.google.android.apps.vms.test/.VmsUserClient"
+ });
+
+ mUserId = 10;
+ when(mUserManager.getCurrentForegroundUserId()).thenAnswer((invocation) -> mUserId);
mClientManager = new VmsClientManager(mContext, mUserManager);
mClientManager.registerConnectionListener(mConnectionListener);
@@ -244,12 +245,12 @@
@Test
public void testUserSwitchedToSystemUser() {
- mUserInfo = new UserInfo(UserHandle.USER_SYSTEM, "Owner", 0);
- when(mUserManager.getCurrentForegroundUserInfo()).thenReturn(mUserInfo);
+ mUserId = UserHandle.USER_SYSTEM;
notifyUserSwitched();
// System user should not trigger any binding
- verifyUserBind(0);
+ verifySystemBind(0);
+ verifyNoBind();
}
@Test
@@ -502,16 +503,14 @@
resetContext();
reset(mConnectionListener);
- mUserInfo = new UserInfo(11, "Driver", 0);
- when(mUserManager.getCurrentForegroundUserInfo()).thenReturn(mUserInfo);
+ mUserId = 11;
notifyUserSwitched();
verify(mContext).unbindService(connection);
verify(mConnectionListener).onClientDisconnected(
eq("com.google.android.apps.vms.test/com.google.android.apps.vms.test"
+ ".VmsUserClient U=10"));
- verifyBind(1, "com.google.android.apps.vms.test/.VmsUserClient",
- mUserInfo.getUserHandle());
+ verifyUserBind(1);
}
@Test
@@ -523,8 +522,7 @@
resetContext();
reset(mConnectionListener);
- mUserInfo = new UserInfo(UserHandle.USER_SYSTEM, "Owner", 0);
- when(mUserManager.getCurrentForegroundUserInfo()).thenReturn(mUserInfo);
+ mUserId = UserHandle.USER_SYSTEM;
notifyUserSwitched();
verify(mContext).unbindService(connection);
@@ -532,8 +530,7 @@
eq("com.google.android.apps.vms.test/com.google.android.apps.vms.test"
+ ".VmsUserClient U=10"));
// User processes will not be bound for system user
- verifyBind(0, "com.google.android.apps.vms.test/.VmsUserClient",
- mUserInfo.getUserHandle());
+ verifyNoBind();
}
@Test
@@ -543,13 +540,11 @@
ServiceConnection connection = mConnectionCaptor.getValue();
resetContext();
- mUserInfo = new UserInfo(11, "Driver", 0);
- when(mUserManager.getCurrentForegroundUserInfo()).thenReturn(mUserInfo);
+ mUserId = 11;
notifyUserSwitched();
verify(mContext).unbindService(connection);
- verifyBind(1, "com.google.android.apps.vms.test/.VmsUserClient",
- mUserInfo.getUserHandle());
+ verifyUserBind(1);
}
@Test
@@ -561,16 +556,14 @@
resetContext();
reset(mConnectionListener);
- mUserInfo = new UserInfo(11, "Driver", 0);
- when(mUserManager.getCurrentForegroundUserInfo()).thenReturn(mUserInfo);
+ mUserId = 11;
notifyUserUnlocked();
verify(mContext).unbindService(connection);
verify(mConnectionListener).onClientDisconnected(
eq("com.google.android.apps.vms.test/com.google.android.apps.vms.test"
+ ".VmsUserClient U=10"));
- verifyBind(1, "com.google.android.apps.vms.test/.VmsUserClient",
- mUserInfo.getUserHandle());
+ verifyUserBind(1);
}
@Test
@@ -582,8 +575,7 @@
resetContext();
reset(mConnectionListener);
- mUserInfo = new UserInfo(UserHandle.USER_SYSTEM, "Owner", 0);
- when(mUserManager.getCurrentForegroundUserInfo()).thenReturn(mUserInfo);
+ mUserId = UserHandle.USER_SYSTEM;
notifyUserUnlocked();
verify(mContext).unbindService(connection);
@@ -591,8 +583,7 @@
eq("com.google.android.apps.vms.test/com.google.android.apps.vms.test"
+ ".VmsUserClient U=10"));
// User processes will not be bound for system user
- verifyBind(0, "com.google.android.apps.vms.test/.VmsUserClient",
- mUserInfo.getUserHandle());
+ verifyNoBind();
}
@Test
@@ -602,13 +593,11 @@
ServiceConnection connection = mConnectionCaptor.getValue();
resetContext();
- mUserInfo = new UserInfo(11, "Driver", 0);
- when(mUserManager.getCurrentForegroundUserInfo()).thenReturn(mUserInfo);
+ mUserId = 11;
notifyUserUnlocked();
verify(mContext).unbindService(connection);
- verifyBind(1, "com.google.android.apps.vms.test/.VmsUserClient",
- mUserInfo.getUserHandle());
+ verifyUserBind(1);
}
private void resetContext() {
@@ -640,7 +629,12 @@
private void verifyUserBind(int times) {
verifyBind(times, "com.google.android.apps.vms.test/.VmsUserClient",
- mUserInfo.getUserHandle());
+ UserHandle.of(mUserId));
+ }
+
+ private void verifyNoBind() {
+ verify(mContext, never()).bindServiceAsUser(any(Intent.class), any(ServiceConnection.class),
+ anyInt(), any(Handler.class), any(UserHandle.class));
}
private void verifyBind(int times, String componentName,
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2eCarTestBase.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2eCarTestBase.java
index d78713f..24ee1ff 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2eCarTestBase.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2eCarTestBase.java
@@ -47,7 +47,7 @@
public class E2eCarTestBase {
private static final String TAG = Utils.concatTag(E2eCarTestBase.class);
- private static final int DEFAULT_WAIT_TIMEOUT_MS = 1000;
+ private static final int DEFAULT_WAIT_TIMEOUT_MS = 5000;
protected IVehicle mVehicle;
protected Car mCar;
@@ -56,7 +56,7 @@
@Before
public void connectToVehicleHal() throws Exception {
- mVehicle = Utils.getVehicle();
+ mVehicle = Utils.getVehicleWithTimeout(DEFAULT_WAIT_TIMEOUT_MS);
mVehicle.getPropConfigs(
Lists.newArrayList(VhalEventGenerator.GENERATE_FAKE_DATA_CONTROLLING_PROPERTY),
(status, propConfigs) -> assumeTrue(status == StatusCode.OK));
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java
index 56ce568..6399549 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java
@@ -183,10 +183,10 @@
final int EXPECTED_INVOCATIONS = 1000; // How many time get/set will be called.
- final int EXPECTED_DURATION_MS = 2500;
+ final int EXPECTED_DURATION_MS = 3000;
// This is a stress test and it can be flaky because it shares resources with all currently
// running process. Let's have this number of attempt before giving up.
- final int ATTEMPTS = 3;
+ final int ATTEMPTS = 5;
for (int curAttempt = 0; curAttempt < ATTEMPTS; curAttempt++) {
long missingInvocations = stressTestHvacProperties(mgr, cfg,
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java
index 0d6048d..fb09ebd 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java
@@ -18,6 +18,7 @@
import static com.android.car.vehiclehal.test.Utils.isVhalPropertyAvailable;
import static com.android.car.vehiclehal.test.Utils.readVhalProperty;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeTrue;
@@ -37,12 +38,12 @@
/** Test retrieving the OBD2_FREEZE_FRAME property from VHAL */
public class Obd2FreezeFrameTest {
private static final String TAG = Utils.concatTag(Obd2FreezeFrameTest.class);
-
+ private static final int DEFAULT_WAIT_TIMEOUT_MS = 5000;
private IVehicle mVehicle = null;
@Before
public void setUp() throws Exception {
- mVehicle = Utils.getVehicle();
+ mVehicle = Utils.getVehicleWithTimeout(DEFAULT_WAIT_TIMEOUT_MS);
assumeTrue("Freeze frame not available, test-case ignored.", isFreezeFrameAvailable());
}
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java
index 25f2454..627e032 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java
@@ -18,6 +18,7 @@
import static com.android.car.vehiclehal.test.Utils.isVhalPropertyAvailable;
import static com.android.car.vehiclehal.test.Utils.readVhalProperty;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeTrue;
@@ -35,12 +36,12 @@
/** Test retrieving the OBD2_LIVE_FRAME property from VHAL */
public class Obd2LiveFrameTest {
private static final String TAG = Utils.concatTag(Obd2LiveFrameTest.class);
-
+ private static final int DEFAULT_WAIT_TIMEOUT_MS = 5000;
private IVehicle mVehicle = null;
@Before
public void setUp() throws Exception {
- mVehicle = Utils.getVehicle();
+ mVehicle = Utils.getVehicleWithTimeout(DEFAULT_WAIT_TIMEOUT_MS);
assumeTrue("Live frame not available, test-case ignored.", isLiveFrameAvailable());
}
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java
index 496b504..952f430 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java
@@ -16,6 +16,9 @@
package com.android.car.vehiclehal.test;
+import static android.os.SystemClock.elapsedRealtime;
+
+import android.annotation.Nullable;
import android.car.hardware.CarPropertyValue;
import android.hardware.automotive.vehicle.V2_0.IVehicle;
import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
@@ -81,15 +84,32 @@
return readVhalProperty(vehicle, request, f);
}
- static IVehicle getVehicle() throws RemoteException {
- IVehicle service;
+ @Nullable
+ private static IVehicle getVehicle() {
try {
- service = IVehicle.getService();
+ return IVehicle.getService();
} catch (NoSuchElementException ex) {
- throw new RuntimeException("Couldn't connect to vehicle@2.0", ex);
+ Log.e(TAG, "IVehicle service not registered yet", ex);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get IVehicle Service ", e);
}
- Log.d(TAG, "Connected to IVehicle service: " + service);
- return service;
+ Log.d(TAG, "Failed to connect to IVehicle service");
+ return null;
+ }
+
+ static IVehicle getVehicleWithTimeout(long waitMilliseconds) {
+ IVehicle vehicle = getVehicle();
+ long endTime = elapsedRealtime() + waitMilliseconds;
+ while (vehicle == null && endTime > elapsedRealtime()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Sleep was interrupted", e);
+ }
+ vehicle = getVehicle();
+ }
+
+ return vehicle;
}
/**