Merge "Force car service crash handling to client"
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index 6716a69..2d03cc9 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -24,6 +24,8 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
+import android.app.Activity;
+import android.app.Service;
 import android.car.cluster.CarInstrumentClusterManager;
 import android.car.cluster.ClusterActivityState;
 import android.car.content.pm.CarPackageManager;
@@ -738,11 +740,10 @@
                 mConnectionState = STATE_CONNECTED;
                 mService = newService;
             }
-            if (mServiceConnectionListenerClient != null) {
-                mServiceConnectionListenerClient.onServiceConnected(name, service);
-            }
             if (mStatusChangeCallback != null) {
                 mStatusChangeCallback.onLifecycleChanged(Car.this, true);
+            } else if (mServiceConnectionListenerClient != null) {
+                mServiceConnectionListenerClient.onServiceConnected(name, service);
             }
         }
 
@@ -755,11 +756,13 @@
                 }
                 handleCarDisconnectLocked();
             }
-            if (mServiceConnectionListenerClient != null) {
-                mServiceConnectionListenerClient.onServiceDisconnected(name);
-            }
             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();
             }
         }
     };
@@ -1147,12 +1150,15 @@
     @Nullable
     public Object getCarManager(String serviceName) {
         CarManagerBase manager;
-        ICar service = getICarOrThrow();
         synchronized (mLock) {
+            if (mService == null) {
+                Log.w(TAG_CAR, "getCarManager not working while car service not ready");
+                return null;
+            }
             manager = mServiceMap.get(serviceName);
             if (manager == null) {
                 try {
-                    IBinder binder = service.getCarService(serviceName);
+                    IBinder binder = mService.getCarService(serviceName);
                     if (binder == null) {
                         Log.w(TAG_CAR, "getCarManager could not get binder for service:"
                                 + serviceName);
@@ -1166,7 +1172,7 @@
                     }
                     mServiceMap.put(serviceName, manager);
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
                 }
             }
         }
@@ -1182,90 +1188,145 @@
         return CONNECTION_TYPE_EMBEDDED;
     }
 
+    /** @hide */
+    Context getContext() {
+        return mContext;
+    }
+
+    /** @hide */
+    Handler getEventHandler() {
+        return mEventHandler;
+    }
+
+    /** @hide */
+    <T> T handleRemoteExceptionFromCarService(RemoteException e, T returnValue) {
+        handleRemoteExceptionFromCarService(e);
+        return returnValue;
+    }
+
+    /** @hide */
+    void handleRemoteExceptionFromCarService(RemoteException e) {
+        Log.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()) {
+                Log.w(TAG_CAR, "Car service crashed, client not handling it, finish Activity");
+                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 crashed, client not handling it.");
+    }
+
+    /** @hide */
+    public static <T> T handleRemoteExceptionFromCarService(Service service, RemoteException e,
+            T returnValue) {
+        handleRemoteExceptionFromCarService(service, e);
+        return returnValue;
+    }
+
+    /** @hide */
+    public static  void handleRemoteExceptionFromCarService(Service service, RemoteException e) {
+        Log.w(TAG_CAR,
+                "Car service has crashed, client:" + service.getPackageName() + ","
+                        + service.getClass().getSimpleName(), e);
+        service.stopSelf();
+    }
+
     @Nullable
     private CarManagerBase createCarManager(String serviceName, IBinder binder) {
         CarManagerBase manager = null;
         switch (serviceName) {
             case AUDIO_SERVICE:
-                manager = new CarAudioManager(binder, mContext, mEventHandler);
+                manager = new CarAudioManager(this, binder);
                 break;
             case SENSOR_SERVICE:
-                manager = new CarSensorManager(binder, mContext, mEventHandler);
+                manager = new CarSensorManager(this, binder);
                 break;
             case INFO_SERVICE:
-                manager = new CarInfoManager(binder);
+                manager = new CarInfoManager(this, binder);
                 break;
             case APP_FOCUS_SERVICE:
-                manager = new CarAppFocusManager(binder, mEventHandler);
+                manager = new CarAppFocusManager(this, binder);
                 break;
             case PACKAGE_SERVICE:
-                manager = new CarPackageManager(binder, mContext);
+                manager = new CarPackageManager(this, binder);
                 break;
             case CAR_OCCUPANT_ZONE_SERVICE:
-                manager = new CarOccupantZoneManager(binder, mContext, mEventHandler);
+                manager = new CarOccupantZoneManager(this, binder);
                 break;
             case CAR_NAVIGATION_SERVICE:
-                manager = new CarNavigationStatusManager(binder);
+                manager = new CarNavigationStatusManager(this, binder);
                 break;
             case CABIN_SERVICE:
-                manager = new CarCabinManager(binder, mContext, mEventHandler);
+                manager = new CarCabinManager(this, binder);
                 break;
             case DIAGNOSTIC_SERVICE:
-                manager = new CarDiagnosticManager(binder, mContext, mEventHandler);
+                manager = new CarDiagnosticManager(this, binder);
                 break;
             case HVAC_SERVICE:
-                manager = new CarHvacManager(binder, mContext, mEventHandler);
+                manager = new CarHvacManager(this, binder);
                 break;
             case POWER_SERVICE:
-                manager = new CarPowerManager(binder, mContext, mEventHandler);
+                manager = new CarPowerManager(this, binder);
                 break;
             case PROJECTION_SERVICE:
-                manager = new CarProjectionManager(binder, mEventHandler);
+                manager = new CarProjectionManager(this, binder);
                 break;
             case PROPERTY_SERVICE:
-                manager = new CarPropertyManager(ICarProperty.Stub.asInterface(binder),
-                    mEventHandler);
+                manager = new CarPropertyManager(this, ICarProperty.Stub.asInterface(binder));
                 break;
             case VENDOR_EXTENSION_SERVICE:
-                manager = new CarVendorExtensionManager(binder, mEventHandler);
+                manager = new CarVendorExtensionManager(this, binder);
                 break;
             case CAR_INSTRUMENT_CLUSTER_SERVICE:
-                manager = new CarInstrumentClusterManager(binder, mEventHandler);
+                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 CarTestManagerBinderWrapper(binder);
+                manager = new CarTestManagerBinderWrapper(this, binder);
                 break;
             case VMS_SUBSCRIBER_SERVICE:
-                manager = new VmsSubscriberManager(binder);
+                manager = new VmsSubscriberManager(this, binder);
                 break;
             case BLUETOOTH_SERVICE:
-                manager = new CarBluetoothManager(binder, mContext);
+                manager = new CarBluetoothManager(this, binder);
                 break;
             case STORAGE_MONITORING_SERVICE:
-                manager = new CarStorageMonitoringManager(binder, mEventHandler);
+                manager = new CarStorageMonitoringManager(this, binder);
                 break;
             case CAR_DRIVING_STATE_SERVICE:
-                manager = new CarDrivingStateManager(binder, mContext, mEventHandler);
+                manager = new CarDrivingStateManager(this, binder);
                 break;
             case CAR_UX_RESTRICTION_SERVICE:
-                manager = new CarUxRestrictionsManager(binder, mContext, mEventHandler);
+                manager = new CarUxRestrictionsManager(this, binder);
                 break;
             case CAR_CONFIGURATION_SERVICE:
-                manager = new CarConfigurationManager(binder);
+                manager = new CarConfigurationManager(this, binder);
                 break;
             case CAR_TRUST_AGENT_ENROLLMENT_SERVICE:
-                manager = new CarTrustAgentEnrollmentManager(binder, mContext, mEventHandler);
+                manager = new CarTrustAgentEnrollmentManager(this, binder);
                 break;
             case CAR_MEDIA_SERVICE:
-                manager = new CarMediaManager(binder);
+                manager = new CarMediaManager(this, binder);
                 break;
             case CAR_BUGREPORT_SERVICE:
-                manager = new CarBugreportManager(binder, mContext);
+                manager = new CarBugreportManager(this, binder);
                 break;
             case CAR_USER_SERVICE:
-                manager = new CarUserManager(binder);
+                manager = new CarUserManager(this, binder);
             default:
                 break;
         }
@@ -1297,15 +1358,6 @@
         }
     }
 
