Fix missing path to crash client for car service crash
- Missed service connection for one path of createCar(context)
- Also store call stack for construction time so that crash log
can tell where it was created.
Bug: 136079720
Test: kill car service and confirms clients crashing.
Change-Id: I4b695d267ed82997d0cf7073ad5c2fc77ad6f4db
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index cc18688..4ca47f8 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -682,6 +682,8 @@
private final Context mContext;
+ private final Exception mConstructionStack;
+
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -845,6 +847,8 @@
}
if (service != null) {
if (!started) { // specialization for most common case.
+ // Do this to crash client when car service crashes.
+ car.startCarService();
return car;
}
break;
@@ -1030,6 +1034,13 @@
}
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;
+ }
}
/**
@@ -1206,16 +1217,20 @@
if (mContext instanceof Activity) {
Activity activity = (Activity) mContext;
if (!activity.isFinishing()) {
- Log.w(TAG_CAR, "Car service crashed, client not handling it, finish Activity");
+ Log.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;
- throw new RuntimeException("Car service has crashed, client not handle it:"
- + service.getPackageName() + "," + service.getClass().getSimpleName());
+ throw new IllegalStateException("Car service has crashed, client not handle it:"
+ + service.getPackageName() + "," + service.getClass().getSimpleName(),
+ mConstructionStack);
}
- throw new IllegalStateException("Car service crashed, client not handling it.");
+ throw new IllegalStateException("Car service crashed, client not handling it.",
+ mConstructionStack);
}
/** @hide */
diff --git a/tests/carservice_unit_test/src/android/car/CarTest.java b/tests/carservice_unit_test/src/android/car/CarTest.java
index d12334d..d1f5ac6 100644
--- a/tests/carservice_unit_test/src/android/car/CarTest.java
+++ b/tests/carservice_unit_test/src/android/car/CarTest.java
@@ -22,8 +22,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static junit.framework.Assert.fail;
-
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.times;
@@ -154,7 +152,9 @@
@Test
public void testCreateCarSuccessWithCarServiceRunning() {
expectService(mService);
- assertThat(Car.createCar(mContext)).isNotNull();
+ Car car = Car.createCar(mContext);
+ assertThat(car).isNotNull();
+ car.disconnect();
}
@Test
@@ -173,20 +173,7 @@
Car car = Car.createCar(mContext);
assertThat(car).isNotNull();
assertServiceBoundOnce();
-
- // Just call these to guarantee that nothing crashes when service is connected /
- // disconnected.
- runOnMainSyncSafe(() -> {
- car.getServiceConnectionListener().onServiceConnected(new ComponentName("", ""),
- mService);
- try {
- car.getServiceConnectionListener().onServiceDisconnected(new ComponentName("", ""));
- } catch (IllegalStateException e) {
- // expected
- return;
- }
- fail("onServiceDisconnected should have triggered exception");
- });
+ car.disconnect();
}
@Test