diff --git a/remoteauth/service/Android.bp b/remoteauth/service/Android.bp
index dfaf8cf117e69bf049c6c8ff6a1c398218758164..6e7b8d251433f5f2496318c2bad194bb6308b4f4 100644
--- a/remoteauth/service/Android.bp
+++ b/remoteauth/service/Android.bp
@@ -25,7 +25,7 @@ filegroup {
 java_library {
     name: "service-remoteauth-pre-jarjar",
     srcs: [":remoteauth-service-srcs"],
-    required: ["libremoteauth_jni_rust_defaults"],
+    required: ["libremoteauth_jni_rust"],
     defaults: [
         "enable-remoteauth-targets",
         "framework-system-server-module-defaults",
diff --git a/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthConnectionCache.java b/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthConnectionCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..49481a2856287494a3114fd62b29951042568834
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthConnectionCache.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.remoteauth;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.remoteauth.connectivity.Connection;
+import com.android.server.remoteauth.connectivity.ConnectionException;
+import com.android.server.remoteauth.connectivity.ConnectionInfo;
+import com.android.server.remoteauth.connectivity.ConnectivityManager;
+import com.android.server.remoteauth.connectivity.EventListener;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manages caching of remote devices {@link ConnectionInfo} and {@link Connection}.
+ *
+ * <p>Allows mapping between {@link ConnectionInfo#getConnectionId()} to {@link ConnectionInfo} and
+ * {@link Connection}
+ */
+public class RemoteAuthConnectionCache {
+    public static final String TAG = "RemoteAuthConCache";
+    private final Map<Integer, ConnectionInfo> mConnectionInfoMap = new ConcurrentHashMap<>();
+    private final Map<Integer, Connection> mConnectionMap = new ConcurrentHashMap<>();
+
+    private final ConnectivityManager mConnectivityManager;
+
+    public RemoteAuthConnectionCache(@NonNull ConnectivityManager connectivityManager) {
+        Preconditions.checkNotNull(connectivityManager);
+        this.mConnectivityManager = connectivityManager;
+    }
+
+    /** Returns the {@link ConnectivityManager}. */
+    ConnectivityManager getConnectivityManager() {
+        return mConnectivityManager;
+    }
+
+    /**
+     * Associates the connectionId with {@link ConnectionInfo}. Updates association with new value
+     * if already exists
+     *
+     * @param connectionInfo of the remote device
+     */
+    public void setConnectionInfo(@NonNull ConnectionInfo connectionInfo) {
+        Preconditions.checkNotNull(connectionInfo);
+        mConnectionInfoMap.put(connectionInfo.getConnectionId(), connectionInfo);
+    }
+
+    /** Returns {@link ConnectionInfo} associated with connectionId. */
+    public ConnectionInfo getConnectionInfo(int connectionId) {
+        return mConnectionInfoMap.get(connectionId);
+    }
+
+    /**
+     * Associates the connectionId with {@link Connection}. Updates association with new value if
+     * already exists
+     *
+     * @param connection to the remote device
+     */
+    public void setConnection(@NonNull Connection connection) {
+        Preconditions.checkNotNull(connection);
+        mConnectionMap.put(connection.getConnectionInfo().getConnectionId(), connection);
+    }
+
+    /**
+     * Returns {@link Connection} associated with connectionId. Uses {@link ConnectivityManager} to
+     * create and associate with new {@link Connection}, if mapping doesn't exist
+     *
+     * @param connectionId of the remote device
+     */
+    public Connection getConnection(int connectionId) {
+        return mConnectionMap.computeIfAbsent(
+                connectionId,
+                id -> {
+                    ConnectionInfo connectionInfo = getConnectionInfo(id);
+                    if (null == connectionInfo) {
+                        // TODO: Try accessing DB to fetch by connectionId
+                        Log.e(TAG, String.format("Unknown connectionId: %d", connectionId));
+                        return null;
+                    }
+                    try {
+                        Connection connection =
+                                mConnectivityManager.connect(
+                                        connectionInfo,
+                                        new EventListener() {
+                                            @Override
+                                            public void onDisconnect(
+                                                    @NonNull ConnectionInfo connectionInfo) {
+                                                removeConnection(connectionInfo.getConnectionId());
+                                                Log.i(
+                                                        TAG,
+                                                        String.format(
+                                                                "Disconnected from: %d",
+                                                                connectionInfo.getConnectionId()));
+                                            }
+                                        });
+                        if (null == connection) {
+                            Log.e(TAG, String.format("Failed to connect: %d", connectionId));
+                            return null;
+                        }
+                        return connection;
+                    } catch (ConnectionException e) {
+                        Log.e(
+                                TAG,
+                                String.format("Failed to create connection to %d.", connectionId),
+                                e);
+                        return null;
+                    }
+                });
+    }
+
+    /**
+     * Removes {@link Connection} from cache.
+     *
+     * @param connectionId of the remote device
+     */
+    public void removeConnection(int connectionId) {
+        if (null != mConnectionMap.remove(connectionId)) {
+            Log.i(
+                    TAG,
+                    String.format("Connection associated with id: %d was removed", connectionId));
+        }
+    }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthPlatform.java b/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthPlatform.java
new file mode 100644
index 0000000000000000000000000000000000000000..a61aeff7a5d432eece02585907964269b45ff34f
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthPlatform.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.remoteauth;
+
+import android.util.Log;
+
+import com.android.server.remoteauth.connectivity.Connection;
+import com.android.server.remoteauth.jni.INativeRemoteAuthService;
+
+/** Implementation of the {@link INativeRemoteAuthService.IPlatform} interface. */
+public class RemoteAuthPlatform implements INativeRemoteAuthService.IPlatform {
+    public static final String TAG = "RemoteAuthPlatform";
+    private final RemoteAuthConnectionCache mConnectionCache;
+
+    public RemoteAuthPlatform(RemoteAuthConnectionCache connectionCache) {
+        mConnectionCache = connectionCache;
+    }
+
+    /**
+     * Sends message to the remote device via {@link Connection} created by
+     * {@link com.android.server.remoteauth.connectivity.ConnectivityManager}.
+     *
+     * @param connectionId connection ID of the {@link android.remoteauth.RemoteAuthenticator}
+     * @param request payload of the request
+     * @param callback to be used to pass the response result
+     * @return true if succeeded, false otherwise.
+     * @hide
+     */
+    @Override
+    public boolean sendRequest(int connectionId, byte[] request, ResponseCallback callback) {
+        Connection connection = mConnectionCache.getConnection(connectionId);
+        if (null == connection) {
+            Log.e(TAG, String.format("Failed to get a connection for: %d", connectionId));
+            return false;
+        }
+        connection.sendRequest(
+                request,
+                new Connection.MessageResponseCallback() {
+                    @Override
+                    public void onSuccess(byte[] buffer) {
+                        callback.onSuccess(buffer);
+                    }
+
+                    @Override
+                    public void onFailure(@Connection.ErrorCode int errorCode) {
+                        callback.onFailure(errorCode);
+                    }
+                });
+        return true;
+    }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthService.java b/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthService.java
index 9374ace3776c3887c815bc0843e26362bd4db671..619785f517dd8038458857482e1ce30ed450f0a9 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthService.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/RemoteAuthService.java
@@ -65,7 +65,7 @@ public class RemoteAuthService extends IRemoteAuthService.Stub {
     }
 
     private static void checkPermission(Context context, String permission) {
-        context.enforceCallingOrSelfPermission(permission,
-                "Must have " + permission + " permission.");
+        context.enforceCallingOrSelfPermission(
+                permission, "Must have " + permission + " permission.");
     }
 }
diff --git a/remoteauth/service/java/com/android/server/remoteauth/connectivity/EventListener.java b/remoteauth/service/java/com/android/server/remoteauth/connectivity/EventListener.java
index d07adb1f23e0f996b708fe24578431509e856b19..8ec851a0964a17b66260c95245df4f66ae4f4553 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/connectivity/EventListener.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/connectivity/EventListener.java
@@ -21,7 +21,7 @@ import android.annotation.NonNull;
 /**
  * Listens to the events from underlying transport.
  */
-interface EventListener {
+public interface EventListener {
     /** Called when remote device is disconnected from the underlying transport. */
     void onDisconnect(@NonNull ConnectionInfo connectionInfo);
 }
diff --git a/remoteauth/service/java/com/android/server/remoteauth/jni/INativeRemoteAuthService.java b/remoteauth/service/java/com/android/server/remoteauth/jni/INativeRemoteAuthService.java
index f79ec7e4f2bb4fcab0cdebe4663f7d544554962b..4aaa7605d7c97f6869198023b0b276a1ddb9803a 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/jni/INativeRemoteAuthService.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/jni/INativeRemoteAuthService.java
@@ -34,10 +34,10 @@ public interface INativeRemoteAuthService {
          * @param connectionId connection ID of the {@link android.remoteauth.RemoteAuthenticator}
          * @param request payload of the request
          * @param callback to be used to pass the response result
-         *
+         * @return true if succeeded, false otherwise.
          * @hide
          */
-        void sendRequest(int connectionId, byte[] request, ResponseCallback callback);
+        boolean sendRequest(int connectionId, byte[] request, ResponseCallback callback);
 
         /**
          * Interface for a callback to send a response back.
@@ -49,7 +49,6 @@ public interface INativeRemoteAuthService {
              * Invoked when message sending succeeds.
              *
              * @param response contains response
-             *
              * @hide
              */
             void onSuccess(byte[] response);
@@ -58,7 +57,6 @@ public interface INativeRemoteAuthService {
              * Invoked when message sending fails.
              *
              * @param errorCode indicating the error
-             *
              * @hide
              */
             void onFailure(int errorCode);
diff --git a/remoteauth/service/java/com/android/server/remoteauth/jni/NativeRemoteAuthService.java b/remoteauth/service/java/com/android/server/remoteauth/jni/NativeRemoteAuthService.java
index 39c2a74b4b6fd701032613651db4c32c9868b5fd..a676562374d46dadb703d4a351776b4a8bd08e13 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/jni/NativeRemoteAuthService.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/jni/NativeRemoteAuthService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.remoteauth.jni;
 
+import android.util.Log;
+
 import com.android.internal.annotations.Keep;
 import com.android.server.remoteauth.jni.INativeRemoteAuthService.IPlatform;
 
@@ -53,12 +55,13 @@ public class NativeRemoteAuthService {
      *     platform
      * @param platformHandle a handle associated with the platform object, used to pass the response
      *     to the specific platform
-     *
      * @hide
      */
     @Keep
     public void sendRequest(
             int connectionId, byte[] request, long responseHandle, long platformHandle) {
+        Log.d(TAG, String.format("sendRequest with connectionId: %d, rh: %d, ph: %d",
+                connectionId, responseHandle, platformHandle));
         mPlatform.sendRequest(
                 connectionId,
                 request,
diff --git a/remoteauth/service/java/com/android/server/remoteauth/jni/PlatformBadHandleException.java b/remoteauth/service/java/com/android/server/remoteauth/jni/PlatformBadHandleException.java
index 3ae9838b2ad0f9188ad0f72793fbd3aba308907f..4bf930cabe0a670d6eb4f9fede51ac8226da43a3 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/jni/PlatformBadHandleException.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/jni/PlatformBadHandleException.java
@@ -21,6 +21,7 @@
 package com.android.server.remoteauth.jni;
 
 import com.android.internal.annotations.Keep;
+
 /**
  * Exception thrown by native platform rust implementation of {@link
  * com.android.server.remoteauth.RemoteAuthService}.
diff --git a/remoteauth/service/jni/Android.bp b/remoteauth/service/jni/Android.bp
index e6e8a437e17788fbcba38e0c085f2079d6fc5cf1..a95a8fb90d059fadea119fa5b4ef931d2bdfb455 100644
--- a/remoteauth/service/jni/Android.bp
+++ b/remoteauth/service/jni/Android.bp
@@ -30,6 +30,12 @@ rust_defaults {
     host_supported: true,
 }
 
+rust_ffi_shared {
+    name: "libremoteauth_jni_rust",
+    defaults: ["libremoteauth_jni_rust_defaults"],
+    rustlibs: [],
+}
+
 rust_test {
     name: "libremoteauth_jni_rust_tests",
     defaults: ["libremoteauth_jni_rust_defaults"],
diff --git a/remoteauth/service/jni/src/lib.rs b/remoteauth/service/jni/src/lib.rs
index a816c947fdafe2bf0d97dd9709a915ae0a9969b1..c6f8c725c5bc0de76c3f93e5f2c576cb098b0178 100644
--- a/remoteauth/service/jni/src/lib.rs
+++ b/remoteauth/service/jni/src/lib.rs
@@ -21,5 +21,7 @@ mod jnames;
 mod unique_jvm;
 mod utils;
 
+/// Implementation of JNI platform functionality.
 pub mod remoteauth_jni_android_platform;
+/// Implementation of JNI protocol functionality.
 pub mod remoteauth_jni_android_protocol;
diff --git a/remoteauth/service/jni/src/remoteauth_jni_android_platform.rs b/remoteauth/service/jni/src/remoteauth_jni_android_platform.rs
index 1967c1a3a8f93c48ea1bc4c70a38b95dc1afbd05..0a189f2de77cbb67af8297163dd7d16b9ae1710a 100644
--- a/remoteauth/service/jni/src/remoteauth_jni_android_platform.rs
+++ b/remoteauth/service/jni/src/remoteauth_jni_android_platform.rs
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+//! Implementation of JNI platform functionality.
 use crate::jnames::{SEND_REQUEST_MNAME, SEND_REQUEST_MSIG};
 use crate::unique_jvm;
 use anyhow::anyhow;
@@ -73,11 +74,15 @@ fn insert_platform_handle(handle: i64, item: Arc<Mutex<JavaPlatform>>) {
     HANDLE_MAPPING.lock().unwrap().insert(handle, Arc::clone(&item));
 }
 
+/// Reports a response from remote device.
 pub trait ResponseCallback {
+    /// Invoked upon successful response
     fn on_response(&mut self, response: Vec<u8>);
+    /// Invoked upon failure
     fn on_error(&mut self, error_code: i32);
 }
 
+/// Trait to platform functionality
 pub trait Platform {
     /// Send a binary message to the remote with the given connection id and return the response.
     fn send_request(
@@ -89,6 +94,7 @@ pub trait Platform {
 }
 //////////////////////////////////
 
+/// Implementation of Platform trait
 pub struct JavaPlatform {
     platform_handle: i64,
     vm: &'static Arc<JavaVM>,
@@ -99,7 +105,7 @@ pub struct JavaPlatform {
 }
 
 impl JavaPlatform {
-    // Method to create JavaPlatform
+    /// Creates JavaPlatform and associates with unique handle id
     pub fn create(
         java_platform_native: JObject<'_>,
     ) -> Result<Arc<Mutex<impl Platform>>, JNIError> {
@@ -219,6 +225,7 @@ impl JavaPlatform {
     }
 }
 
+/// Returns successful response from remote device
 #[no_mangle]
 pub extern "system" fn Java_com_android_server_remoteauth_jni_NativeRemoteAuthJavaPlatform_native_on_send_request_success(
     env: JNIEnv,
@@ -250,6 +257,7 @@ fn native_on_send_request_success(
     }
 }
 
+/// Notifies about failure to receive a response from remote device
 #[no_mangle]
 pub extern "system" fn Java_com_android_server_remoteauth_jni_NativeRemoteAuthJavaPlatform_native_on_send_request_error(
     env: JNIEnv,
diff --git a/remoteauth/service/jni/src/remoteauth_jni_android_protocol.rs b/remoteauth/service/jni/src/remoteauth_jni_android_protocol.rs
index 1f7320744d96e06c05f345f1c1494b6e1a1c095b..ac2eb8cd9a52dff8fb5525d8058195cf25ef4fe8 100644
--- a/remoteauth/service/jni/src/remoteauth_jni_android_protocol.rs
+++ b/remoteauth/service/jni/src/remoteauth_jni_android_protocol.rs
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
+//! Implementation of JNI protocol functionality.
 use crate::unique_jvm;
 use crate::utils::get_boolean_result;
 use jni::objects::JObject;
 use jni::sys::jboolean;
 use jni::JNIEnv;
 
+/// Initialize native library. Captures Java VM:
 #[no_mangle]
 pub extern "system" fn Java_com_android_server_remoteauth_jni_NativeRemoteAuthJavaPlatform_native_init(
     env: JNIEnv,
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/RemoteAuthConnectionCacheTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/RemoteAuthConnectionCacheTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..00f35d3a13a51faa5c533b922a6e6bbd7aa49008
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/RemoteAuthConnectionCacheTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.remoteauth;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.remoteauth.connectivity.Connection;
+import com.android.server.remoteauth.connectivity.ConnectionException;
+import com.android.server.remoteauth.connectivity.ConnectionInfo;
+import com.android.server.remoteauth.connectivity.ConnectivityManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Unit test for {@link com.android.server.remoteauth.RemoteAuthConnectionCache} */
+@RunWith(AndroidJUnit4.class)
+public class RemoteAuthConnectionCacheTest {
+    @Mock private Connection mConnection;
+    @Mock private ConnectionInfo mConnectionInfo;
+    @Mock private ConnectivityManager mConnectivityManager;
+    private RemoteAuthConnectionCache mConnectionCache;
+
+    private static final int CONNECTION_ID = 1;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        doReturn(CONNECTION_ID).when(mConnectionInfo).getConnectionId();
+        doReturn(mConnectionInfo).when(mConnection).getConnectionInfo();
+        mConnectionCache = new RemoteAuthConnectionCache(mConnectivityManager);
+    }
+
+    @Test
+    public void testCreateCache_managerIsNull() {
+        assertThrows(NullPointerException.class, () -> new RemoteAuthConnectionCache(null));
+    }
+
+    @Test
+    public void testGetManager_managerExists() {
+        assertEquals(mConnectivityManager, mConnectionCache.getConnectivityManager());
+    }
+
+    @Test
+    public void testSetConnectionInfo_infoIsNull() {
+        assertThrows(NullPointerException.class, () -> mConnectionCache.setConnectionInfo(null));
+    }
+
+    @Test
+    public void testSetConnectionInfo_infoIsValid() {
+        mConnectionCache.setConnectionInfo(mConnectionInfo);
+
+        assertEquals(mConnectionInfo, mConnectionCache.getConnectionInfo(CONNECTION_ID));
+    }
+
+    @Test
+    public void testSetConnection_connectionIsNull() {
+        assertThrows(NullPointerException.class, () -> mConnectionCache.setConnection(null));
+    }
+
+    @Test
+    public void testGetConnection_connectionAlreadyExists() {
+        mConnectionCache.setConnection(mConnection);
+
+        assertEquals(mConnection, mConnectionCache.getConnection(CONNECTION_ID));
+    }
+
+    @Test
+    public void testGetConnection_connectionInfoDoesntExists() {
+        assertNull(mConnectionCache.getConnection(CONNECTION_ID));
+    }
+
+    @Test
+    public void testGetConnection_failedToConnect() {
+        mConnectionCache.setConnectionInfo(mConnectionInfo);
+        doReturn(null).when(mConnectivityManager).connect(eq(mConnectionInfo), anyObject());
+
+        assertNull(mConnectionCache.getConnection(CONNECTION_ID));
+    }
+
+    @Test
+    public void testGetConnection_failedToConnectException() {
+        mConnectionCache.setConnectionInfo(mConnectionInfo);
+        doThrow(ConnectionException.class)
+                .when(mConnectivityManager)
+                .connect(eq(mConnectionInfo), anyObject());
+
+        assertNull(mConnectionCache.getConnection(CONNECTION_ID));
+    }
+
+    @Test
+    public void testGetConnection_connectionSucceed() {
+        mConnectionCache.setConnectionInfo(mConnectionInfo);
+        doReturn(mConnection).when(mConnectivityManager).connect(eq(mConnectionInfo), anyObject());
+
+        assertEquals(mConnection, mConnectionCache.getConnection(CONNECTION_ID));
+    }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/RemoteAuthPlatformTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/RemoteAuthPlatformTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8975d52b8500da15095fb06dcab04941ece846d4
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/RemoteAuthPlatformTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.remoteauth;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.remoteauth.connectivity.Connection;
+import com.android.server.remoteauth.jni.INativeRemoteAuthService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Unit test for {@link com.android.server.remoteauth.RemoteAuthPlatform} */
+@RunWith(AndroidJUnit4.class)
+public class RemoteAuthPlatformTest {
+    @Mock private Connection mConnection;
+    @Mock private RemoteAuthConnectionCache mConnectionCache;
+    private RemoteAuthPlatform mPlatform;
+    private static final int CONNECTION_ID = 1;
+    private static final byte[] REQUEST = new byte[] {(byte) 0x01};
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mPlatform = new RemoteAuthPlatform(mConnectionCache);
+    }
+
+    @Test
+    public void testSendRequest_connectionIsNull() {
+        doReturn(null).when(mConnectionCache).getConnection(anyInt());
+        assertFalse(
+                mPlatform.sendRequest(
+                        CONNECTION_ID,
+                        REQUEST,
+                        new INativeRemoteAuthService.IPlatform.ResponseCallback() {
+                            @Override
+                            public void onSuccess(byte[] response) {}
+
+                            @Override
+                            public void onFailure(int errorCode) {}
+                        }));
+    }
+
+    @Test
+    public void testSendRequest_connectionExists() {
+        doReturn(mConnection).when(mConnectionCache).getConnection(anyInt());
+        assertTrue(
+                mPlatform.sendRequest(
+                        CONNECTION_ID,
+                        REQUEST,
+                        new INativeRemoteAuthService.IPlatform.ResponseCallback() {
+                            @Override
+                            public void onSuccess(byte[] response) {}
+
+                            @Override
+                            public void onFailure(int errorCode) {}
+                        }));
+        verify(mConnection, times(1)).sendRequest(eq(REQUEST), anyObject());
+    }
+}