-    private ICar getICarOrThrow() throws IllegalStateException {
-        synchronized (mLock) {
-            if (mService == null) {
-                throw new IllegalStateException("not connected");
-            }
-            return mService;
-        }
-    }
-
     private void tearDownCarManagersLocked() {
         // All disconnected handling should be only doing its internal cleanup.
         for (CarManagerBase manager: mServiceMap.values()) {
diff --git a/car-lib/src/android/car/CarAppFocusManager.java b/car-lib/src/android/car/CarAppFocusManager.java
index ff0c25d..b8936af 100644
--- a/car-lib/src/android/car/CarAppFocusManager.java
+++ b/car-lib/src/android/car/CarAppFocusManager.java
@@ -17,7 +17,6 @@
 package android.car;
 
 import android.annotation.IntDef;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -35,7 +34,7 @@
  * should run in the system, and other app setting the flag for the matching app should
  * lead into other app to stop.
  */
-public final class CarAppFocusManager implements CarManagerBase {
+public final class CarAppFocusManager extends CarManagerBase {
     /**
      * Listener to get notification for app getting information on application type status changes.
      */
@@ -114,7 +113,6 @@
     public @interface AppFocusRequestResult {}
 
     private final IAppFocus mService;
-    private final Handler mHandler;
     private final Map<OnAppFocusChangedListener, IAppFocusListenerImpl> mChangeBinders =
             new HashMap<>();
     private final Map<OnAppFocusOwnershipCallback, IAppFocusOwnershipCallbackImpl>
@@ -123,9 +121,9 @@
     /**
      * @hide
      */
-    CarAppFocusManager(IBinder service, Handler handler) {
+    CarAppFocusManager(Car car, IBinder service) {
+        super(car);
         mService = IAppFocus.Stub.asInterface(service);
-        mHandler = handler;
     }
 
     /**
@@ -149,7 +147,7 @@
         try {
             mService.registerFocusListener(binder, appType);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -169,7 +167,8 @@
         try {
             mService.unregisterFocusListener(binder, appType);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
+            // continue for local clean-up
         }
         synchronized (this) {
             binder.removeAppType(appType);
@@ -197,7 +196,7 @@
                 mService.unregisterFocusListener(binder, appType);
             }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -209,7 +208,7 @@
         try {
             return mService.getActiveAppTypes();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, new int[0]);
         }
     }
 
@@ -229,7 +228,7 @@
         try {
             return mService.isOwningFocus(binder, appType);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -261,7 +260,7 @@
         try {
             return mService.requestAppFocus(binder, appType);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, APP_FOCUS_REQUEST_FAILED);
         }
     }
 
@@ -286,7 +285,8 @@
         try {
             mService.abandonAppFocus(binder, appType);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
+            // continue for local clean-up
         }
         synchronized (this) {
             binder.removeAppType(appType);
@@ -314,7 +314,7 @@
                 mService.abandonAppFocus(binder, appType);
             }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -359,11 +359,8 @@
             if (manager == null || listener == null) {
                 return;
             }
-            manager.mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    listener.onAppFocusChanged(appType, active);
-                }
+            manager.getEventHandler().post(() -> {
+                listener.onAppFocusChanged(appType, active);
             });
         }
     }
@@ -403,11 +400,8 @@
             if (manager == null || callback == null) {
                 return;
             }
-            manager.mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    callback.onAppFocusOwnershipLost(appType);
-                }
+            manager.getEventHandler().post(() -> {
+                callback.onAppFocusOwnershipLost(appType);
             });
         }
 
@@ -418,11 +412,8 @@
             if (manager == null || callback == null) {
                 return;
             }
-            manager.mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    callback.onAppFocusOwnershipGranted(appType);
-                }
+            manager.getEventHandler().post(() -> {
+                callback.onAppFocusOwnershipGranted(appType);
             });
         }
     }
diff --git a/car-lib/src/android/car/CarBluetoothManager.java b/car-lib/src/android/car/CarBluetoothManager.java
index c85cec7..c8e46ca 100644
--- a/car-lib/src/android/car/CarBluetoothManager.java
+++ b/car-lib/src/android/car/CarBluetoothManager.java
@@ -17,7 +17,6 @@
 
 import android.Manifest;
 import android.annotation.RequiresPermission;
-import android.content.Context;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -26,9 +25,8 @@
  *
  * @hide
  */
-public final class CarBluetoothManager implements CarManagerBase {
+public final class CarBluetoothManager extends CarManagerBase {
     private static final String TAG = "CarBluetoothManager";
-    private final Context mContext;
     private final ICarBluetooth mService;
 
     /**
@@ -50,7 +48,7 @@
         try {
             mService.connectDevices();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -59,8 +57,8 @@
      *
      * @hide
      */
-    public CarBluetoothManager(IBinder service, Context context) {
-        mContext = context;
+    public CarBluetoothManager(Car car, IBinder service) {
+        super(car);
         mService = ICarBluetooth.Stub.asInterface(service);
     }
 
diff --git a/car-lib/src/android/car/CarBugreportManager.java b/car-lib/src/android/car/CarBugreportManager.java
index f5d3b1d..99f2c7c 100644
--- a/car-lib/src/android/car/CarBugreportManager.java
+++ b/car-lib/src/android/car/CarBugreportManager.java
@@ -20,7 +20,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
-import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -39,10 +38,9 @@
  *
  * @hide
  */
-public final class CarBugreportManager implements CarManagerBase {
+public final class CarBugreportManager extends CarManagerBase {
 
     private final ICarBugreportService mService;
-    private Handler mHandler;
 
     /**
      * Callback from carbugreport manager. Callback methods are always called on the main thread.
@@ -153,9 +151,9 @@
      *
      * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
      */
-    public CarBugreportManager(IBinder service, Context context) {
+    public CarBugreportManager(Car car, IBinder service) {
+        super(car);
         mService = ICarBugreportService.Stub.asInterface(service);
-        mHandler = new Handler(context.getMainLooper());
     }
 
     /**
@@ -185,10 +183,10 @@
         Preconditions.checkNotNull(callback);
         try {
             CarBugreportManagerCallbackWrapper wrapper =
-                    new CarBugreportManagerCallbackWrapper(callback, mHandler);
+                    new CarBugreportManagerCallbackWrapper(callback, getEventHandler());
             mService.requestBugreport(output, extraOutput, wrapper);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         } finally {
             IoUtils.closeQuietly(output);
             IoUtils.closeQuietly(extraOutput);
diff --git a/car-lib/src/android/car/CarInfoManager.java b/car-lib/src/android/car/CarInfoManager.java
index 6a34471..c78523b 100644
--- a/car-lib/src/android/car/CarInfoManager.java
+++ b/car-lib/src/android/car/CarInfoManager.java
@@ -29,7 +29,7 @@
  * Utility to retrieve various static information from car. Each data are grouped as {@link Bundle}
  * and relevant data can be checked from {@link Bundle} using pre-specified keys.
  */
-public final class CarInfoManager implements CarManagerBase{
+public final class CarInfoManager extends CarManagerBase {
 
     private final CarPropertyManager mCarPropertyMgr;
     /**
@@ -261,15 +261,14 @@
     }
 
     /** @hide */
-    public CarInfoManager(IBinder service) {
+    public CarInfoManager(Car car, IBinder service) {
+        super(car);
         ICarProperty mCarPropertyService = ICarProperty.Stub.asInterface(service);
-        mCarPropertyMgr = new CarPropertyManager(mCarPropertyService, null);
+        mCarPropertyMgr = new CarPropertyManager(car, mCarPropertyService);
     }
 
     /** @hide */
     public void onCarDisconnected() {
         mCarPropertyMgr.onCarDisconnected();
     }
-
-
 }
diff --git a/car-lib/src/android/car/CarManagerBase.java b/car-lib/src/android/car/CarManagerBase.java
index 737f356..8d30fdf 100644
--- a/car-lib/src/android/car/CarManagerBase.java
+++ b/car-lib/src/android/car/CarManagerBase.java
@@ -16,10 +16,44 @@
 
 package android.car;
 
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+
 /**
- * Common interface for Car*Manager
+ * Common base class for Car*Manager
  * @hide
  */
-public interface CarManagerBase {
-    void onCarDisconnected();
+public abstract class CarManagerBase {
+
+    protected final Car mCar;
+
+    public CarManagerBase(Car car) {
+        mCar = car;
+    }
+
+    protected Context getContext() {
+        return mCar.getContext();
+    }
+
+    protected Handler getEventHandler() {
+        return mCar.getEventHandler();
+    }
+
+    protected <T> T handleRemoteExceptionFromCarService(RemoteException e, T returnValue) {
+        return mCar.handleRemoteExceptionFromCarService(e, returnValue);
+    }
+
+    protected void handleRemoteExceptionFromCarService(RemoteException e) {
+        mCar.handleRemoteExceptionFromCarService(e);
+    }
+
+    /**
+     * Handle disconnection of car service (=crash). As car service has crashed already, this call
+     * should only clean up any listeners / callbacks passed from client. Clearing object passed
+     * to car service is not necessary as car service has crashed. Note that Car*Manager will not
+     * work any more as all binders are invalid. Client should re-create all Car*Managers when
+     * car service is restarted.
+     */
+    protected abstract void onCarDisconnected();
 }
diff --git a/car-lib/src/android/car/CarOccupantZoneManager.java b/car-lib/src/android/car/CarOccupantZoneManager.java
index 32cfea0..5865991 100644
--- a/car-lib/src/android/car/CarOccupantZoneManager.java
+++ b/car-lib/src/android/car/CarOccupantZoneManager.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.Context;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.IBinder;
@@ -28,6 +27,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.Display;
 
@@ -40,13 +40,14 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * API to get information on displays and users in the car.
  */
-public class CarOccupantZoneManager implements CarManagerBase {
+public class CarOccupantZoneManager extends CarManagerBase {
 
     private static final String TAG = CarOccupantZoneManager.class.getSimpleName();
 
@@ -261,11 +262,12 @@
 
     /** @hide */
     @VisibleForTesting
-    public CarOccupantZoneManager(IBinder service, Context context, Handler handler) {
+    public CarOccupantZoneManager(Car car, IBinder service) {
+        super(car);
         mService = ICarOccupantZone.Stub.asInterface(service);
         mBinderCallback = new ICarOccupantZoneCallbackImpl(this);
-        mDisplayManager = context.getSystemService(DisplayManager.class);
-        mEventHandler = new EventHandler(handler.getLooper());
+        mDisplayManager = getContext().getSystemService(DisplayManager.class);
+        mEventHandler = new EventHandler(getEventHandler().getLooper());
     }
 
     /**
@@ -277,7 +279,7 @@
         try {
             return Arrays.asList(mService.getAllOccupantZones());
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -303,7 +305,7 @@
             }
             return displays;
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -326,7 +328,7 @@
             }
             return mDisplayManager.getDisplay(displayId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -340,7 +342,7 @@
         try {
             return mService.getDisplayType(display.getDisplayId());
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, DISPLAY_TYPE_UNKNOWN);
         }
     }
 
@@ -353,7 +355,7 @@
         try {
             return mService.getUserForOccupant(occupantZone.zoneId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, UserHandle.USER_NULL);
         }
     }
 
@@ -380,7 +382,7 @@
                 try {
                     mService.registerCallback(mBinderCallback);
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
                 }
             }
         }
diff --git a/car-lib/src/android/car/CarProjectionManager.java b/car-lib/src/android/car/CarProjectionManager.java
index 4c177f7..bc4107f 100644
--- a/car-lib/src/android/car/CarProjectionManager.java
+++ b/car-lib/src/android/car/CarProjectionManager.java
@@ -69,7 +69,7 @@
  * @hide
  */
 @SystemApi
-public final class CarProjectionManager implements CarManagerBase {
+public final class CarProjectionManager extends CarManagerBase {
     private static final String TAG = CarProjectionManager.class.getSimpleName();
 
     private final Binder mToken = new Binder();
@@ -194,7 +194,6 @@
     public static final int PROJECTION_AP_FAILED = 2;
 
     private final ICarProjection mService;
-    private final Handler mHandler;
     private final Executor mHandlerExecutor;
 
     @GuardedBy("mLock")
@@ -241,9 +240,10 @@
     /**
      * @hide
      */
-    public CarProjectionManager(IBinder service, Handler handler) {
+    public CarProjectionManager(Car car, IBinder service) {
+        super(car);
         mService = ICarProjection.Stub.asInterface(service);
-        mHandler = handler;
+        Handler handler = getEventHandler();
         mHandlerExecutor = handler::post;
     }
 
@@ -448,7 +448,8 @@
                 mService.unregisterKeyEventHandler(mBinderHandler);
             }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
+            return;
         }
 
         mHandledEvents = events;
@@ -466,7 +467,7 @@
             try {
                 mService.registerProjectionRunner(serviceIntent);
             } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+                handleRemoteExceptionFromCarService(e);
             }
         }
     }
@@ -483,7 +484,7 @@
             try {
                 mService.unregisterProjectionRunner(serviceIntent);
             } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+                handleRemoteExceptionFromCarService(e);
             }
         }
     }
@@ -507,14 +508,14 @@
     public void startProjectionAccessPoint(@NonNull ProjectionAccessPointCallback callback) {
         Preconditions.checkNotNull(callback, "callback cannot be null");
         synchronized (mLock) {
-            Looper looper = mHandler.getLooper();
+            Looper looper = getEventHandler().getLooper();
             ProjectionAccessPointCallbackProxy proxy =
                     new ProjectionAccessPointCallbackProxy(this, looper, callback);
             try {
                 mService.startProjectionAccessPoint(proxy.getMessenger(), mAccessPointProxyToken);
                 mProjectionAccessPointCallbackProxy = proxy;
             } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+                handleRemoteExceptionFromCarService(e);
             }
         }
     }
@@ -535,7 +536,7 @@
             }
             return channelList;
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -556,7 +557,7 @@
         try {
             mService.stopProjectionAccessPoint(mAccessPointProxyToken);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -575,7 +576,7 @@
         try {
             return mService.requestBluetoothProfileInhibit(device, profile, mToken);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -593,7 +594,7 @@
         try {
             return mService.releaseBluetoothProfileInhibit(device, profile, mToken);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -611,7 +612,7 @@
         try {
             mService.updateProjectionStatus(status, mToken);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -634,12 +635,12 @@
                 try {
                     mService.registerProjectionStatusListener(mCarProjectionStatusListener);
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
                 }
             } else {
                 // Already subscribed to Car Service, immediately notify listener with the current
                 // projection status in the event handler thread.
-                mHandler.post(() ->
+                getEventHandler().post(() ->
                         listener.onProjectionStatusChanged(
                                 mCarProjectionStatusListener.mCurrentState,
                                 mCarProjectionStatusListener.mCurrentPackageName,
@@ -671,7 +672,7 @@
             mService.unregisterProjectionStatusListener(mCarProjectionStatusListener);
             mCarProjectionStatusListener = null;
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -695,7 +696,7 @@
         try {
             return mService.getProjectionOptions();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Bundle.EMPTY);
         }
     }
 
@@ -838,7 +839,7 @@
                 List<ProjectionStatus> details) {
             CarProjectionManager mgr = mManagerRef.get();
             if (mgr != null) {
-                mgr.mHandler.post(() -> {
+                mgr.getEventHandler().post(() -> {
                     mCurrentState = projectionState;
                     mCurrentPackageName = packageName;
                     mDetails = Collections.unmodifiableList(details);
diff --git a/car-lib/src/android/car/CarUserManager.java b/car-lib/src/android/car/CarUserManager.java
index 7453cad..6ea62af 100644
--- a/car-lib/src/android/car/CarUserManager.java
+++ b/car-lib/src/android/car/CarUserManager.java
@@ -27,6 +27,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -35,14 +36,15 @@
  * @hide
  */
 @SystemApi
-public final class CarUserManager implements CarManagerBase {
+public final class CarUserManager extends CarManagerBase {
 
     private static final String TAG = CarUserManager.class.getSimpleName();
     private final ICarUserService mService;
 
     /** @hide */
     @VisibleForTesting
-    public CarUserManager(@NonNull IBinder service) {
+    public CarUserManager(Car car, @NonNull IBinder service) {
+        super(car);
         mService = ICarUserService.Stub.asInterface(service);
     }
 
@@ -63,7 +65,7 @@
         try {
             return mService.createDriver(name, admin);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -84,7 +86,7 @@
         try {
             return mService.createPassenger(name, driverId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -102,7 +104,7 @@
         try {
             return mService.switchDriver(driverId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -120,7 +122,7 @@
         try {
             return mService.getAllDrivers();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -139,7 +141,7 @@
         try {
             return mService.getPassengers(driverId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -159,7 +161,7 @@
         try {
             return mService.startPassenger(passengerId, zoneId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -177,7 +179,7 @@
         try {
             return mService.stopPassenger(passengerId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
diff --git a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
index 54d10e2..2b633a0 100644
--- a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
+++ b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
@@ -17,10 +17,10 @@
 package android.car.cluster;
 
 import android.annotation.SystemApi;
+import android.car.Car;
 import android.car.CarManagerBase;
 import android.content.Intent;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 
 /**
@@ -35,7 +35,7 @@
  */
 @Deprecated
 @SystemApi
-public class CarInstrumentClusterManager implements CarManagerBase {
+public class CarInstrumentClusterManager extends CarManagerBase {
     /**
      * @deprecated use {@link android.car.Car#CATEGORY_NAVIGATION} instead
      *
@@ -101,7 +101,8 @@
     }
 
     /** @hide */
-    public CarInstrumentClusterManager(IBinder service, Handler handler) {
+    public CarInstrumentClusterManager(Car car, IBinder service) {
+        super(car);
         // No-op
     }
 
diff --git a/car-lib/src/android/car/content/pm/CarAppBlockingPolicyService.java b/car-lib/src/android/car/content/pm/CarAppBlockingPolicyService.java
index 5b0a6bd..f95063a 100644
--- a/car-lib/src/android/car/content/pm/CarAppBlockingPolicyService.java
+++ b/car-lib/src/android/car/content/pm/CarAppBlockingPolicyService.java
@@ -17,6 +17,7 @@
 
 import android.annotation.SystemApi;
 import android.app.Service;
+import android.car.Car;
 import android.content.Intent;
 import android.os.Handler;
 import android.os.IBinder;
@@ -76,7 +77,7 @@
             try {
                 setter.setAppBlockingPolicy(policy);
             } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+                Car.handleRemoteExceptionFromCarService(CarAppBlockingPolicyService.this, e);
             }
         }
     }
diff --git a/car-lib/src/android/car/content/pm/CarPackageManager.java b/car-lib/src/android/car/content/pm/CarPackageManager.java
index d23633d..7498c65 100644
--- a/car-lib/src/android/car/content/pm/CarPackageManager.java
+++ b/car-lib/src/android/car/content/pm/CarPackageManager.java
@@ -19,9 +19,9 @@
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.car.Car;
 import android.car.CarManagerBase;
 import android.content.ComponentName;
-import android.content.Context;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -32,7 +32,7 @@
 /**
  * Provides car specific API related with package management.
  */
-public final class CarPackageManager implements CarManagerBase {
+public final class CarPackageManager extends CarManagerBase {
     private static final String TAG = "CarPackageManager";
 
     /**
@@ -70,12 +70,11 @@
     public @interface SetPolicyFlags {}
 
     private final ICarPackageManager mService;
-    private final Context mContext;
 
     /** @hide */
-    public CarPackageManager(IBinder service, Context context) {
+    public CarPackageManager(Car car, IBinder service) {
+        super(car);
         mService = ICarPackageManager.Stub.asInterface(service);
-        mContext = context;
     }
 
     /** @hide */
@@ -115,7 +114,7 @@
         try {
             mService.setAppBlockingPolicy(packageName, policy, flags);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -128,7 +127,7 @@
         try {
             mService.restartTask(taskId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -151,7 +150,7 @@
         try {
             return mService.isActivityBackedBySafeActivity(activityName);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -165,7 +164,7 @@
         try {
             mService.setEnableActivityBlocking(enable);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -181,7 +180,7 @@
         try {
             return mService.isActivityDistractionOptimized(packageName, className);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -197,7 +196,7 @@
         try {
             return mService.isServiceDistractionOptimized(packageName, className);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 }
diff --git a/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java b/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java
index 1559dd4..c9c8b6f 100644
--- a/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java
+++ b/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java
@@ -23,8 +23,6 @@
 import android.car.CarLibLog;
 import android.car.CarManagerBase;
 import android.car.diagnostic.ICarDiagnosticEventListener.Stub;
-import android.content.Context;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -47,7 +45,7 @@
  * @hide
  */
 @SystemApi
-public final class CarDiagnosticManager implements CarManagerBase {
+public final class CarDiagnosticManager extends CarManagerBase {
     public static final int FRAME_TYPE_LIVE = 0;
     public static final int FRAME_TYPE_FREEZE = 1;
 
@@ -70,15 +68,16 @@
     /** Handles call back into clients. */
     private final SingleMessageHandler<CarDiagnosticEvent> mHandlerCallback;
 
-    private CarDiagnosticEventListenerToService mListenerToService;
+    private final CarDiagnosticEventListenerToService mListenerToService;
 
     private final CarPermission mVendorExtensionPermission;
 
     /** @hide */
-    public CarDiagnosticManager(IBinder service, Context context, Handler handler) {
+    public CarDiagnosticManager(Car car, IBinder service) {
+        super(car);
         mService = ICarDiagnostic.Stub.asInterface(service);
-        mHandlerCallback = new SingleMessageHandler<CarDiagnosticEvent>(handler.getLooper(),
-            MSG_DIAGNOSTIC_EVENTS) {
+        mHandlerCallback = new SingleMessageHandler<CarDiagnosticEvent>(
+                getEventHandler().getLooper(), MSG_DIAGNOSTIC_EVENTS) {
             @Override
             protected void handleEvent(CarDiagnosticEvent event) {
                 CarDiagnosticListeners listeners;
@@ -90,7 +89,9 @@
                 }
             }
         };
-        mVendorExtensionPermission = new CarPermission(context, Car.PERMISSION_VENDOR_EXTENSION);
+        mVendorExtensionPermission = new CarPermission(getContext(),
+                Car.PERMISSION_VENDOR_EXTENSION);
+        mListenerToService = new CarDiagnosticEventListenerToService(this);
     }
 
     @Override
@@ -98,7 +99,6 @@
     public void onCarDisconnected() {
         synchronized(mActiveListeners) {
             mActiveListeners.clear();
-            mListenerToService = null;
         }
     }
 
@@ -137,9 +137,6 @@
             OnDiagnosticEventListener listener, @FrameType int frameType, int rate) {
         assertFrameType(frameType);
         synchronized(mActiveListeners) {
-            if (null == mListenerToService) {
-                mListenerToService = new CarDiagnosticEventListenerToService(this);
-            }
             boolean needsServerUpdate = false;
             CarDiagnosticListeners listeners = mActiveListeners.get(frameType);
             if (listeners == null) {
@@ -184,7 +181,8 @@
                     mService.unregisterDiagnosticListener(frameType,
                         mListenerToService);
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
+                    // continue for local clean-up
                 }
                 mActiveListeners.remove(frameType);
             } else if (needsServerUpdate) {
@@ -197,7 +195,7 @@
         try {
             return mService.registerOrUpdateDiagnosticListener(frameType, rate, mListenerToService);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -212,7 +210,7 @@
         try {
             return mService.getLatestLiveFrame();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -229,7 +227,7 @@
         try {
             return mService.getFreezeFrameTimestamps();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, new long[0]);
         }
     }
 
@@ -246,7 +244,7 @@
         try {
             return mService.getFreezeFrame(timestamp);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -264,7 +262,7 @@
         try {
             return mService.clearFreezeFrames(timestamps);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -276,7 +274,7 @@
         try {
             return mService.isLiveFrameSupported();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -288,7 +286,7 @@
         try {
             return mService.isFreezeFrameNotificationSupported();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -300,7 +298,7 @@
         try {
             return mService.isGetFreezeFrameSupported();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -318,7 +316,7 @@
         try {
             return mService.isClearFreezeFramesSupported();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -336,7 +334,7 @@
         try {
             return mService.isSelectiveClearFreezeFramesSupported();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
diff --git a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
index 9b0626f..4053c5c 100644
--- a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
+++ b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
@@ -22,7 +22,6 @@
 import android.annotation.TestApi;
 import android.car.Car;
 import android.car.CarManagerBase;
-import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -40,13 +39,12 @@
  */
 @SystemApi
 @TestApi
-public final class CarDrivingStateManager implements CarManagerBase {
+public final class CarDrivingStateManager extends CarManagerBase {
     private static final String TAG = "CarDrivingStateMgr";
     private static final boolean DBG = false;
     private static final boolean VDBG = false;
     private static final int MSG_HANDLE_DRIVING_STATE_CHANGE = 0;
 
-    private final Context mContext;
     private final ICarDrivingState mDrivingService;
     private final EventCallbackHandler mEventCallbackHandler;
     private CarDrivingStateEventListener mDrvStateEventListener;
@@ -54,10 +52,10 @@
 
 
     /** @hide */
-    public CarDrivingStateManager(IBinder service, Context context, Handler handler) {
-        mContext = context;
+    public CarDrivingStateManager(Car car, IBinder service) {
+        super(car);
         mDrivingService = ICarDrivingState.Stub.asInterface(service);
-        mEventCallbackHandler = new EventCallbackHandler(this, handler.getLooper());
+        mEventCallbackHandler = new EventCallbackHandler(this, getEventHandler().getLooper());
     }
 
     /** @hide */
@@ -111,7 +109,7 @@
             // register to the Service for getting notified
             mDrivingService.registerDrivingStateChangeListener(mListenerToService);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -134,7 +132,7 @@
             mDrvStateEventListener = null;
             mListenerToService = null;
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -151,7 +149,7 @@
         try {
             return mDrivingService.getCurrentDrivingState();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -172,7 +170,7 @@
         try {
             mDrivingService.injectDrivingState(event);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
index 9a3d5cf..be194b8 100644
--- a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
@@ -22,7 +22,6 @@
 import android.annotation.RequiresPermission;
 import android.car.Car;
 import android.car.CarManagerBase;
-import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -43,7 +42,7 @@
  * API to register and get the User Experience restrictions imposed based on the car's driving
  * state.
  */
-public final class CarUxRestrictionsManager implements CarManagerBase {
+public final class CarUxRestrictionsManager extends CarManagerBase {
     private static final String TAG = "CarUxRManager";
     private static final boolean DBG = false;
     private static final boolean VDBG = false;
@@ -80,7 +79,6 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface UxRestrictionMode {}
 
-    private final Context mContext;
     private int mDisplayId = Display.INVALID_DISPLAY;
     private final ICarUxRestrictionsManager mUxRService;
     private final EventCallbackHandler mEventCallbackHandler;
@@ -89,10 +87,11 @@
     private CarUxRestrictionsChangeListenerToService mListenerToService;
 
     /** @hide */
-    public CarUxRestrictionsManager(IBinder service, Context context, Handler handler) {
-        mContext = context;
+    public CarUxRestrictionsManager(Car car, IBinder service) {
+        super(car);
         mUxRService = ICarUxRestrictionsManager.Stub.asInterface(service);
-        mEventCallbackHandler = new EventCallbackHandler(this, handler.getLooper());
+        mEventCallbackHandler = new EventCallbackHandler(this,
+                getEventHandler().getLooper());
     }
 
     /** @hide */
@@ -152,7 +151,7 @@
             // register to the Service to listen for changes.
             mUxRService.registerUxRestrictionsChangeListener(mListenerToService, displayId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -172,7 +171,7 @@
         try {
             mUxRService.unregisterUxRestrictionsChangeListener(mListenerToService);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -197,7 +196,7 @@
         try {
             return mUxRService.saveUxRestrictionsConfigurationForNextBoot(configs);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -219,7 +218,7 @@
         try {
             return mUxRService.getCurrentUxRestrictions(displayId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -233,7 +232,7 @@
         try {
             return mUxRService.setRestrictionMode(mode);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -248,7 +247,7 @@
         try {
             return mUxRService.getRestrictionMode();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -288,7 +287,7 @@
         try {
             return mUxRService.getStagedConfigs();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -304,7 +303,7 @@
         try {
             return mUxRService.getConfigs();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -399,7 +398,7 @@
             return mDisplayId;
         }
 
-        mDisplayId = mContext.getDisplayId();
+        mDisplayId = getContext().getDisplayId();
         Log.i(TAG, "Context returns display ID " + mDisplayId);
 
         if (mDisplayId == Display.INVALID_DISPLAY) {
diff --git a/car-lib/src/android/car/hardware/CarSensorManager.java b/car-lib/src/android/car/hardware/CarSensorManager.java
index d61cb2e..082c8eb 100644
--- a/car-lib/src/android/car/hardware/CarSensorManager.java
+++ b/car-lib/src/android/car/hardware/CarSensorManager.java
@@ -26,9 +26,7 @@
 import android.car.hardware.property.CarPropertyManager;
 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
 import android.car.hardware.property.ICarProperty;
-import android.content.Context;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.util.ArraySet;
 import android.util.Log;
@@ -46,7 +44,7 @@
  *  API for monitoring car sensor data.
  */
 @Deprecated
-public final class CarSensorManager implements CarManagerBase {
+public final class CarSensorManager extends CarManagerBase {
     private static final String TAG = "CarSensorManager";
     private final CarPropertyManager mCarPropertyMgr;
     /** @hide */
@@ -304,9 +302,10 @@
 
     }
     /** @hide */
-    public CarSensorManager(IBinder service, Context context, Handler handler) {
+    public CarSensorManager(Car car, IBinder service) {
+        super(car);
         ICarProperty mCarPropertyService = ICarProperty.Stub.asInterface(service);
-        mCarPropertyMgr = new CarPropertyManager(mCarPropertyService, handler);
+        mCarPropertyMgr = new CarPropertyManager(car, mCarPropertyService);
     }
 
     /** @hide */
diff --git a/car-lib/src/android/car/hardware/CarVendorExtensionManager.java b/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
index e7df3b0..b796156 100644
--- a/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
+++ b/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
@@ -22,7 +22,6 @@
 import android.car.hardware.property.CarPropertyManager;
 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
 import android.car.hardware.property.ICarProperty;
-import android.os.Handler;
 import android.os.IBinder;
 import android.util.ArraySet;
 
@@ -44,7 +43,7 @@
  */
 @Deprecated
 @SystemApi
-public final class CarVendorExtensionManager implements CarManagerBase {
+public final class CarVendorExtensionManager extends CarManagerBase {
 
     private final static boolean DBG = false;
     private final static String TAG = CarVendorExtensionManager.class.getSimpleName();
@@ -84,9 +83,10 @@
      * <p>Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
      * @hide
      */
-    public CarVendorExtensionManager(IBinder service, Handler handler) {
+    public CarVendorExtensionManager(Car car, IBinder service) {
+        super(car);
         ICarProperty mCarPropertyService = ICarProperty.Stub.asInterface(service);
-        mPropertyManager = new CarPropertyManager(mCarPropertyService, handler);
+        mPropertyManager = new CarPropertyManager(car, mCarPropertyService);
     }
 
     /**
@@ -206,6 +206,9 @@
     /** @hide */
     @Override
     public void onCarDisconnected() {
+        synchronized (mLock) {
+            mCallbacks.clear();
+        }
         mPropertyManager.onCarDisconnected();
     }
     private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback {
diff --git a/car-lib/src/android/car/hardware/cabin/CarCabinManager.java b/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
index 1c41a2b..7318176 100644
--- a/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
+++ b/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
@@ -25,8 +25,6 @@
 import android.car.hardware.property.CarPropertyManager;
 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
 import android.car.hardware.property.ICarProperty;
-import android.content.Context;
-import android.os.Handler;
 import android.os.IBinder;
 import android.util.ArraySet;
 
@@ -58,7 +56,7 @@
  */
 @Deprecated
 @SystemApi
-public final class CarCabinManager implements CarManagerBase {
+public final class CarCabinManager extends CarManagerBase {
     private final static boolean DBG = false;
     private final static String TAG = "CarCabinManager";
     private final CarPropertyManager mCarPropertyMgr;
@@ -470,9 +468,10 @@
      * @param handler
      * @hide
      */
-    public CarCabinManager(IBinder service, Context context, Handler handler) {
+    public CarCabinManager(Car car, IBinder service) {
+        super(car);
         ICarProperty mCarPropertyService = ICarProperty.Stub.asInterface(service);
-        mCarPropertyMgr = new CarPropertyManager(mCarPropertyService, handler);
+        mCarPropertyMgr = new CarPropertyManager(car, mCarPropertyService);
     }
 
     /**
@@ -594,6 +593,10 @@
     /** @hide */
     @Override
     public void onCarDisconnected() {
+        // TODO(b/142730969) Fix synchronization to use separate mLock
+        synchronized (this) {
+            mCallbacks.clear();
+        }
         mCarPropertyMgr.onCarDisconnected();
     }
 }
diff --git a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
index 3b7c098..f6a2d53 100644
--- a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
+++ b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
@@ -25,8 +25,6 @@
 import android.car.hardware.property.CarPropertyManager;
 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
 import android.car.hardware.property.ICarProperty;
-import android.content.Context;
-import android.os.Handler;
 import android.os.IBinder;
 import android.util.ArraySet;
 import android.util.Log;
@@ -46,7 +44,7 @@
  */
 @Deprecated
 @SystemApi
-public final class CarHvacManager implements CarManagerBase {
+public final class CarHvacManager extends CarManagerBase {
     private final static boolean DBG = false;
     private final static String TAG = "CarHvacManager";
     private final CarPropertyManager mCarPropertyMgr;
@@ -304,14 +302,15 @@
      *
      * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
      * @param service
-     * @param context
-     * @param handler
+     *
      * @hide
      */
-    public CarHvacManager(IBinder service, Context context, Handler handler) {
+    public CarHvacManager(Car car, IBinder service) {
+        super(car);
         ICarProperty mCarPropertyService = ICarProperty.Stub.asInterface(service);
-        mCarPropertyMgr = new CarPropertyManager(mCarPropertyService, handler);
+        mCarPropertyMgr = new CarPropertyManager(car, mCarPropertyService);
     }
+
     /**
      * Implement wrappers for contained CarPropertyManager object
      * @param callback
@@ -435,6 +434,10 @@
 
     /** @hide */
     public void onCarDisconnected() {
+        // TODO(b/142730482) Fix synchronization to use separate mLock
+        synchronized (this) {
+            mCallbacks.clear();
+        }
         mCarPropertyMgr.onCarDisconnected();
     }
 }
diff --git a/car-lib/src/android/car/hardware/power/CarPowerManager.java b/car-lib/src/android/car/hardware/power/CarPowerManager.java
index 3d9a23a..4b0e8cf 100644
--- a/car-lib/src/android/car/hardware/power/CarPowerManager.java
+++ b/car-lib/src/android/car/hardware/power/CarPowerManager.java
@@ -19,8 +19,6 @@
 import android.annotation.SystemApi;
 import android.car.Car;
 import android.car.CarManagerBase;
-import android.content.Context;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -35,15 +33,18 @@
  * @hide
  */
 @SystemApi
-public class CarPowerManager implements CarManagerBase {
+public class CarPowerManager extends CarManagerBase {
     private final static boolean DBG = false;
     private final static String TAG = "CarPowerManager";
 
     private final Object mLock = new Object();
     private final ICarPower mService;
 
+    @GuardedBy("mLock")
     private CarPowerStateListener mListener;
+    @GuardedBy("mLock")
     private CarPowerStateListenerWithCompletion mListenerWithCompletion;
+    @GuardedBy("mLock")
     private CompletableFuture<Void> mFuture;
     @GuardedBy("mLock")
     private ICarPowerStateListener mListenerToService;
@@ -131,7 +132,8 @@
      * @param handler
      * @hide
      */
-    public CarPowerManager(IBinder service, Context context, Handler handler) {
+    public CarPowerManager(Car car, IBinder service) {
+        super(car);
         mService = ICarPower.Stub.asInterface(service);
     }
 
@@ -143,7 +145,7 @@
         try {
             mService.requestShutdownOnNextSuspend();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -155,7 +157,7 @@
         try {
             mService.scheduleNextWakeupTime(seconds);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -209,13 +211,23 @@
                 @Override
                 public void onStateChanged(int state) throws RemoteException {
                     if (useCompletion) {
-                        // Update CompletableFuture. This will recreate it or just clean it up.
-                        updateFuture(state);
+                        CarPowerStateListenerWithCompletion listenerWithCompletion;
+                        CompletableFuture<Void> future;
+                        synchronized (mLock) {
+                            // Update CompletableFuture. This will recreate it or just clean it up.
+                            updateFutureLocked(state);
+                            listenerWithCompletion = mListenerWithCompletion;
+                            future = mFuture;
+                        }
                         // Notify user that the state has changed and supply a future
-                        mListenerWithCompletion.onStateChanged(state, mFuture);
+                        listenerWithCompletion.onStateChanged(state, future);
                     } else {
+                        CarPowerStateListener listener;
+                        synchronized (mLock) {
+                            listener = mListener;
+                        }
                         // Notify the user without supplying a future
-                        mListener.onStateChanged(state);
+                        listener.onStateChanged(state);
                     }
                 }
             };
@@ -227,7 +239,7 @@
                 }
                 mListenerToService = listenerToService;
             } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+                handleRemoteExceptionFromCarService(e);
             }
         }
     }
@@ -243,7 +255,7 @@
             mListenerToService = null;
             mListener = null;
             mListenerWithCompletion = null;
-            cleanupFuture();
+            cleanupFutureLocked();
         }
 
         if (listenerToService == null) {
@@ -254,12 +266,12 @@
         try {
             mService.unregisterListener(listenerToService);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
-    private void updateFuture(int state) {
-        cleanupFuture();
+    private void updateFutureLocked(int state) {
+        cleanupFutureLocked();
         if (state == CarPowerStateListener.SHUTDOWN_PREPARE) {
             // Create a CompletableFuture and pass it to the listener.
             // When the listener completes the future, tell
@@ -269,16 +281,20 @@
                 if (exception != null && !(exception instanceof CancellationException)) {
                     Log.e(TAG, "Exception occurred while waiting for future", exception);
                 }
+                ICarPowerStateListener listenerToService;
+                synchronized (mLock) {
+                    listenerToService = mListenerToService;
+                }
                 try {
-                    mService.finished(mListenerToService);
+                    mService.finished(listenerToService);
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
                 }
             });
         }
     }
 
-    private void cleanupFuture() {
+    private void cleanupFutureLocked() {
         if (mFuture != null) {
             if (!mFuture.isDone()) {
                 mFuture.cancel(false);
@@ -290,13 +306,9 @@
     /** @hide */
     @Override
     public void onCarDisconnected() {
-        ICarPowerStateListener listenerToService;
         synchronized (mLock) {
-            listenerToService = mListenerToService;
-        }
-
-        if (listenerToService != null) {
-            clearListener();
+            mListener = null;
+            mListenerWithCompletion = null;
         }
     }
 }
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index 3f7da1d..e3651da 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -21,6 +21,7 @@
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.car.Car;
 import android.car.CarManagerBase;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
@@ -44,7 +45,7 @@
  * For details about the individual properties, see the descriptions in
  * hardware/interfaces/automotive/vehicle/types.hal
  */
-public class CarPropertyManager implements CarManagerBase {
+public class CarPropertyManager extends CarManagerBase {
     private static final boolean DBG = false;
     private static final String TAG = "CarPropertyManager";
     private static final int MSG_GENERIC_EVENT = 0;
@@ -93,11 +94,12 @@
      * Get an instance of the CarPropertyManager.
      *
      * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
+     * @param car Car instance
      * @param service ICarProperty instance
-     * @param handler The handler to deal with CarPropertyEvent.
      * @hide
      */
-    public CarPropertyManager(@NonNull ICarProperty service, @Nullable Handler handler) {
+    public CarPropertyManager(Car car, @NonNull ICarProperty service) {
+        super(car);
         mService = service;
         try {
             List<CarPropertyConfig> configs = mService.getPropertyList();
@@ -108,11 +110,12 @@
             Log.e(TAG, "getPropertyList exception ", e);
             throw new RuntimeException(e);
         }
-        if (handler == null) {
+        Handler eventHandler = getEventHandler();
+        if (eventHandler == null) {
             mHandler = null;
             return;
         }
-        mHandler = new SingleMessageHandler<CarPropertyEvent>(handler.getLooper(),
+        mHandler = new SingleMessageHandler<CarPropertyEvent>(eventHandler.getLooper(),
             MSG_GENERIC_EVENT) {
             @Override
             protected void handleEvent(CarPropertyEvent event) {
@@ -206,7 +209,7 @@
         try {
             mService.registerListener(propertyId, rate, mCarPropertyEventToService);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
         return true;
     }
@@ -274,7 +277,8 @@
                 try {
                     mService.unregisterListener(propertyId, mCarPropertyEventToService);
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
+                    // continue for local clean-up
                 }
                 mActivePropertyListener.remove(propertyId);
             } else if (needsServerUpdate) {
@@ -327,7 +331,7 @@
         try {
             return mService.getReadPermission(propId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, "");
         }
     }
 
@@ -346,7 +350,7 @@
         try {
             return mService.getWritePermission(propId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, "");
         }
     }
 
@@ -363,7 +367,7 @@
             return (propValue != null)
                     && (propValue.getStatus() == CarPropertyValue.STATUS_AVAILABLE);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -449,7 +453,7 @@
             }
             return propVal;
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -466,7 +470,7 @@
             CarPropertyValue<E> propVal = mService.getProperty(propId, areaId);
             return propVal;
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -488,7 +492,7 @@
         try {
             mService.setProperty(new CarPropertyValue<>(propId, areaId, val));
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
diff --git a/car-lib/src/android/car/input/CarInputHandlingService.java b/car-lib/src/android/car/input/CarInputHandlingService.java
index 518cee1..0ea990f 100644
--- a/car-lib/src/android/car/input/CarInputHandlingService.java
+++ b/car-lib/src/android/car/input/CarInputHandlingService.java
@@ -19,6 +19,7 @@
 import android.annotation.MainThread;
 import android.annotation.SystemApi;
 import android.app.Service;
+import android.car.Car;
 import android.car.CarLibLog;
 import android.content.Intent;
 import android.os.Bundle;
@@ -101,7 +102,7 @@
         try {
             callbackBinder.transact(INPUT_CALLBACK_BINDER_CODE, dataIn, null, IBinder.FLAG_ONEWAY);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Car.handleRemoteExceptionFromCarService(this, e);
         }
     }
 
diff --git a/car-lib/src/android/car/media/CarAudioManager.java b/car-lib/src/android/car/media/CarAudioManager.java
index dcd4514..2bc8fd7 100644
--- a/car-lib/src/android/car/media/CarAudioManager.java
+++ b/car-lib/src/android/car/media/CarAudioManager.java
@@ -22,10 +22,8 @@
 import android.car.Car;
 import android.car.CarLibLog;
 import android.car.CarManagerBase;
-import android.content.Context;
 import android.media.AudioAttributes;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -52,7 +50,7 @@
  * - There is exactly one audio zone, which is the primary zone
  * - Each volume group represents a controllable STREAM_TYPE, same as AudioManager
  */
-public final class CarAudioManager implements CarManagerBase {
+public final class CarAudioManager extends CarManagerBase {
 
     /**
      * Zone id of the primary audio zone.
@@ -114,7 +112,7 @@
         try {
             return mService.isDynamicRoutingEnabled();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -147,7 +145,7 @@
         try {
             mService.setGroupVolume(zoneId, groupId, index, flags);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -177,7 +175,7 @@
         try {
             return mService.getGroupMaxVolume(zoneId, groupId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, 0);
         }
     }
 
@@ -207,7 +205,7 @@
         try {
             return mService.getGroupMinVolume(zoneId, groupId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, 0);
         }
     }
 
@@ -240,7 +238,7 @@
         try {
             return mService.getGroupVolume(zoneId, groupId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, 0);
         }
     }
 
@@ -259,7 +257,7 @@
         try {
             mService.setFadeTowardFront(value);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -278,7 +276,7 @@
         try {
             mService.setBalanceTowardRight(value);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -300,7 +298,8 @@
         try {
             return mService.getExternalSources();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
+            return new String[0];
         }
     }
 
@@ -330,7 +329,7 @@
         try {
             return mService.createAudioPatch(sourceAddress, usage, gainInMillibels);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -350,7 +349,7 @@
         try {
             mService.releaseAudioPatch(patch);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -379,7 +378,7 @@
         try {
             return mService.getVolumeGroupCount(zoneId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, 0);
         }
     }
 
@@ -409,7 +408,7 @@
         try {
             return mService.getVolumeGroupIdForUsage(zoneId, usage);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, 0);
         }
     }
 
@@ -436,7 +435,7 @@
         try {
             return mService.getAudioZoneIds();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, new int[0]);
         }
     }
 
@@ -453,7 +452,7 @@
         try {
             return mService.getZoneIdForUid(uid);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, 0);
         }
     }
 
@@ -470,7 +469,7 @@
         try {
             return mService.setZoneIdForUid(zoneId, uid);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -486,7 +485,7 @@
         try {
             return mService.clearZoneIdForUid(uid);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -523,7 +522,7 @@
         try {
             return mService.getZoneIdForDisplayPortId(displayPortId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, 0);
         }
     }
 
@@ -541,7 +540,7 @@
         try {
             return mService.getUsagesForVolumeGroupId(zoneId, groupId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, new int[0]);
         }
     }
 
@@ -552,16 +551,16 @@
             try {
                 mService.unregisterVolumeCallback(mCarVolumeCallbackImpl.asBinder());
             } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+                handleRemoteExceptionFromCarService(e);
             }
         }
     }
 
     /** @hide */
-    public CarAudioManager(IBinder service, Context context, Handler handler) {
+    public CarAudioManager(Car car, IBinder service) {
+        super(car);
         mService = ICarAudio.Stub.asInterface(service);
         mCarVolumeCallbacks = new ArrayList<>();
-
         try {
             mService.registerVolumeCallback(mCarVolumeCallbackImpl.asBinder());
         } catch (RemoteException e) {
diff --git a/car-lib/src/android/car/media/CarMediaManager.java b/car-lib/src/android/car/media/CarMediaManager.java
index 12c2dc8..8537ed6 100644
--- a/car-lib/src/android/car/media/CarMediaManager.java
+++ b/car-lib/src/android/car/media/CarMediaManager.java
@@ -29,7 +29,7 @@
  * API for updating and receiving updates to the primary media source in the car.
  * @hide
  */
-public final class CarMediaManager implements CarManagerBase {
+public final class CarMediaManager extends CarManagerBase {
 
     private final ICarMedia mService;
     private Map<MediaSourceChangedListener, ICarMediaSourceListener> mCallbackMap = new HashMap();
@@ -40,7 +40,8 @@
      * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
      * @hide
      */
-    public CarMediaManager(IBinder service) {
+    public CarMediaManager(Car car, IBinder service) {
+        super(car);
         mService = ICarMedia.Stub.asInterface(service);
     }
 
@@ -67,7 +68,7 @@
         try {
             return mService.getMediaSource();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -81,7 +82,7 @@
         try {
             mService.setMediaSource(componentName);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -102,7 +103,7 @@
             mCallbackMap.put(callback, binderCallback);
             mService.registerMediaSourceListener(binderCallback);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -117,12 +118,14 @@
             ICarMediaSourceListener binderCallback = mCallbackMap.remove(callback);
             mService.unregisterMediaSourceListener(binderCallback);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
     /** @hide */
     @Override
     public synchronized void onCarDisconnected() {
+        // TODO(b/142733057) Fix synchronization to use separate mLock
+        mCallbackMap.clear();
     }
 }
diff --git a/car-lib/src/android/car/navigation/CarNavigationStatusManager.java b/car-lib/src/android/car/navigation/CarNavigationStatusManager.java
index a70e3c8..2aa2f10 100644
--- a/car-lib/src/android/car/navigation/CarNavigationStatusManager.java
+++ b/car-lib/src/android/car/navigation/CarNavigationStatusManager.java
@@ -24,14 +24,13 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.util.Log;
 
 /**
  * API for providing navigation status for instrument cluster.
  * @hide
  */
 @SystemApi
-public final class CarNavigationStatusManager implements CarManagerBase {
+public final class CarNavigationStatusManager extends CarManagerBase {
     private static final String TAG = CarLibLog.TAG_NAV;
 
     private final IInstrumentClusterNavigation mService;
@@ -40,7 +39,8 @@
      * Only for CarServiceLoader
      * @hide
      */
-    public CarNavigationStatusManager(IBinder service) {
+    public CarNavigationStatusManager(Car car, IBinder service) {
+        super(car);
         mService = IInstrumentClusterNavigation.Stub.asInterface(service);
     }
 
@@ -67,14 +67,13 @@
         try {
             mService.onNavigationStateChanged(bundle);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
     /** @hide */
     @Override
     public void onCarDisconnected() {
-        Log.e(TAG, "Car service disconnected");
     }
 
     /** Returns navigation features of instrument cluster */
@@ -83,7 +82,7 @@
         try {
             return mService.getInstrumentClusterInfo();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 }
diff --git a/car-lib/src/android/car/settings/CarConfigurationManager.java b/car-lib/src/android/car/settings/CarConfigurationManager.java
index 34d5f4a..626ad39 100644
--- a/car-lib/src/android/car/settings/CarConfigurationManager.java
+++ b/car-lib/src/android/car/settings/CarConfigurationManager.java
@@ -16,6 +16,7 @@
 
 package android.car.settings;
 
+import android.car.Car;
 import android.car.CarManagerBase;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -23,13 +24,14 @@
 /**
  * Manager that exposes car configuration values that are stored on the system.
  */
-public class CarConfigurationManager implements CarManagerBase {
+public class CarConfigurationManager extends CarManagerBase {
     private static final String TAG = "CarConfigurationManager";
 
     private final ICarConfigurationManager mConfigurationService;
 
     /** @hide */
-    public CarConfigurationManager(IBinder service) {
+    public CarConfigurationManager(Car car, IBinder service) {
+        super(car);
         mConfigurationService = ICarConfigurationManager.Stub.asInterface(service);
     }
 
@@ -42,7 +44,7 @@
         try {
             return mConfigurationService.getSpeedBumpConfiguration();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
diff --git a/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java b/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java
index ff7b099..69c092b 100644
--- a/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java
+++ b/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java
@@ -19,7 +19,6 @@
 import android.annotation.SystemApi;
 import android.car.Car;
 import android.car.CarManagerBase;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -37,7 +36,7 @@
  * @hide
  */
 @SystemApi
-public final class CarStorageMonitoringManager implements CarManagerBase {
+public final class CarStorageMonitoringManager extends CarManagerBase {
     private static final String TAG = CarStorageMonitoringManager.class.getSimpleName();
     private static final int MSG_IO_STATS_EVENT = 0;
 
@@ -77,9 +76,10 @@
     /**
      * @hide
      */
-    public CarStorageMonitoringManager(IBinder service, Handler handler) {
+    public CarStorageMonitoringManager(Car car, IBinder service) {
+        super(car);
         mService = ICarStorageMonitoring.Stub.asInterface(service);
-        mMessageHandler = new SingleMessageHandler<IoStats>(handler, MSG_IO_STATS_EVENT) {
+        mMessageHandler = new SingleMessageHandler<IoStats>(getEventHandler(), MSG_IO_STATS_EVENT) {
             @Override
             protected void handleEvent(IoStats event) {
                 for (IoStatsListener listener : mListeners) {
@@ -112,7 +112,7 @@
         try {
             return mService.getPreEolIndicatorStatus();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, PRE_EOL_INFO_UNKNOWN);
         }
     }
 
@@ -130,7 +130,7 @@
         try {
             return mService.getWearEstimate();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -150,7 +150,7 @@
         try {
             return mService.getWearEstimateHistory();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -169,7 +169,7 @@
         try {
             return mService.getBootIoStats();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -199,7 +199,7 @@
         try {
             return mService.getShutdownDiskWriteAmount();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, 0);
         }
     }
 
@@ -216,7 +216,7 @@
         try {
             return mService.getAggregateIoStats();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -236,7 +236,7 @@
         try {
             return mService.getIoStatsDeltas();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -259,7 +259,7 @@
             }
             mListeners.add(listener);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -277,7 +277,7 @@
                 mListenerToService = null;
             }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 }
diff --git a/car-lib/src/android/car/test/CarTestManagerBinderWrapper.java b/car-lib/src/android/car/test/CarTestManagerBinderWrapper.java
index 5e39ea3..0a167cf 100644
--- a/car-lib/src/android/car/test/CarTestManagerBinderWrapper.java
+++ b/car-lib/src/android/car/test/CarTestManagerBinderWrapper.java
@@ -15,6 +15,7 @@
  */
 package android.car.test;
 
+import android.car.Car;
 import android.car.CarManagerBase;
 import android.os.IBinder;
 
@@ -22,10 +23,17 @@
  * Only for system testing
  * @hide
  */
-public class CarTestManagerBinderWrapper implements CarManagerBase {
+public class CarTestManagerBinderWrapper extends CarManagerBase {
     public final IBinder binder;
 
     public CarTestManagerBinderWrapper(IBinder binder) {
+        super(null); // This will not work safely but is only for keeping API.
+        this.binder = binder;
+    }
+
+    /** @hide */
+    public CarTestManagerBinderWrapper(Car car, IBinder binder) {
+        super(car);
         this.binder = binder;
     }
 
diff --git a/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
index c82d515..9881420 100644
--- a/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
+++ b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
@@ -24,8 +24,8 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.bluetooth.BluetoothDevice;
+import android.car.Car;
 import android.car.CarManagerBase;
-import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -39,6 +39,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.Collections;
 import java.util.List;
 
 
@@ -67,7 +68,7 @@
  * @hide
  */
 @SystemApi
-public final class CarTrustAgentEnrollmentManager implements CarManagerBase {
+public final class CarTrustAgentEnrollmentManager extends CarManagerBase {
     private static final String TAG = "CarTrustEnrollMgr";
     private static final String KEY_HANDLE = "handle";
     private static final String KEY_ACTIVE = "active";
@@ -81,7 +82,6 @@
     private static final int MSG_ENROLL_TOKEN_STATE_CHANGED = 7;
     private static final int MSG_ENROLL_TOKEN_REMOVED = 8;
 
-    private final Context mContext;
     private final ICarTrustAgentEnrollment mEnrollmentService;
     private Object mListenerLock = new Object();
     @GuardedBy("mListenerLock")
@@ -114,10 +114,10 @@
 
 
     /** @hide */
-    public CarTrustAgentEnrollmentManager(IBinder service, Context context, Handler handler) {
-        mContext = context;
+    public CarTrustAgentEnrollmentManager(Car car, IBinder service) {
+        super(car);
         mEnrollmentService = ICarTrustAgentEnrollment.Stub.asInterface(service);
-        mEventCallbackHandler = new EventCallbackHandler(this, handler.getLooper());
+        mEventCallbackHandler = new EventCallbackHandler(this, getEventHandler().getLooper());
     }
 
     /** @hide */
@@ -134,7 +134,7 @@
         try {
             mEnrollmentService.startEnrollmentAdvertising();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -146,7 +146,7 @@
         try {
             mEnrollmentService.stopEnrollmentAdvertising();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -161,7 +161,7 @@
         try {
             mEnrollmentService.enrollmentHandshakeAccepted(device);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -173,7 +173,7 @@
         try {
             mEnrollmentService.terminateEnrollmentHandshake();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -194,7 +194,7 @@
         try {
             return mEnrollmentService.isEscrowTokenActive(handle, uid);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, false);
         }
     }
 
@@ -209,7 +209,7 @@
         try {
             mEnrollmentService.removeEscrowToken(handle, uid);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -223,7 +223,7 @@
         try {
             mEnrollmentService.removeAllTrustedDevices(uid);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -238,7 +238,7 @@
         try {
             mEnrollmentService.setTrustedDeviceEnrollmentEnabled(isEnabled);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -253,7 +253,7 @@
         try {
             mEnrollmentService.setTrustedDeviceUnlockEnabled(isEnabled);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -278,7 +278,7 @@
                     mEnrollmentService.registerEnrollmentCallback(mListenerToEnrollmentService);
                     mEnrollmentCallback = callback;
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
                 }
             }
         }
@@ -290,7 +290,7 @@
                 try {
                     mEnrollmentService.unregisterEnrollmentCallback(mListenerToEnrollmentService);
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
                 }
                 mEnrollmentCallback = null;
             }
@@ -318,7 +318,7 @@
                     mEnrollmentService.registerBleCallback(mListenerToBleService);
                     mBleCallback = callback;
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
                 }
             }
         }
@@ -330,7 +330,7 @@
                 try {
                     mEnrollmentService.unregisterBleCallback(mListenerToBleService);
                 } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
+                    handleRemoteExceptionFromCarService(e);
                 }
                 mBleCallback = null;
             }
@@ -351,7 +351,7 @@
         try {
             return mEnrollmentService.getEnrolledDeviceInfosForUser(uid);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
diff --git a/car-lib/src/android/car/vms/VmsPublisherClientService.java b/car-lib/src/android/car/vms/VmsPublisherClientService.java
index 309d0ee..ea75707 100644
--- a/car-lib/src/android/car/vms/VmsPublisherClientService.java
+++ b/car-lib/src/android/car/vms/VmsPublisherClientService.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.app.Service;
+import android.car.Car;
 import android.content.Intent;
 import android.os.Binder;
 import android.os.Build;
@@ -114,7 +115,7 @@
         try {
             mVmsPublisherService.publish(token, layer, publisherId, payload);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Car.handleRemoteExceptionFromCarService(this, e);
         }
     }
 
@@ -134,7 +135,7 @@
             mVmsPublisherService.setLayersOffering(token, offering);
             VmsOperationRecorder.get().setLayersOffering(offering);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Car.handleRemoteExceptionFromCarService(this, e);
         }
     }
 
@@ -172,6 +173,7 @@
             publisherId = mVmsPublisherService.getPublisherId(publisherInfo);
             Log.i(TAG, "Assigned publisher ID: " + publisherId);
         } catch (RemoteException e) {
+            // This will crash. To prevent crash, safer invalid return value should be defined.
             throw e.rethrowFromSystemServer();
         }
         VmsOperationRecorder.get().getPublisherId(publisherId);
@@ -191,7 +193,7 @@
         try {
             return mVmsPublisherService.getSubscriptions();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return Car.handleRemoteExceptionFromCarService(this, e, null);
         }
     }
 
diff --git a/car-lib/src/android/car/vms/VmsSubscriberManager.java b/car-lib/src/android/car/vms/VmsSubscriberManager.java
index c02d3a5..edde982 100644
--- a/car-lib/src/android/car/vms/VmsSubscriberManager.java
+++ b/car-lib/src/android/car/vms/VmsSubscriberManager.java
@@ -19,6 +19,7 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.car.Car;
 import android.car.CarManagerBase;
 import android.os.Binder;
 import android.os.IBinder;
@@ -39,7 +40,7 @@
  * @hide
  */
 @SystemApi
-public final class VmsSubscriberManager implements CarManagerBase {
+public final class VmsSubscriberManager extends CarManagerBase {
     private static final String TAG = "VmsSubscriberManager";
 
     private final IVmsSubscriberService mVmsSubscriberService;
@@ -75,7 +76,8 @@
      *
      * @hide
      */
-    public VmsSubscriberManager(IBinder service) {
+    public VmsSubscriberManager(Car car, IBinder service) {
+        super(car);
         mVmsSubscriberService = IVmsSubscriberService.Stub.asInterface(service);
         mSubscriberManagerClient = new IVmsSubscriberClient.Stub() {
             @Override
@@ -133,7 +135,7 @@
         try {
             mVmsSubscriberService.addVmsSubscriberToNotifications(mSubscriberManagerClient);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -148,7 +150,7 @@
         try {
             mVmsSubscriberService.removeVmsSubscriberToNotifications(mSubscriberManagerClient);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         } finally {
             synchronized (mClientCallbackLock) {
                 mClientCallback = null;
@@ -168,7 +170,7 @@
         try {
             return mVmsSubscriberService.getPublisherInfo(publisherId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -182,7 +184,7 @@
         try {
             return mVmsSubscriberService.getAvailableLayers();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
@@ -199,7 +201,7 @@
             mVmsSubscriberService.addVmsSubscriber(mSubscriberManagerClient, layer);
             VmsOperationRecorder.get().subscribe(layer);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -218,7 +220,7 @@
                     mSubscriberManagerClient, layer, publisherId);
             VmsOperationRecorder.get().subscribe(layer, publisherId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -231,7 +233,7 @@
             mVmsSubscriberService.addVmsSubscriberPassive(mSubscriberManagerClient);
             VmsOperationRecorder.get().startMonitoring();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -248,7 +250,7 @@
             mVmsSubscriberService.removeVmsSubscriber(mSubscriberManagerClient, layer);
             VmsOperationRecorder.get().unsubscribe(layer);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -266,7 +268,7 @@
                     mSubscriberManagerClient, layer, publisherId);
             VmsOperationRecorder.get().unsubscribe(layer, publisherId);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -278,7 +280,7 @@
             mVmsSubscriberService.removeVmsSubscriberPassive(mSubscriberManagerClient);
             VmsOperationRecorder.get().stopMonitoring();
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -326,5 +328,9 @@
      */
     @Override
     public void onCarDisconnected() {
+        synchronized (mClientCallbackLock) {
+            mClientCallback = null;
+            mExecutor = null;
+        }
     }
 }
diff --git a/car-systemtest-lib/src/android/car/test/CarTestManager.java b/car-systemtest-lib/src/android/car/test/CarTestManager.java
index 52b01a6..3ee1067 100644
--- a/car-systemtest-lib/src/android/car/test/CarTestManager.java
+++ b/car-systemtest-lib/src/android/car/test/CarTestManager.java
@@ -27,18 +27,19 @@
  * @hide
  */
 @SystemApi
-public final class CarTestManager implements CarManagerBase {
+public final class CarTestManager extends CarManagerBase {
 
     private final ICarTest mService;
 
 
-    public CarTestManager(IBinder carServiceBinder) {
+    public CarTestManager(Car car, IBinder carServiceBinder) {
+        super(car);
         mService = ICarTest.Stub.asInterface(carServiceBinder);
     }
 
     @Override
     public void onCarDisconnected() {
-        // should not happen for embedded
+        // test will fail. nothing to do.
     }
 
     /**
@@ -52,7 +53,7 @@
         try {
             mService.stopCarService(token);
         } catch (RemoteException e) {
-            handleRemoteException(e);
+            handleRemoteExceptionFromCarService(e);
         }
     }
 
@@ -66,12 +67,7 @@
         try {
             mService.startCarService(token);
         } catch (RemoteException e) {
-            handleRemoteException(e);
+            handleRemoteExceptionFromCarService(e);
         }
     }
-
-    private static void handleRemoteException(RemoteException e) {
-        // let test fail
-        throw new RuntimeException(e);
-    }
 }
diff --git a/service/src/com/android/car/CarLocalServices.java b/service/src/com/android/car/CarLocalServices.java
index 6c756b8..ea1b6f1 100644
--- a/service/src/com/android/car/CarLocalServices.java
+++ b/service/src/com/android/car/CarLocalServices.java
@@ -17,6 +17,7 @@
 package com.android.car;
 
 import android.annotation.Nullable;
+import android.car.Car;
 import android.car.hardware.power.CarPowerManager;
 import android.content.Context;
 import android.util.ArrayMap;
@@ -90,10 +91,12 @@
      */
     @Nullable
     public static CarPowerManager createCarPowerManager(Context context) {
+        // This does not require connection as binder will be passed to CarPowerManager directly.
+        Car car = new Car(context, /* service= */null, /* handler= */ null);
         CarPowerManagementService service = getService(CarPowerManagementService.class);
         if (service == null) {
             return null;
         }
-        return new CarPowerManager(service, context, null);
+        return new CarPowerManager(car, service);
     }
 }
diff --git a/service/src/com/android/car/CarOccupantZoneService.java b/service/src/com/android/car/CarOccupantZoneService.java
index b2876f5..727d6b3 100644
--- a/service/src/com/android/car/CarOccupantZoneService.java
+++ b/service/src/com/android/car/CarOccupantZoneService.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.car.Car;
 import android.car.CarInfoManager;
 import android.car.CarOccupantZoneManager;
 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
@@ -168,6 +169,9 @@
     private final RemoteCallbackList<ICarOccupantZoneCallback> mClientCallbacks =
             new RemoteCallbackList<>();
 
+    @GuardedBy("mLock")
+    private int mDriverSeat = VehicleAreaSeat.SEAT_UNKNOWN;
+
     public CarOccupantZoneService(Context context) {
         mContext = context;
         mDisplayManager = context.getSystemService(DisplayManager.class);
@@ -181,7 +185,13 @@
 
     @Override
     public void init() {
+        // This does not require connection as binder will be passed directly.
+        Car car = new Car(mContext, /* service= */null, /* handler= */ null);
+        CarInfoManager infoManager = new CarInfoManager(car, CarLocalServices.getService(
+                CarPropertyService.class));
+        int driverSeat = infoManager.getDriverSeat();
         synchronized (mLock) {
+            mDriverSeat = driverSeat;
             parseOccupantZoneConfigsLocked();
             parseDisplayConfigsLocked();
             handleActiveDisplaysLocked();
@@ -351,11 +361,12 @@
         throw new RuntimeException("Format error in config_occupant_zones resource:" + msg);
     }
 
+    // For overriding in test
     @VisibleForTesting
     int getDriverSeat() {
-        CarInfoManager infoManager = new CarInfoManager(CarLocalServices.getService(
-                CarPropertyService.class));
-        return infoManager.getDriverSeat();
+        synchronized (mLock) {
+            return mDriverSeat;
+        }
     }
 
     private void parseOccupantZoneConfigsLocked() {
diff --git a/service/src/com/android/car/CarTestService.java b/service/src/com/android/car/CarTestService.java
index 8c3f64d..776fd53 100644
--- a/service/src/com/android/car/CarTestService.java
+++ b/service/src/com/android/car/CarTestService.java
@@ -22,6 +22,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -39,6 +41,9 @@
     private final Context mContext;
     private final ICarImpl mICarImpl;
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private final Map<IBinder, TokenDeathRecipient> mTokens = new HashMap<>();
 
     CarTestService(Context context, ICarImpl carImpl) {
@@ -69,7 +74,7 @@
         Log.d(TAG, "stopCarService, token: " + token);
         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_TEST_SERVICE);
 
-        synchronized (this) {
+        synchronized (mLock) {
             if (mTokens.containsKey(token)) {
                 Log.w(TAG, "Calling stopCarService twice with the same token.");
                 return;
@@ -80,7 +85,7 @@
             token.linkToDeath(deathRecipient, 0);
 
             if (mTokens.size() == 1) {
-                mICarImpl.release();
+                CarServiceUtils.runOnMainSync(mICarImpl::release);
             }
         }
     }
@@ -92,15 +97,17 @@
         releaseToken(token);
     }
 
-    private synchronized void releaseToken(IBinder token) {
+    private void releaseToken(IBinder token) {
         Log.d(TAG, "releaseToken, token: " + token);
-        DeathRecipient deathRecipient = mTokens.remove(token);
-        if (deathRecipient != null) {
-            token.unlinkToDeath(deathRecipient, 0);
-        }
+        synchronized (mLock) {
+            DeathRecipient deathRecipient = mTokens.remove(token);
+            if (deathRecipient != null) {
+                token.unlinkToDeath(deathRecipient, 0);
+            }
 
-        if (mTokens.size() == 0) {
-            CarServiceUtils.runOnMain(mICarImpl::init);
+            if (mTokens.size() == 0) {
+                CarServiceUtils.runOnMainSync(mICarImpl::init);
+            }
         }
     }
 
diff --git a/service/src/com/android/car/pm/ActivityBlockingActivity.java b/service/src/com/android/car/pm/ActivityBlockingActivity.java
index 9dcb70a..9756523 100644
--- a/service/src/com/android/car/pm/ActivityBlockingActivity.java
+++ b/service/src/com/android/car/pm/ActivityBlockingActivity.java
@@ -79,14 +79,19 @@
         // restrictions are lifted.
         // This Activity should be launched only after car service is initialized. Currently this
         // Activity is only launched from CPMS. So this is safe to do.
-        mCar = Car.createCar(this);
-        mUxRManager = (CarUxRestrictionsManager) mCar.getCarManager(
-                Car.CAR_UX_RESTRICTION_SERVICE);
-        // This activity would have been launched only in a restricted state.
-        // But ensuring when the service connection is established, that we are still
-        // in a restricted state.
-        handleUxRChange(mUxRManager.getCurrentCarUxRestrictions());
-        mUxRManager.registerListener(ActivityBlockingActivity.this::handleUxRChange);
+        mCar = Car.createCar(this, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
+                (car, ready) -> {
+                    if (!ready) {
+                        return;
+                    }
+                    mUxRManager = (CarUxRestrictionsManager) car.getCarManager(
+                            Car.CAR_UX_RESTRICTION_SERVICE);
+                    // This activity would have been launched only in a restricted state.
+                    // But ensuring when the service connection is established, that we are still
+                    // in a restricted state.
+                    handleUxRChange(mUxRManager.getCurrentCarUxRestrictions());
+                    mUxRManager.registerListener(ActivityBlockingActivity.this::handleUxRChange);
+                });
     }
 
     @Override
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
index 482b246..cab9ccf 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
@@ -21,9 +21,7 @@
 import android.car.CarAppFocusManager.OnAppFocusChangedListener;
 import android.car.CarAppFocusManager.OnAppFocusOwnershipCallback;
 import android.car.media.CarAudioManager;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.hardware.display.DisplayManager;
@@ -35,7 +33,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.util.Log;
 import android.util.SparseArray;
@@ -133,41 +130,39 @@
     private void connectCar() {
         mContext = getContext();
         mHandler = new Handler(Looper.getMainLooper());
-        mCar = Car.createCar(mContext, new ServiceConnection() {
-            @Override
-            public void onServiceConnected(ComponentName name, IBinder service) {
-                mAppFocusManager =
-                        (CarAppFocusManager) mCar.getCarManager(Car.APP_FOCUS_SERVICE);
-                OnAppFocusChangedListener listener = new OnAppFocusChangedListener() {
-                    @Override
-                    public void onAppFocusChanged(int appType, boolean active) {
+        mCar = Car.createCar(mContext, /* handler= */ null,
+                Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, (car, ready) -> {
+                    if (!ready) {
+                        return;
                     }
-                };
-                mAppFocusManager.addFocusListener(listener,
-                        CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
-                mAppFocusManager.addFocusListener(listener,
-                        CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+                    mAppFocusManager =
+                            (CarAppFocusManager) mCar.getCarManager(Car.APP_FOCUS_SERVICE);
+                    OnAppFocusChangedListener listener = new OnAppFocusChangedListener() {
+                        @Override
+                        public void onAppFocusChanged(int appType, boolean active) {
+                        }
+                    };
+                    mAppFocusManager.addFocusListener(listener,
+                            CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+                    mAppFocusManager.addFocusListener(listener,
+                            CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
 
-                mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
+                    mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
 
-                //take care of zone selection
-                int[] zoneList = mCarAudioManager.getAudioZoneIds();
-                Integer[] zoneArray = Arrays.stream(zoneList).boxed().toArray(Integer[]::new);
-                mZoneAdapter = new ArrayAdapter<>(mContext,
-                        android.R.layout.simple_spinner_item, zoneArray);
-                mZoneAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-                mZoneSpinner.setAdapter(mZoneAdapter);
-                mZoneSpinner.setEnabled(true);
+                    //take care of zone selection
+                    int[] zoneList = mCarAudioManager.getAudioZoneIds();
+                    Integer[] zoneArray = Arrays.stream(zoneList).boxed().toArray(Integer[]::new);
+                    mZoneAdapter = new ArrayAdapter<>(mContext,
+                            android.R.layout.simple_spinner_item, zoneArray);
+                    mZoneAdapter.setDropDownViewResource(
+                            android.R.layout.simple_spinner_dropdown_item);
+                    mZoneSpinner.setAdapter(mZoneAdapter);
+                    mZoneSpinner.setEnabled(true);
 
-                if (mCarAudioManager.isDynamicRoutingEnabled()) {
-                    setUpDisplayPlayer();
-                }
-            }
-            @Override
-            public void onServiceDisconnected(ComponentName name) {
-            }
-            });
-        mCar.connect();
+                    if (mCarAudioManager.isDynamicRoutingEnabled()) {
+                        setUpDisplayPlayer();
+                    }
+                });
     }
 
     private void initializePlayers() {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java
index 7657c38..8886913 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java
@@ -17,6 +17,7 @@
 
 import android.annotation.Nullable;
 import android.car.Car;
+import android.car.Car.CarServiceLifecycleListener;
 import android.car.CarAppFocusManager;
 import android.car.CarNotConnectedException;
 import android.car.cluster.navigation.NavigationState;
@@ -33,11 +34,8 @@
 import android.car.cluster.navigation.NavigationState.Step;
 import android.car.cluster.navigation.NavigationState.Timestamp;
 import android.car.navigation.CarNavigationStatusManager;
-import android.content.ComponentName;
-import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -73,19 +71,19 @@
     private NavigationStateProto[] mNavStateData;
     private Button mTurnByTurnButton;
 
-    private ServiceConnection mCarServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            Log.d(TAG, "Connected to Car Service");
-            mCarNavigationStatusManager = (CarNavigationStatusManager) mCarApi
-                    .getCarManager(Car.CAR_NAVIGATION_SERVICE);
-            mCarAppFocusManager = (CarAppFocusManager) mCarApi
-                    .getCarManager(Car.APP_FOCUS_SERVICE);
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
+    private CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
+        if (!ready) {
             Log.d(TAG, "Disconnect from Car Service");
+            return;
+        }
+        Log.d(TAG, "Connected to Car Service");
+        try {
+            mCarNavigationStatusManager = (CarNavigationStatusManager) car.getCarManager(
+                    Car.CAR_NAVIGATION_SERVICE);
+            mCarAppFocusManager = (CarAppFocusManager) car.getCarManager(
+                    Car.APP_FOCUS_SERVICE);
+        } catch (CarNotConnectedException e) {
+            Log.e(TAG, "Car is not connected!", e);
         }
     };
 
@@ -117,13 +115,8 @@
 
 
     private void initCarApi() {
-        if (mCarApi != null && mCarApi.isConnected()) {
-            mCarApi.disconnect();
-            mCarApi = null;
-        }
-
-        mCarApi = Car.createCar(getContext(), mCarServiceConnection);
-        mCarApi.connect();
+        mCarApi = Car.createCar(getContext(), /* handler= */ null,
+                Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mCarServiceLifecycleListener);
     }
 
     @NonNull
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
index 73e3798..df9aa7b 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
@@ -16,14 +16,12 @@
 package com.google.android.car.kitchensink.volume;
 
 import android.car.Car;
+import android.car.Car.CarServiceLifecycleListener;
 import android.car.media.CarAudioManager;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.ServiceConnection;
 import android.media.AudioManager;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Message;
 import android.util.Log;
 import android.util.SparseIntArray;
@@ -112,20 +110,15 @@
         public boolean mHasFocus;
     }
 
-    private final ServiceConnection mCarConnectionCallback =
-            new ServiceConnection() {
-                @Override
-                public void onServiceConnected(ComponentName name, IBinder binder) {
-                    Log.d(TAG, "Connected to Car Service");
-                    mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
-                    initVolumeInfo();
-                }
-
-                @Override
-                public void onServiceDisconnected(ComponentName name) {
-                    Log.d(TAG, "Disconnect from Car Service");
-                }
-            };
+    private CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
+        if (!ready) {
+            Log.d(TAG, "Disconnect from Car Service");
+            return;
+        }
+        Log.d(TAG, "Connected to Car Service");
+        mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
+        initVolumeInfo();
+    };
 
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -161,8 +154,8 @@
         mBalance = v.findViewById(R.id.balance_bar);
         mBalance.setOnSeekBarChangeListener(seekListener);
 
-        mCar = Car.createCar(getActivity(), mCarConnectionCallback);
-        mCar.connect();
+        mCar = Car.createCar(getActivity(), /* handler= */ null,
+                Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mCarServiceLifecycleListener);
         return v;
     }
 
@@ -210,12 +203,4 @@
         }
         mAdapter.refreshVolumes(mVolumeInfos);
     }
-
-    @Override
-    public void onDestroy() {
-        if (mCar != null) {
-            mCar.disconnect();
-        }
-        super.onDestroy();
-    }
 }
diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
index 091c960..82f0608 100644
--- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
@@ -263,11 +263,10 @@
         if (mRealCarServiceReleased) {
             return;  // We just want to release it once.
         }
-
         mRealCarServiceReleased = true;  // To make sure it was called once.
 
         Object waitForConnection = new Object();
-        android.car.Car car = android.car.Car.createCar(context, new ServiceConnection() {
+        Car car = android.car.Car.createCar(context, new ServiceConnection() {
             @Override
             public void onServiceConnected(ComponentName name, IBinder service) {
                 synchronized (waitForConnection) {
@@ -289,10 +288,10 @@
         if (car.isConnected()) {
             Log.i(TAG, "Connected to real car service");
             CarTestManagerBinderWrapper binderWrapper =
-                    (CarTestManagerBinderWrapper) car.getCarManager(android.car.Car.TEST_SERVICE);
+                    (CarTestManagerBinderWrapper) car.getCarManager(Car.TEST_SERVICE);
             assertNotNull(binderWrapper);
 
-            CarTestManager mgr = new CarTestManager(binderWrapper.binder);
+            CarTestManager mgr = new CarTestManager(car, binderWrapper.binder);
             mgr.stopCarService(mCarServiceToken);
         }
     }
diff --git a/tests/carservice_unit_test/src/android/car/CarTest.java b/tests/carservice_unit_test/src/android/car/CarTest.java
index 9ac8d75..d12334d 100644
--- a/tests/carservice_unit_test/src/android/car/CarTest.java
+++ b/tests/carservice_unit_test/src/android/car/CarTest.java
@@ -22,6 +22,8 @@
 
 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;
@@ -177,7 +179,13 @@
         runOnMainSyncSafe(() -> {
             car.getServiceConnectionListener().onServiceConnected(new ComponentName("", ""),
                     mService);
-            car.getServiceConnectionListener().onServiceDisconnected(new ComponentName("", ""));
+            try {
+                car.getServiceConnectionListener().onServiceDisconnected(new ComponentName("", ""));
+            } catch (IllegalStateException e) {
+                // expected
+                return;
+            }
+            fail("onServiceDisconnected should have triggered exception");
         });
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
index 84ce231..ae3d136 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
@@ -26,13 +26,13 @@
 import static org.testng.Assert.assertThrows;
 
 import android.app.ActivityManager;
+import android.car.Car;
 import android.car.CarOccupantZoneManager;
 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
 import android.car.VehicleAreaSeat;
 import android.content.Context;
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
-import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
 import android.view.Display;
@@ -207,8 +207,8 @@
         doReturn(VehicleAreaSeat.SEAT_ROW_1_LEFT).when(mService).getDriverSeat();
         doReturn(ActivityManager.getCurrentUser()).when(mService).getCurrentUser();
 
-        mManager = new CarOccupantZoneManager(mService, mContext, new Handler(
-                Looper.getMainLooper()));
+        Car car = new Car(mContext, /* service= */null, /* handler= */ null);
+        mManager = new CarOccupantZoneManager(car, mService);
     }
 
     @After