Address security issues in Comms API

1. To avoid the receiver forgetting to check the version and signature,
   this CL applied the default check on the receiver side while allowing
   the receiver to have custom check.
2. Merge onRjected() into onFailed() to simplify the API
3. Provide default implementation for some methods in
   AbstractReceiverService since the client app doesn't have to
   overriden them.

Bug: 268779678
Bug: 257118072
Test: atest com.android.car.occupantconnection.CarOccupantConnectionServiceTest
Test: atest com.android.car.CarOccupantConnectionManagerUnitTest
Test: atest android.car.cts.CarOccupantConnectionManagerTest
Test: atest android.car.occupantconnection.AbstractReceiverServiceUnitTest
Test: atest com.android.car.occupantconnection.CarOccupantConnectionManagerPermissionTest

Change-Id: Id631da288a02f1987fe21ead2730294fd45c9fd6
diff --git a/car-lib-module/api/system-current.txt b/car-lib-module/api/system-current.txt
index 2e14fdf..de997b5 100644
--- a/car-lib-module/api/system-current.txt
+++ b/car-lib-module/api/system-current.txt
@@ -210,8 +210,8 @@
     field public static final int FLAG_CLIENT_INSTALLED = 1; // 0x1
     field public static final int FLAG_CLIENT_IN_FOREGROUND = 16; // 0x10
     field public static final int FLAG_CLIENT_RUNNING = 8; // 0x8
+    field public static final int FLAG_CLIENT_SAME_LONG_VERSION = 2; // 0x2
     field public static final int FLAG_CLIENT_SAME_SIGNATURE = 4; // 0x4
-    field public static final int FLAG_CLIENT_SAME_VERSION = 2; // 0x2
     field public static final int FLAG_OCCUPANT_ZONE_CONNECTION_READY = 4; // 0x4
     field public static final int FLAG_OCCUPANT_ZONE_POWER_ON = 1; // 0x1
     field public static final int FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED = 2; // 0x2
@@ -1698,11 +1698,13 @@
     method public void dump(@Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
     method public final boolean forwardPayload(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull String, @NonNull android.car.occupantconnection.Payload);
     method @NonNull public final java.util.Set<java.lang.String> getAllReceiverEndpoints();
+    method public boolean isSenderAuthorized(@NonNull android.content.pm.SigningInfo);
+    method public boolean isSenderCompatible(long);
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
-    method public abstract void onConnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
-    method public abstract void onConnectionCanceled(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
-    method public abstract void onConnectionInitiated(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
-    method public abstract void onDisconnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public void onConnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public void onConnectionCanceled(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public abstract void onConnectionInitiated(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public void onDisconnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method @Nullable public android.os.IBinder onLocalServiceBind(@NonNull android.content.Intent);
     method public abstract void onPayloadReceived(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull android.car.occupantconnection.Payload);
     method public void onReceiverRegistered(@NonNull String);
@@ -1717,17 +1719,20 @@
     method @RequiresPermission(android.car.Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION) public void requestConnection(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull java.util.concurrent.Executor, @NonNull android.car.occupantconnection.CarOccupantConnectionManager.ConnectionRequestCallback);
     method @RequiresPermission(android.car.Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION) public void sendPayload(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull android.car.occupantconnection.Payload) throws android.car.occupantconnection.CarOccupantConnectionManager.PayloadTransferException;
     method @RequiresPermission(android.car.Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION) public void unregisterReceiver(@NonNull String);
+    field public static final int CONNECTION_ERROR_LONG_VERSION_NOT_MATCH = 4; // 0x4
     field public static final int CONNECTION_ERROR_NONE = 0; // 0x0
     field public static final int CONNECTION_ERROR_NOT_READY = 2; // 0x2
     field public static final int CONNECTION_ERROR_PEER_APP_NOT_INSTALLED = 3; // 0x3
+    field public static final int CONNECTION_ERROR_PREDEFINED_MAXIMUM_VALUE = 10000; // 0x2710
+    field public static final int CONNECTION_ERROR_SIGNATURE_NOT_MATCH = 5; // 0x5
     field public static final int CONNECTION_ERROR_UNKNOWN = 1; // 0x1
+    field public static final int CONNECTION_ERROR_USER_REJECTED = 6; // 0x6
   }
 
   public static interface CarOccupantConnectionManager.ConnectionRequestCallback {
     method public void onConnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method public void onDisconnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method public void onFailed(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
-    method public void onRejected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
   }
 
   public static interface CarOccupantConnectionManager.PayloadCallback {
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 2e14fdf..de997b5 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -210,8 +210,8 @@
     field public static final int FLAG_CLIENT_INSTALLED = 1; // 0x1
     field public static final int FLAG_CLIENT_IN_FOREGROUND = 16; // 0x10
     field public static final int FLAG_CLIENT_RUNNING = 8; // 0x8
+    field public static final int FLAG_CLIENT_SAME_LONG_VERSION = 2; // 0x2
     field public static final int FLAG_CLIENT_SAME_SIGNATURE = 4; // 0x4
-    field public static final int FLAG_CLIENT_SAME_VERSION = 2; // 0x2
     field public static final int FLAG_OCCUPANT_ZONE_CONNECTION_READY = 4; // 0x4
     field public static final int FLAG_OCCUPANT_ZONE_POWER_ON = 1; // 0x1
     field public static final int FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED = 2; // 0x2
@@ -1698,11 +1698,13 @@
     method public void dump(@Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
     method public final boolean forwardPayload(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull String, @NonNull android.car.occupantconnection.Payload);
     method @NonNull public final java.util.Set<java.lang.String> getAllReceiverEndpoints();
+    method public boolean isSenderAuthorized(@NonNull android.content.pm.SigningInfo);
+    method public boolean isSenderCompatible(long);
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
-    method public abstract void onConnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
-    method public abstract void onConnectionCanceled(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
-    method public abstract void onConnectionInitiated(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
-    method public abstract void onDisconnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public void onConnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public void onConnectionCanceled(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public abstract void onConnectionInitiated(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public void onDisconnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method @Nullable public android.os.IBinder onLocalServiceBind(@NonNull android.content.Intent);
     method public abstract void onPayloadReceived(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull android.car.occupantconnection.Payload);
     method public void onReceiverRegistered(@NonNull String);
@@ -1717,17 +1719,20 @@
     method @RequiresPermission(android.car.Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION) public void requestConnection(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull java.util.concurrent.Executor, @NonNull android.car.occupantconnection.CarOccupantConnectionManager.ConnectionRequestCallback);
     method @RequiresPermission(android.car.Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION) public void sendPayload(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull android.car.occupantconnection.Payload) throws android.car.occupantconnection.CarOccupantConnectionManager.PayloadTransferException;
     method @RequiresPermission(android.car.Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION) public void unregisterReceiver(@NonNull String);
+    field public static final int CONNECTION_ERROR_LONG_VERSION_NOT_MATCH = 4; // 0x4
     field public static final int CONNECTION_ERROR_NONE = 0; // 0x0
     field public static final int CONNECTION_ERROR_NOT_READY = 2; // 0x2
     field public static final int CONNECTION_ERROR_PEER_APP_NOT_INSTALLED = 3; // 0x3
+    field public static final int CONNECTION_ERROR_PREDEFINED_MAXIMUM_VALUE = 10000; // 0x2710
+    field public static final int CONNECTION_ERROR_SIGNATURE_NOT_MATCH = 5; // 0x5
     field public static final int CONNECTION_ERROR_UNKNOWN = 1; // 0x1
+    field public static final int CONNECTION_ERROR_USER_REJECTED = 6; // 0x6
   }
 
   public static interface CarOccupantConnectionManager.ConnectionRequestCallback {
     method public void onConnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method public void onDisconnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method public void onFailed(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
-    method public void onRejected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
   }
 
   public static interface CarOccupantConnectionManager.PayloadCallback {
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index d1bbdbb..eed7089 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -216,8 +216,8 @@
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int FLAG_CLIENT_INSTALLED = 1; // 0x1
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int FLAG_CLIENT_IN_FOREGROUND = 16; // 0x10
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int FLAG_CLIENT_RUNNING = 8; // 0x8
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int FLAG_CLIENT_SAME_LONG_VERSION = 2; // 0x2
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int FLAG_CLIENT_SAME_SIGNATURE = 4; // 0x4
-    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int FLAG_CLIENT_SAME_VERSION = 2; // 0x2
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int FLAG_OCCUPANT_ZONE_CONNECTION_READY = 4; // 0x4
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int FLAG_OCCUPANT_ZONE_POWER_ON = 1; // 0x1
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED = 2; // 0x2
@@ -1774,11 +1774,13 @@
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public void dump(@Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public final boolean forwardPayload(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull String, @NonNull android.car.occupantconnection.Payload);
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @NonNull public final java.util.Set<java.lang.String> getAllReceiverEndpoints();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public boolean isSenderAuthorized(@NonNull android.content.pm.SigningInfo);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public boolean isSenderCompatible(long);
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
-    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public abstract void onConnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
-    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public abstract void onConnectionCanceled(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
-    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public abstract void onConnectionInitiated(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
-    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public abstract void onDisconnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public void onConnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public void onConnectionCanceled(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public abstract void onConnectionInitiated(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public void onDisconnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @Nullable public android.os.IBinder onLocalServiceBind(@NonNull android.content.Intent);
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public abstract void onPayloadReceived(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull android.car.occupantconnection.Payload);
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public void onReceiverRegistered(@NonNull String);
@@ -1793,17 +1795,20 @@
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @RequiresPermission(android.car.Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION) public void requestConnection(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull java.util.concurrent.Executor, @NonNull android.car.occupantconnection.CarOccupantConnectionManager.ConnectionRequestCallback);
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @RequiresPermission(android.car.Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION) public void sendPayload(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull android.car.occupantconnection.Payload) throws android.car.occupantconnection.CarOccupantConnectionManager.PayloadTransferException;
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @RequiresPermission(android.car.Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION) public void unregisterReceiver(@NonNull String);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int CONNECTION_ERROR_LONG_VERSION_NOT_MATCH = 4; // 0x4
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int CONNECTION_ERROR_NONE = 0; // 0x0
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int CONNECTION_ERROR_NOT_READY = 2; // 0x2
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int CONNECTION_ERROR_PEER_APP_NOT_INSTALLED = 3; // 0x3
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int CONNECTION_ERROR_PREDEFINED_MAXIMUM_VALUE = 10000; // 0x2710
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int CONNECTION_ERROR_SIGNATURE_NOT_MATCH = 5; // 0x5
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int CONNECTION_ERROR_UNKNOWN = 1; // 0x1
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int CONNECTION_ERROR_USER_REJECTED = 6; // 0x6
   }
 
   public static interface CarOccupantConnectionManager.ConnectionRequestCallback {
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public void onConnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public void onDisconnected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public void onFailed(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
-    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public void onRejected(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
   }
 
   public static interface CarOccupantConnectionManager.PayloadCallback {
diff --git a/car-lib/src/android/car/CarRemoteDeviceManager.java b/car-lib/src/android/car/CarRemoteDeviceManager.java
index 8cc0353..3dc3e99 100644
--- a/car-lib/src/android/car/CarRemoteDeviceManager.java
+++ b/car-lib/src/android/car/CarRemoteDeviceManager.java
@@ -103,7 +103,7 @@
      */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
             minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
-    public static final int FLAG_CLIENT_SAME_VERSION = 1 << 1;
+    public static final int FLAG_CLIENT_SAME_LONG_VERSION = 1 << 1;
 
     /**
      * Flag to indicate whether the client app with the same signing info ({@link
@@ -155,7 +155,7 @@
      */
     @IntDef(flag = true, prefix = {"FLAG_CLIENT_"}, value = {
             FLAG_CLIENT_INSTALLED,
-            FLAG_CLIENT_SAME_VERSION,
+            FLAG_CLIENT_SAME_LONG_VERSION,
             FLAG_CLIENT_SAME_SIGNATURE,
             FLAG_CLIENT_RUNNING,
             FLAG_CLIENT_IN_FOREGROUND
diff --git a/car-lib/src/android/car/occupantconnection/AbstractReceiverService.java b/car-lib/src/android/car/occupantconnection/AbstractReceiverService.java
index db05f69..9b5f1ed 100644
--- a/car-lib/src/android/car/occupantconnection/AbstractReceiverService.java
+++ b/car-lib/src/android/car/occupantconnection/AbstractReceiverService.java
@@ -17,18 +17,24 @@
 package android.car.occupantconnection;
 
 import static android.car.Car.CAR_INTENT_ACTION_RECEIVER_SERVICE;
+import static android.car.occupantconnection.CarOccupantConnectionManager.CONNECTION_ERROR_LONG_VERSION_NOT_MATCH;
+import static android.car.occupantconnection.CarOccupantConnectionManager.CONNECTION_ERROR_SIGNATURE_NOT_MATCH;
+import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES;
 
 import static com.android.car.internal.util.VersionUtils.assertPlatformVersionAtLeastU;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
-import android.car.CarRemoteDeviceManager.AppState;
 import android.car.annotation.ApiRequirements;
 import android.car.builtin.util.Slogf;
 import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.SigningInfo;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -100,6 +106,7 @@
             new BinderKeyValueContainer<>();
 
     private IBackendConnectionResponder mBackendConnectionResponder;
+    private long mMyVersionCode;
 
     private final IBackendReceiver.Stub mBackendReceiver = new IBackendReceiver.Stub() {
         @Override
@@ -124,9 +131,24 @@
         }
 
         @Override
-        public void onConnectionInitiated(OccupantZoneInfo senderZone,
-                @AppState int senderAppState) {
-            AbstractReceiverService.this.onConnectionInitiated(senderZone, senderAppState);
+        public void onConnectionInitiated(OccupantZoneInfo senderZone, long senderVersion,
+                SigningInfo senderSigningInfo) {
+            if (!isSenderCompatible(senderVersion)) {
+                Slogf.w(TAG, "Reject the connection request from %s because its long version"
+                                + " code %d doesn't match the receiver's %d ", senderZone,
+                        senderVersion, mMyVersionCode);
+                AbstractReceiverService.this.rejectConnection(senderZone,
+                        CONNECTION_ERROR_LONG_VERSION_NOT_MATCH);
+                return;
+            }
+            if (!isSenderAuthorized(senderSigningInfo)) {
+                Slogf.w(TAG, "Reject the connection request from %s because its SigningInfo"
+                        + " doesn't match", senderZone);
+                AbstractReceiverService.this.rejectConnection(senderZone,
+                        CONNECTION_ERROR_SIGNATURE_NOT_MATCH);
+                return;
+            }
+            AbstractReceiverService.this.onConnectionInitiated(senderZone);
         }
 
         @Override
@@ -147,6 +169,24 @@
 
     /**
      * {@inheritDoc}
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        assertPlatformVersionAtLeastU();
+        try {
+            PackageInfo myInfo = getPackageManager().getPackageInfo(getPackageName(),
+                    GET_SIGNING_CERTIFICATES);
+            mMyVersionCode = myInfo.getLongVersionCode();
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException("Couldn't find the PackageInfo of " + getPackageName(), e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
      * <p>
      * To prevent the client app overriding this method improperly, this method is {@code final}.
      * If the client app needs to bind to this service, it should override {@link
@@ -205,54 +245,76 @@
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
             minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
     public void onReceiverRegistered(@NonNull String receiverEndpointId) {
+        assertPlatformVersionAtLeastU();
     }
 
-
     /**
-     * Invoked when the sender client on {@code senderZone} has requested a connection to this
-     * client.
+     * Returns whether the long version code ({@link PackageInfo#getLongVersionCode}) of the sender
+     * app is compatible with the receiver app's. If it doesn't match, this service will reject the
+     * connection request from the sender.
      * <p>
-     * When the connection is initiated, the inheritance of this service can call {@link
-     * #acceptConnection} or {@link #rejectConnection}.
-     * <ul>
-     *   <li> If user confirmation is not needed to establish the connection, the inheritance can
-     *        just call {@link #acceptConnection}.
-     *   <li> Otherwise, the inheritance can call {@link
-     *        android.app.Activity#startActivityForResult} to launch a permission activity, and call
-     *        {@link #acceptConnection} or {@link #rejectConnection} based on the activity result.
-     *        For driving safety, the permission activity must be distraction optimized. If this
-     *        is infeasible, the inheritance should just call {@link #rejectConnection}.
-     *   <li> For security, it is highly recommended that the inheritance not accept the connection
-     *        if {@code senderAppState} doesn't contain
-     *        {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_VERSION} or
-     *        {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_SIGNATURE}. If the
-     *        inheritance still wants to accept the connection in the case above, it should call
-     *        {@link android.car.CarRemoteDeviceManager#getEndpointPackageInfo} to get the sender's
-     *        {@link android.content.pm.PackageInfo} and check if it's valid before accepting the
-     *        connection.
-     * </ul>
-     *
-     * @param senderZone     the occupant zone that the sender client runs in
-     * @param senderAppState the {@link AppState} of the sender
+     * The default implementation checks whether the version codes are identical. This is fine if
+     * all the peer clients run on the same Android instance, since PackageManager doesn't allow to
+     * install two different apps with the same package name - even for different users.
+     * However, if the peer clients run on different Android instances, and the app wants to support
+     * connection between them even if they have different versions, the app will need to override
+     * this method.
      */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
             minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
-    public abstract void onConnectionInitiated(@NonNull OccupantZoneInfo senderZone,
-            @AppState int senderAppState);
+    @SuppressLint("OnNameExpected")
+    public boolean isSenderCompatible(long senderVersion) {
+        assertPlatformVersionAtLeastU();
+        return mMyVersionCode == senderVersion;
+    }
+
+    /**
+     * Returns whether the signing info ({@link PackageInfo#signingInfo} of the sender app is
+     * authorized. If it is not authorized, this service will reject the connection request from
+     * the sender.
+     * <p>
+     * The default implementation simply returns {@code true}. This is fine if all the peer clients
+     * run on the same Android instance, since PackageManager doesn't allow to install two different
+     * apps with the same package name - even for different users.
+     * However, if the peer clients run on different Android instances, the app must override this
+     * method for security.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    @SuppressLint("OnNameExpected")
+    public boolean isSenderAuthorized(@NonNull SigningInfo senderSigningInfo) {
+        assertPlatformVersionAtLeastU();
+        return true;
+    }
+
+    /**
+     * Invoked when the sender client in {@code senderZone} has requested a connection to this
+     * client.
+     * <p>
+     * If user confirmation is needed to establish the connection, the inheritance can override
+     * this method to launch a permission activity, and call {@link #acceptConnection} or
+     * {@link #rejectConnection} based on the result. For driving safety, the permission activity
+     * must be distraction optimized. Alternatively, the permission can be granted during device
+     * setup.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public abstract void onConnectionInitiated(@NonNull OccupantZoneInfo senderZone);
 
     /**
      * Invoked when the one-way connection has been established.
      * <p>
      * In order to establish the connection, the inheritance of this service must call
      * {@link #acceptConnection}, and the sender must NOT call {@link
-     * android.car.occupantconnection.CarOccupantConnectionManager#cancelConnection} before the
-     * connection is established.
+     * CarOccupantConnectionManager#cancelConnection} before the connection is established.
      * <p>
      * Once the connection is established, the sender can send {@link Payload} to this client.
      */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
             minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
-    public abstract void onConnected(@NonNull OccupantZoneInfo senderZone);
+    public void onConnected(@NonNull OccupantZoneInfo senderZone) {
+        assertPlatformVersionAtLeastU();
+    }
 
     /**
      * Invoked when the sender has canceled the pending connection request, or has become
@@ -260,18 +322,22 @@
      */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
             minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
-    public abstract void onConnectionCanceled(@NonNull OccupantZoneInfo senderZone);
+    public void onConnectionCanceled(@NonNull OccupantZoneInfo senderZone) {
+        assertPlatformVersionAtLeastU();
+    }
 
     /**
      * Invoked when the connection is terminated. For example, the sender on {@code senderZone}
-     * has called {@link android.car.occupantconnection.CarOccupantConnectionManager#disconnect},
-     * or the sender has become unreachable.
+     * has called {@link CarOccupantConnectionManager#disconnect}, or the sender has become
+     * unreachable.
      * <p>
      * When disconnected, the sender can no longer send {@link Payload} to this client.
      */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
             minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
-    public abstract void onDisconnected(@NonNull OccupantZoneInfo senderZone);
+    public void onDisconnected(@NonNull OccupantZoneInfo senderZone) {
+        assertPlatformVersionAtLeastU();
+    }
 
     /** Accepts the connection request from {@code senderZone}. */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
@@ -288,8 +354,12 @@
     /**
      * Rejects the connection request from {@code senderZone}.
      *
-     * @param rejectionReason the reason for rejection, such as user rejected, UX restricted.
-     *                        The client app is responsible for defining this value
+     * @param rejectionReason the reason for rejection. It could be a predefined value (
+     *        {@link CarOccupantConnectionManager#CONNECTION_ERROR_LONG_VERSION_NOT_MATCH},
+     *        {@link CarOccupantConnectionManager#CONNECTION_ERROR_SIGNATURE_NOT_MATCH},
+     *        {@link CarOccupantConnectionManager#CONNECTION_ERROR_USER_REJECTED}), or app-defined
+     *        value that is larger than {@link
+     *        CarOccupantConnectionManager#CONNECTION_ERROR_PREDEFINED_MAXIMUM_VALUE}.
      */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
             minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
diff --git a/car-lib/src/android/car/occupantconnection/CarOccupantConnectionManager.java b/car-lib/src/android/car/occupantconnection/CarOccupantConnectionManager.java
index a0958ed..7285e68 100644
--- a/car-lib/src/android/car/occupantconnection/CarOccupantConnectionManager.java
+++ b/car-lib/src/android/car/occupantconnection/CarOccupantConnectionManager.java
@@ -212,6 +212,37 @@
     public static final int CONNECTION_ERROR_PEER_APP_NOT_INSTALLED = 3;
 
     /**
+     * The connection request failed because its long version code ({@link
+     * PackageInfo#getLongVersionCode}) didn't match the peer app's long version code.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int CONNECTION_ERROR_LONG_VERSION_NOT_MATCH = 4;
+
+    /**
+     * The connection request failed because its signing info ({@link PackageInfo#signingInfo}
+     * didn't match the peer app's signing info.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int CONNECTION_ERROR_SIGNATURE_NOT_MATCH = 5;
+
+    /** The connection request failed because the user rejected it. */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int CONNECTION_ERROR_USER_REJECTED = 6;
+
+    /**
+     * The maximum value of predefined connection error code. If the client app wants to pass a
+     * custom value in {@link AbstractReceiverService#rejectConnection}, the custom value must be
+     * larger than this value, otherwise the sender client might get the wrong connection error code
+     * when its connection request fails.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int CONNECTION_ERROR_PREDEFINED_MAXIMUM_VALUE = 10000;
+
+    /**
      * Flags for the error type of connection request.
      *
      * @hide
@@ -220,7 +251,11 @@
             CONNECTION_ERROR_NONE,
             CONNECTION_ERROR_UNKNOWN,
             CONNECTION_ERROR_NOT_READY,
-            CONNECTION_ERROR_PEER_APP_NOT_INSTALLED
+            CONNECTION_ERROR_PEER_APP_NOT_INSTALLED,
+            CONNECTION_ERROR_LONG_VERSION_NOT_MATCH,
+            CONNECTION_ERROR_SIGNATURE_NOT_MATCH,
+            CONNECTION_ERROR_USER_REJECTED,
+            CONNECTION_ERROR_PREDEFINED_MAXIMUM_VALUE
     })
     @Retention(RetentionPolicy.SOURCE)
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
@@ -249,23 +284,16 @@
         void onConnected(@NonNull OccupantZoneInfo receiverZone);
 
         /**
-         * Invoked when the connection request has been rejected by the receiver client.
-         *
-         * @param rejectionReason the reason for rejection, such as the user rejected, UX
-         *                        restricted. The client app is responsible for defining this value.
-         */
-        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
-                minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
-        void onRejected(@NonNull OccupantZoneInfo receiverZone, int rejectionReason);
-
-        /**
          * Invoked when there was an error when establishing the connection. For example, the
-         * receiver client is not ready for connection.
+         * receiver client is not ready for connection, or the receiver client rejected the
+         * connection request.
+         *
+         * @param connectionError could be any value of {@link ConnectionError}, or an app-defined
+         *                        value
          */
         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
                 minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
-        void onFailed(@NonNull OccupantZoneInfo receiverZone,
-                @ConnectionError int connectionError);
+        void onFailed(@NonNull OccupantZoneInfo receiverZone, int connectionError);
 
         /**
          * Invoked when the connection is terminated. For example, the receiver {@link
@@ -334,24 +362,6 @@
                 }
 
                 @Override
-                public void onRejected(OccupantZoneInfo receiverZone, int rejectionReason) {
-                    synchronized (mLock) {
-                        Pair<ConnectionRequestCallback, Executor> pair =
-                                mConnectionRequestMap.get(receiverZone.zoneId);
-                        if (pair == null) {
-                            Slog.e(TAG, "onRejected: no pending connection request");
-                            return;
-                        }
-                        // Notify the sender of rejection.
-                        ConnectionRequestCallback callback = pair.first;
-                        Executor executor = pair.second;
-                        executor.execute(() -> callback.onRejected(receiverZone, rejectionReason));
-
-                        mConnectionRequestMap.remove(receiverZone.zoneId);
-                    }
-                }
-
-                @Override
                 public void onFailed(OccupantZoneInfo receiverZone, int connectionError) {
                     synchronized (mLock) {
                         Pair<ConnectionRequestCallback, Executor> pair =
@@ -515,7 +525,7 @@
      * <p>
      * For security, it is highly recommended that the sender not request a connection to the
      * receiver client if the state of the receiver client doesn't contain
-     * {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_VERSION} or
+     * {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_LONG_VERSION} or
      * {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_SIGNATURE}. If the sender still
      * wants to request the connection in the case above, it should call
      * {@link android.car.CarRemoteDeviceManager#getEndpointPackageInfo} to get the receiver's
diff --git a/car-lib/src/android/car/occupantconnection/IBackendReceiver.aidl b/car-lib/src/android/car/occupantconnection/IBackendReceiver.aidl
index f619444..9075dbe 100644
--- a/car-lib/src/android/car/occupantconnection/IBackendReceiver.aidl
+++ b/car-lib/src/android/car/occupantconnection/IBackendReceiver.aidl
@@ -20,6 +20,7 @@
 import android.car.occupantconnection.IBackendConnectionResponder;
 import android.car.occupantconnection.IPayloadCallback;
 import android.car.occupantconnection.Payload;
+import android.content.pm.SigningInfo;
 
 /**
   * AIDL used by CarOccupantConnectionService to communicate to AbstractReceiverService.
@@ -38,7 +39,7 @@
         in Payload payload);
 
     void onConnectionInitiated(in CarOccupantZoneManager.OccupantZoneInfo senderZone,
-        int senderAppState);
+        long senderVersion, in SigningInfo senderSigningInfo);
 
     void onConnected(in CarOccupantZoneManager.OccupantZoneInfo senderZone);
 
diff --git a/car-lib/src/android/car/occupantconnection/IConnectionRequestCallback.aidl b/car-lib/src/android/car/occupantconnection/IConnectionRequestCallback.aidl
index d5808f7..58dab51 100644
--- a/car-lib/src/android/car/occupantconnection/IConnectionRequestCallback.aidl
+++ b/car-lib/src/android/car/occupantconnection/IConnectionRequestCallback.aidl
@@ -23,9 +23,6 @@
 
     void onConnected(in CarOccupantZoneManager.OccupantZoneInfo receiverZone);
 
-    void onRejected(in CarOccupantZoneManager.OccupantZoneInfo receiverZone,
-        int rejectionReason);
-
     void onFailed(in CarOccupantZoneManager.OccupantZoneInfo receiverZone,
         int connectionError);
 
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index b52ab59..22594cc 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -486,15 +486,17 @@
 
         if (mFeatureController.isFeatureEnabled(Car.CAR_OCCUPANT_CONNECTION_SERVICE)
                 || mFeatureController.isFeatureEnabled(Car.CAR_REMOTE_DEVICE_SERVICE)) {
-            mCarOccupantConnectionService = constructWithTrace(
-                    t, CarOccupantConnectionService.class,
-                    () -> new CarOccupantConnectionService(serviceContext, mCarOccupantZoneService),
-                    allServices);
             mCarRemoteDeviceService = constructWithTrace(
                     t, CarRemoteDeviceService.class,
                     () -> new CarRemoteDeviceService(serviceContext, mCarOccupantZoneService,
                             mCarPowerManagementService, mSystemActivityMonitoringService),
                     allServices);
+            mCarOccupantConnectionService = constructWithTrace(
+                    t, CarOccupantConnectionService.class,
+                    () -> new CarOccupantConnectionService(serviceContext, mCarOccupantZoneService,
+                            mCarRemoteDeviceService),
+                    allServices);
+
         } else {
             mCarOccupantConnectionService = null;
             mCarRemoteDeviceService = null;
diff --git a/service/src/com/android/car/occupantconnection/CarOccupantConnectionService.java b/service/src/com/android/car/occupantconnection/CarOccupantConnectionService.java
index 99fd6a4..c591e53 100644
--- a/service/src/com/android/car/occupantconnection/CarOccupantConnectionService.java
+++ b/service/src/com/android/car/occupantconnection/CarOccupantConnectionService.java
@@ -18,11 +18,6 @@
 
 import static android.car.Car.CAR_INTENT_ACTION_RECEIVER_SERVICE;
 import static android.car.CarOccupantZoneManager.INVALID_USER_ID;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_INSTALLED;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_IN_FOREGROUND;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_RUNNING;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_SIGNATURE;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_VERSION;
 import static android.car.occupantconnection.CarOccupantConnectionManager.CONNECTION_ERROR_NONE;
 import static android.car.occupantconnection.CarOccupantConnectionManager.CONNECTION_ERROR_NOT_READY;
 import static android.car.occupantconnection.CarOccupantConnectionManager.CONNECTION_ERROR_PEER_APP_NOT_INSTALLED;
@@ -37,7 +32,6 @@
 import android.car.Car;
 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
 import android.car.builtin.util.Slogf;
-import android.car.occupantconnection.CarOccupantConnectionManager.ConnectionError;
 import android.car.occupantconnection.IBackendConnectionResponder;
 import android.car.occupantconnection.IBackendReceiver;
 import android.car.occupantconnection.ICarOccupantConnection;
@@ -56,7 +50,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
-import com.android.car.CarLocalServices;
 import com.android.car.CarOccupantZoneService;
 import com.android.car.CarServiceBase;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
@@ -83,6 +76,7 @@
 
     private static final int NOTIFY_ON_DISCONNECT = 1;
     private static final int NOTIFY_ON_FAILED = 2;
+
     @IntDef(flag = false, prefix = {"NOTIFY_ON_"}, value = {
             NOTIFY_ON_DISCONNECT,
             NOTIFY_ON_FAILED
@@ -94,6 +88,7 @@
     private final Context mContext;
     private final Object mLock = new Object();
     private final CarOccupantZoneService mOccupantZoneService;
+    private final CarRemoteDeviceService mRemoteDeviceService;
 
     /**
      * A set of receiver services that this service has requested to bind but has not connected
@@ -238,7 +233,7 @@
                                     senderZone.zoneId,
                                     receiverClient.occupantZone.zoneId));
                         } catch (RemoteException e) {
-                            Slogf.e(TAG, "Failed to notify connection success", e);
+                            Slogf.e(TAG, e, "Failed to notify connection success");
                         }
                     }
                 }
@@ -254,10 +249,10 @@
                         try {
                             // Only the sender needs to be notified for connection rejection
                             // since the connection was rejected by the receiver.
-                            callback.onRejected(receiverClient.occupantZone, rejectionReason);
+                            callback.onFailed(receiverClient.occupantZone, rejectionReason);
                         } catch (RemoteException e) {
-                            Slogf.e(TAG, "Failed to notify the sender for connection"
-                                    + " rejection", e);
+                            Slogf.e(TAG, e, "Failed to notify the sender for connection"
+                                    + " rejection");
                         }
                     }
                 }
@@ -271,7 +266,7 @@
             try {
                 mReceiverService.registerBackendConnectionResponder(mResponder);
             } catch (RemoteException e) {
-                Slogf.e(TAG, "Failed to register IBackendConnectionResponder", e);
+                Slogf.e(TAG, e, "Failed to register IBackendConnectionResponder");
             }
 
             synchronized (mLock) {
@@ -330,10 +325,9 @@
         }
     }
 
-    public CarOccupantConnectionService(Context context,
-            CarOccupantZoneService occupantZoneService) {
-        this(context,
-                occupantZoneService,
+    public CarOccupantConnectionService(Context context, CarOccupantZoneService occupantZoneService,
+            CarRemoteDeviceService remoteDeviceService) {
+        this(context, occupantZoneService, remoteDeviceService,
                 /* connectingReceiverServices= */ new ArraySet<>(),
                 /* connectedReceiverServiceMap= */ new BinderKeyValueContainer<>(),
                 /* receiverServiceConnectionMap= */ new ArrayMap<>(),
@@ -347,6 +341,7 @@
     @VisibleForTesting
     CarOccupantConnectionService(Context context,
             CarOccupantZoneService occupantZoneService,
+            CarRemoteDeviceService remoteDeviceService,
             ArraySet<ClientId> connectingReceiverServices,
             BinderKeyValueContainer<ClientId, IBackendReceiver> connectedReceiverServiceMap,
             ArrayMap<ClientId, ServiceConnection> receiverServiceConnectionMap,
@@ -361,6 +356,7 @@
             ArraySet<ConnectionRecord> establishedConnections) {
         mContext = context;
         mOccupantZoneService = occupantZoneService;
+        mRemoteDeviceService = remoteDeviceService;
         mConnectingReceiverServices = connectingReceiverServices;
         mConnectedReceiverServiceMap = connectedReceiverServiceMap;
         mReceiverServiceConnectionMap = receiverServiceConnectionMap;
@@ -491,7 +487,7 @@
                 mRegisteredReceiverEndpointMap.remove(receiverEndpoint);
                 maybeUnbindReceiverServiceLocked(receiverClient);
             } catch (RemoteException e) {
-                Slogf.e(TAG, "Failed the unregister the receiver " + receiverEndpoint + e);
+                Slogf.e(TAG, e, "Failed the unregister the receiver %s", receiverEndpoint);
             }
         }
     }
@@ -502,16 +498,36 @@
         assertPermission(mContext, Car.PERMISSION_MANAGE_OCCUPANT_CONNECTION);
         checkCalledByPackage(mContext, packageName);
 
+        int connectionError = CONNECTION_ERROR_NONE;
         ClientId senderClient = getCallingClientId(packageName);
         ClientId receiverClient = getClientIdInOccupantZone(receiverZone, packageName);
-        int receiverUserId = receiverClient == null ? INVALID_USER_ID : receiverClient.userId;
-        int connectionError = calculateConnectionError(receiverZone, receiverUserId, packageName);
+        // Note: don't call mRemoteDeviceService.getEndpointPackageInfo() because it requires
+        // PERMISSION_MANAGE_REMOTE_DEVICE.
+        PackageInfo senderInfo =
+                mRemoteDeviceService.getPackageInfoAsUser(packageName, senderClient.userId);
+        if (senderInfo == null) {
+            // This should not happen, but let's be cautious.
+            Slogf.e(TAG, "Failed to get the PackageInfo of the sender %s", senderClient);
+            connectionError = CONNECTION_ERROR_UNKNOWN;
+        } else if (!mRemoteDeviceService.isConnectionReady(receiverZone)) {
+            Slogf.e(TAG, "%s is not ready for connection", receiverZone);
+            connectionError = CONNECTION_ERROR_NOT_READY;
+        } else {
+            PackageInfo receiverInfo = receiverClient == null
+                    ? null
+                    : mRemoteDeviceService.getPackageInfoAsUser(packageName, receiverClient.userId);
+            if (receiverInfo == null) {
+                Slogf.e(TAG, "Peer app %s is not installed in %s", packageName, receiverZone);
+                connectionError = CONNECTION_ERROR_PEER_APP_NOT_INSTALLED;
+            }
+        }
+
         if (connectionError != CONNECTION_ERROR_NONE) {
             try {
                 callback.onFailed(receiverZone, connectionError);
             } catch (RemoteException e) {
-                Slogf.e(TAG, "Failed to notify the sender %s of connection failure %s",
-                        senderClient, e);
+                Slogf.e(TAG, e, "Failed to notify the sender %s of connection failure %d",
+                        senderClient, connectionError);
             }
             return;
         }
@@ -529,19 +545,10 @@
             IBackendReceiver receiverService = mConnectedReceiverServiceMap.get(receiverClient);
             if (receiverService != null) {
                 try {
-                    // Since the sender client is requesting connection, it must be running in the
-                    // foreground.
-                    // TODO(b/257118072): maybe we should evaluate it before setting
-                    //  FLAG_CLIENT_IN_FOREGROUND.
-                    // In single-SoC model, the sender client is guaranteed to have the same
-                    // signing info and long version code.
-                    // TODO(b/257118327): support multiple-SoC.
                     receiverService.onConnectionInitiated(senderClient.occupantZone,
-                            FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION
-                                    | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING
-                                    | FLAG_CLIENT_IN_FOREGROUND);
+                            senderInfo.getLongVersionCode(), senderInfo.signingInfo);
                 } catch (RemoteException e) {
-                    Slogf.e(TAG, "Failed to notify the receiver for connection request", e);
+                    Slogf.e(TAG, e, "Failed to notify the receiver for connection request");
                 }
                 return;
             }
@@ -643,7 +650,7 @@
                 mPreregisteredReceiverEndpointMap.removeAt(i);
                 mRegisteredReceiverEndpointMap.put(receiverEndpoint, callback);
             } catch (RemoteException e) {
-                Slogf.e(TAG, "Failed to register receiver", e);
+                Slogf.e(TAG, e, "Failed to register receiver");
             }
         }
     }
@@ -699,7 +706,7 @@
             receiverService.registerReceiver(receiverEndpoint.endpointId, callback);
             mRegisteredReceiverEndpointMap.put(receiverEndpoint, callback);
         } catch (RemoteException e) {
-            Slogf.e(TAG, "Failed to register receiver", e);
+            Slogf.e(TAG, e, "Failed to register receiver");
         }
     }
 
@@ -831,7 +838,7 @@
                                 + callbackType);
                 }
             } catch (RemoteException e) {
-                Slogf.e(TAG, "Failed to notify the sender for connection failure", e);
+                Slogf.e(TAG, e, "Failed to notify the sender for connection failure");
             }
             connectionRequestMap.removeAt(i);
         }
@@ -885,19 +892,32 @@
             // not been notified of the request before, notify the receiver service now.
             if (connectionId.receiverClient.equals(receiverClient)
                     && !notifiedSenderClients.contains(connectionId.senderClient)) {
+                // Note: don't call mRemoteDeviceService.getEndpointPackageInfo() because
+                // sendCachedConnectionRequestLocked() is called on the main thread instead of the
+                // binder thread, so the calling UID check in
+                // mRemoteDeviceService.getEndpointPackageInfo() will fail.
+                PackageInfo senderInfo = mRemoteDeviceService.getPackageInfoAsUser(
+                        connectionId.senderClient.packageName,
+                        connectionId.senderClient.userId);
+                if (senderInfo == null) {
+                    // This should not happen, but let's be cautious.
+                    Slogf.e(TAG, "Failed to get the PackageInfo of the sender %s",
+                            connectionId.senderClient);
+                    IConnectionRequestCallback callback = mPendingConnectionRequestMap.valueAt(i);
+                    try {
+                        callback.onFailed(receiverClient.occupantZone, CONNECTION_ERROR_UNKNOWN);
+                    } catch (RemoteException e) {
+                        Slogf.e(TAG, e, "Failed to notify the sender %s of connection failure",
+                                connectionId.senderClient);
+                    }
+                    return;
+                }
                 try {
-                    // Since the sender client is requesting connection, it must be running in the
-                    // foreground.
-                    // In single-SoC model, the sender client is guaranteed to have the same
-                    // signing info and long version code.
-                    // TODO(b/257118327): support multiple-SoC.
                     receiverService.onConnectionInitiated(connectionId.senderClient.occupantZone,
-                            FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION
-                                    | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING
-                                    | FLAG_CLIENT_IN_FOREGROUND);
+                            senderInfo.getLongVersionCode(), senderInfo.signingInfo);
                     notifiedSenderClients.add(connectionId.senderClient);
                 } catch (RemoteException e) {
-                    Slogf.e(TAG, "Failed to notify the receiver for connection request", e);
+                    Slogf.e(TAG, e, "Failed to notify the receiver for connection request");
                 }
             }
         }
@@ -931,9 +951,9 @@
         } catch (RemoteException e) {
             // There is no need to propagate the Exception to the sender client because
             // the connection was terminated successfully anyway.
-            Slogf.e(TAG, "Failed to notify the receiver service of disconnection! "
+            Slogf.e(TAG, e, "Failed to notify the receiver service of disconnection! "
                             + "senderClient:%s, receiverClient:%s", staleConnection.senderClient,
-                    staleConnection.receiverClient, e);
+                    staleConnection.receiverClient);
         }
 
         maybeUnbindReceiverServiceLocked(staleConnection.receiverClient);
@@ -955,38 +975,13 @@
             } catch (RemoteException e) {
                 // There is no need to propagate the Exception to the sender client because
                 // the connection was canceled successfully anyway.
-                Slogf.e(TAG, "Failed to notify the receiver service of connection request"
+                Slogf.e(TAG, e, "Failed to notify the receiver service of connection request"
                                 + " cancellation! senderClient:%s, receiverClient:%s",
-                        connectionToCancel.senderClient, connectionToCancel.receiverClient, e);
+                        connectionToCancel.senderClient, connectionToCancel.receiverClient);
             }
         }
         // The receiverService may be bound already, or being bound. In either case, it needs to be
         // unbound if it is not needed any more.
         maybeUnbindReceiverServiceLocked(connectionToCancel.receiverClient);
     }
-
-    @ConnectionError
-    private static int calculateConnectionError(OccupantZoneInfo receiverZone, int userId,
-            String packageName) {
-        CarRemoteDeviceService remoteDeviceService =
-                CarLocalServices.getService(CarRemoteDeviceService.class);
-        if (remoteDeviceService == null) {
-            Slogf.e(TAG, "CarRemoteDeviceService is not available on this device");
-            return CONNECTION_ERROR_UNKNOWN;
-        }
-        if (!remoteDeviceService.isConnectionReady(receiverZone)) {
-            Slogf.e(TAG, "%s is not ready for connection", receiverZone);
-            return CONNECTION_ERROR_NOT_READY;
-        }
-        PackageInfo receiverInfo = userId == INVALID_USER_ID
-                ? null
-                // Note: don't call remoteDeviceService.getEndpointPackageInfo() because it
-                // requires PERMISSION_MANAGE_REMOTE_DEVICE.
-                : remoteDeviceService.getPackageInfoAsUser(packageName, userId);
-        if (receiverInfo == null) {
-            Slogf.e(TAG, "Peer app %s is not installed in %s", packageName, receiverZone);
-            return CONNECTION_ERROR_PEER_APP_NOT_INSTALLED;
-        }
-        return CONNECTION_ERROR_NONE;
-    }
 }
diff --git a/service/src/com/android/car/occupantconnection/CarRemoteDeviceService.java b/service/src/com/android/car/occupantconnection/CarRemoteDeviceService.java
index 9a0b94c..d368a31 100644
--- a/service/src/com/android/car/occupantconnection/CarRemoteDeviceService.java
+++ b/service/src/com/android/car/occupantconnection/CarRemoteDeviceService.java
@@ -21,8 +21,8 @@
 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_INSTALLED;
 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_IN_FOREGROUND;
 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_RUNNING;
+import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_LONG_VERSION;
 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_SIGNATURE;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_VERSION;
 import static android.car.CarRemoteDeviceManager.FLAG_OCCUPANT_ZONE_CONNECTION_READY;
 import static android.car.CarRemoteDeviceManager.FLAG_OCCUPANT_ZONE_POWER_ON;
 import static android.car.CarRemoteDeviceManager.FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED;
@@ -106,7 +106,7 @@
  * There are 5 {@link AppState}s:
  * <ul>
  *   <li> App install states ({@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_INSTALLED},
- *        {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_VERSION},
+ *        {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_LONG_VERSION},
  *        {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_SIGNATURE}) are updated by the
  *        PackageChangeReceiver.
  *   <li> App running states ({@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_RUNNING},
@@ -720,7 +720,7 @@
                 try {
                     callback.onOccupantZoneStateChanged(occupantZone, newState);
                 } catch (RemoteException e) {
-                    Slogf.e(TAG, "Failed to notify %s of OccupantZoneState change",
+                    Slogf.e(TAG, e, "Failed to notify %s of OccupantZoneState change",
                             discoveringClient);
                 }
             }
@@ -928,7 +928,7 @@
                 try {
                     callback.onAppStateChanged(discoveredClient.occupantZone, newState);
                 } catch (RemoteException e) {
-                    Slogf.e(TAG, "Failed to notify %d of AppState change", discoveringClient);
+                    Slogf.e(TAG, e, "Failed to notify %d of AppState change", discoveringClient);
                 }
             }
         }
@@ -943,7 +943,7 @@
             // In single-SoC model, the peer client is guaranteed to have the same
             // signing info and long version code.
             // TODO(b/257118327): support multiple-SoC.
-            appState |= FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE;
+            appState |= FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE;
 
             RunningAppProcessInfo info =
                     getRunningAppProcessInfoAsUserLocked(clientId.packageName, clientId.userId);
@@ -1075,14 +1075,15 @@
         // TODO(b/257118327): support multiple-SoC.
         switch (state) {
             case PROCESS_RUNNING_IN_BACKGROUND:
-                return FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE
-                        | FLAG_CLIENT_RUNNING;
+                return FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION
+                        | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING;
             case PROCESS_RUNNING_IN_FOREGROUND:
-                return FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE
-                        | FLAG_CLIENT_RUNNING | FLAG_CLIENT_IN_FOREGROUND;
+                return FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION
+                        | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING
+                        | FLAG_CLIENT_IN_FOREGROUND;
             case PROCESS_NOT_RUNNING:
                 return isAppInstalledAsUserLocked(packageName, userId)
-                        ? FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION
+                        ? FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION
                         | FLAG_CLIENT_SAME_SIGNATURE
                         : INITIAL_APP_STATE;
 
@@ -1121,7 +1122,7 @@
     @ExcludeFromCodeCoverageGeneratedReport(reason = DEBUGGING_CODE)
     private static String appStateToString(@AppState int state) {
         boolean installed = (state & FLAG_CLIENT_INSTALLED) != 0;
-        boolean sameVersion = (state & FLAG_CLIENT_SAME_VERSION) != 0;
+        boolean sameVersion = (state & FLAG_CLIENT_SAME_LONG_VERSION) != 0;
         boolean sameSignature = (state & FLAG_CLIENT_SAME_SIGNATURE) != 0;
         boolean running = (state & FLAG_CLIENT_RUNNING) != 0;
         boolean inForeground = (state & FLAG_CLIENT_IN_FOREGROUND) != 0;
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/occupantconnection/CarOccupantConnectionManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/occupantconnection/CarOccupantConnectionManagerPermissionTest.java
index 2fd5a6b..d0aa5bc 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/occupantconnection/CarOccupantConnectionManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/occupantconnection/CarOccupantConnectionManagerPermissionTest.java
@@ -81,10 +81,6 @@
             }
 
             @Override
-            public void onRejected(@NonNull OccupantZoneInfo receiverZone, int rejectionReason) {
-            }
-
-            @Override
             public void onFailed(@NonNull OccupantZoneInfo receiverZone,
                     int connectionError) {
             }
diff --git a/tests/carservice_unit_test/src/android/car/occupantconnection/AbstractReceiverServiceUnitTest.java b/tests/carservice_unit_test/src/android/car/occupantconnection/AbstractReceiverServiceUnitTest.java
index 6aadadb..329fe1b 100644
--- a/tests/carservice_unit_test/src/android/car/occupantconnection/AbstractReceiverServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/android/car/occupantconnection/AbstractReceiverServiceUnitTest.java
@@ -26,6 +26,7 @@
 
 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
 import android.content.Intent;
+import android.content.pm.SigningInfo;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Pair;
@@ -113,7 +114,8 @@
 
     @Test
     public void testOnConnectionInitiated() throws RemoteException {
-        mBackendReceiver.onConnectionInitiated(mSenderZone, /* senderAppState= */ 0);
+        mBackendReceiver.onConnectionInitiated(mSenderZone, /* senderVersion= */ 0,
+                mock(SigningInfo.class));
 
         assertThat(mService.onConnectionInitiatedInvokedRecords.contains(mSenderZone)).isTrue();
     }
diff --git a/tests/carservice_unit_test/src/android/car/occupantconnection/TestReceiverService.java b/tests/carservice_unit_test/src/android/car/occupantconnection/TestReceiverService.java
index c4f24f0..f40601e 100644
--- a/tests/carservice_unit_test/src/android/car/occupantconnection/TestReceiverService.java
+++ b/tests/carservice_unit_test/src/android/car/occupantconnection/TestReceiverService.java
@@ -50,7 +50,7 @@
     }
 
     @Override
-    public void onConnectionInitiated(OccupantZoneInfo senderZone, int senderAppState) {
+    public void onConnectionInitiated(OccupantZoneInfo senderZone) {
         onConnectionInitiatedInvokedRecords.add(senderZone);
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/CarOccupantConnectionManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/CarOccupantConnectionManagerUnitTest.java
index 95531f0..b618488 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarOccupantConnectionManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarOccupantConnectionManagerUnitTest.java
@@ -18,6 +18,7 @@
 
 import static android.car.CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER;
 import static android.car.VehicleAreaSeat.SEAT_ROW_1_LEFT;
+import static android.car.occupantconnection.CarOccupantConnectionManager.CONNECTION_ERROR_USER_REJECTED;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -148,7 +149,7 @@
 
         mOccupantConnectionManager.requestConnection(mReceiverZone, mCallbackExecutor,
                 mock(ConnectionRequestCallback.class));
-        binderCallback[0].onRejected(mReceiverZone, /* rejectionReason= */ 0);
+        binderCallback[0].onFailed(mReceiverZone, CONNECTION_ERROR_USER_REJECTED);
 
         // The client can request another connection to the same occupant zone since the previous
         // request was rejected.
diff --git a/tests/carservice_unit_test/src/com/android/car/occupantconnection/CarOccupantConnectionServiceTest.java b/tests/carservice_unit_test/src/com/android/car/occupantconnection/CarOccupantConnectionServiceTest.java
index caf90b8..78e22dd 100644
--- a/tests/carservice_unit_test/src/com/android/car/occupantconnection/CarOccupantConnectionServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/occupantconnection/CarOccupantConnectionServiceTest.java
@@ -19,11 +19,6 @@
 import static android.car.Car.CAR_INTENT_ACTION_RECEIVER_SERVICE;
 import static android.car.CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER;
 import static android.car.CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_INSTALLED;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_IN_FOREGROUND;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_RUNNING;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_SIGNATURE;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_VERSION;
 import static android.car.VehicleAreaSeat.SEAT_ROW_1_LEFT;
 import static android.car.VehicleAreaSeat.SEAT_ROW_1_RIGHT;
 import static android.car.occupantconnection.CarOccupantConnectionManager.CONNECTION_ERROR_NOT_READY;
@@ -131,6 +126,7 @@
 
         mService = new CarOccupantConnectionService(mContext,
                 mOccupantZoneService,
+                mRemoteDeviceService,
                 mConnectingReceiverServices,
                 mConnectedReceiverServiceMap,
                 mReceiverServiceConnectionMap,
@@ -503,9 +499,8 @@
         assertThat(mPendingConnectionRequestMap.size()).isEqualTo(1);
 
         // The receiver service should be notified for the connection request.
-        verify(receiverService).onConnectionInitiated(mSenderZone,
-                /* senderAppState= */ FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION
-                | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING | FLAG_CLIENT_IN_FOREGROUND);
+        verify(receiverService).onConnectionInitiated(mSenderZone, /* senderVersion= */
+                0, /* senderSigningInfo= */ null);
     }
 
     @Test
@@ -532,9 +527,8 @@
         assertThat(connectionId.senderClient.packageName).isEqualTo(PACKAGE_NAME);
 
         // The receiver service should be notified for the connection request.
-        verify(receiverService).onConnectionInitiated(mSenderZone,
-                /* senderAppState= */ FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION
-                | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING | FLAG_CLIENT_IN_FOREGROUND);
+        verify(receiverService).onConnectionInitiated(mSenderZone, /* senderVersion= */
+                0, /* senderSigningInfo= */ null);
     }
 
     @Test
@@ -1028,10 +1022,6 @@
         }
 
         @Override
-        public void onRejected(OccupantZoneInfo receiverZone, int rejectionReason) {
-        }
-
-        @Override
         public void onFailed(OccupantZoneInfo receiverZone, int connectionError) {
         }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/occupantconnection/CarRemoteDeviceServiceTest.java b/tests/carservice_unit_test/src/com/android/car/occupantconnection/CarRemoteDeviceServiceTest.java
index f515666..bb0c8bf 100644
--- a/tests/carservice_unit_test/src/com/android/car/occupantconnection/CarRemoteDeviceServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/occupantconnection/CarRemoteDeviceServiceTest.java
@@ -25,8 +25,8 @@
 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_INSTALLED;
 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_IN_FOREGROUND;
 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_RUNNING;
+import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_LONG_VERSION;
 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_SIGNATURE;
-import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_VERSION;
 import static android.car.CarRemoteDeviceManager.FLAG_OCCUPANT_ZONE_CONNECTION_READY;
 import static android.car.CarRemoteDeviceManager.FLAG_OCCUPANT_ZONE_POWER_ON;
 import static android.car.VehicleAreaSeat.SEAT_ROW_1_LEFT;
@@ -230,7 +230,7 @@
         // Pretend that the peer app is installed in the beginning.
         ClientId peerClient = new ClientId(peerZone, USER_ID, PACKAGE_NAME);
         mAppStateMap.put(peerClient,
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
 
         // Then the peer app is uninstalled.
         Uri uri = mock(Uri.class);
@@ -254,7 +254,7 @@
         peerUserInfo.receiver.onReceive(mock(Context.class), intent);
 
         assertThat(mAppStateMap.get(peerClient)).isEqualTo(
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
     }
 
     @Test
@@ -283,7 +283,7 @@
         // Pretend that the peer app is installed in the beginning.
         ClientId peerClient = new ClientId(peerZone, USER_ID, PACKAGE_NAME);
         mAppStateMap.put(peerClient,
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
 
         // Nothing should happen if an app with another package name is uninstalled.
         String anotherPackageName = PACKAGE_NAME + "abc";
@@ -295,7 +295,7 @@
         peerUserInfo.receiver.onReceive(mock(Context.class), intent);
 
         assertThat(mAppStateMap.get(peerClient)).isEqualTo(
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
     }
 
     @Test
@@ -382,7 +382,7 @@
         mockAppInstalledAsUser(USER_ID, mOccupantZone);
 
         assertThat(mService.calculateAppState(clientId)).isEqualTo(
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
     }
 
     @Test
@@ -391,7 +391,7 @@
         mockAppRunningAsUser(USER_ID, PID, mOccupantZone, IMPORTANCE_CACHED);
 
         assertThat(mService.calculateAppState(clientId))
-                .isEqualTo(FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION
+                .isEqualTo(FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION
                         | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING);
     }
 
@@ -401,7 +401,7 @@
         mockAppRunningAsUser(USER_ID, PID, mOccupantZone, IMPORTANCE_FOREGROUND);
 
         assertThat(mService.calculateAppState(clientId))
-                .isEqualTo(FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION
+                .isEqualTo(FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION
                         | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING
                         | FLAG_CLIENT_IN_FOREGROUND);
     }
@@ -485,7 +485,7 @@
         mService.registerStateCallback(PACKAGE_NAME, mCallback);
 
         verify(mCallback).onAppStateChanged(peerZone1,
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
         verify(mCallback).onAppStateChanged(peerZone2, INITIAL_APP_STATE);
 
         verify(mCallback).onOccupantZoneStateChanged(peerZone1, FLAG_OCCUPANT_ZONE_POWER_ON);
@@ -531,7 +531,7 @@
                 /* foregroundActivities= */ true);
 
         verify(mCallback).onAppStateChanged(peerZone1,
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE
                         | FLAG_CLIENT_RUNNING | FLAG_CLIENT_IN_FOREGROUND);
 
         // Peer app2 is running in background.
@@ -541,7 +541,7 @@
                 /* foregroundActivities= */ false);
 
         verify(mCallback).onAppStateChanged(peerZone2,
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE
                         | FLAG_CLIENT_RUNNING);
 
         // Peer app1 is dead.
@@ -549,7 +549,7 @@
         processObserver[0].onProcessDied(peerPid1, userIdToUid(peerUserId1));
 
         verify(mCallback).onAppStateChanged(peerZone1,
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
     }
 
     @Test
@@ -582,7 +582,7 @@
         processObserver[0].onProcessDied(PID, userIdToUid(peerUserId));
 
         verify(mCallback).onAppStateChanged(peerZone,
-                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
+                FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE);
     }
 
     @Test