Put controlee info to applet.

Bug: 200678121
Test: atest com.android.server.uwb
Change-Id: I70fed9db0f8381d000f004c49eef011c9c6029ba
diff --git a/service/java/com/android/server/uwb/secure/ControleeResponderSession.java b/service/java/com/android/server/uwb/secure/ControleeResponderSession.java
index 237cab1..f0c9a2e 100644
--- a/service/java/com/android/server/uwb/secure/ControleeResponderSession.java
+++ b/service/java/com/android/server/uwb/secure/ControleeResponderSession.java
@@ -27,7 +27,9 @@
 import com.android.server.uwb.secure.csml.CsmlUtil;
 import com.android.server.uwb.secure.csml.DispatchResponse;
 import com.android.server.uwb.secure.csml.GetDoCommand;
+import com.android.server.uwb.secure.csml.PutDoCommand;
 import com.android.server.uwb.secure.csml.SessionData;
+import com.android.server.uwb.secure.iso7816.TlvDatum;
 import com.android.server.uwb.secure.iso7816.TlvParser;
 import com.android.server.uwb.util.DataTypeConversionUtil;
 
@@ -48,6 +50,30 @@
     }
 
     @Override
+    protected void handleFiRaSecureChannelEstablished() {
+        super.handleFiRaSecureChannelEstablished();
+
+        PutDoCommand putControleeInfoCommand = PutDoCommand.build(
+                CsmlUtil.constructGetOrPutDoTlv(
+                        new TlvDatum(CsmlUtil.CONTROLEE_INFO_DO_TAG,
+                                mRunningProfileSessionInfo.controleeInfo.get().toBytes())));
+        mFiRaSecureChannel.sendLocalFiRaCommand(putControleeInfoCommand,
+                new FiRaSecureChannel.ExternalRequestCallback() {
+                    @Override
+                    public void onSuccess(@NonNull byte[] responseData) {
+                        logd("controlee info is sent to applet.");
+                    }
+
+                    @Override
+                    public void onFailure() {
+                        logw("failed to send controlee info to applet.");
+                        terminateSession();
+                        mSessionCallback.onSessionAborted();
+                    }
+                });
+    }
+
+    @Override
     protected boolean onDispatchResponseReceived(@NonNull DispatchResponse dispatchResponse) {
         DispatchResponse.RdsAvailableNotification rdsAvailable = null;
         for (DispatchResponse.Notification notification : dispatchResponse.notifications) {
diff --git a/service/tests/src/com/android/server/uwb/secure/ControleeResponderSessionTest.java b/service/tests/src/com/android/server/uwb/secure/ControleeResponderSessionTest.java
index 2c77ece..fb55fd8 100644
--- a/service/tests/src/com/android/server/uwb/secure/ControleeResponderSessionTest.java
+++ b/service/tests/src/com/android/server/uwb/secure/ControleeResponderSessionTest.java
@@ -21,14 +21,19 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
 import android.os.test.TestLooper;
 
 import com.android.server.uwb.pm.RunningProfileSessionInfo;
+import com.android.server.uwb.secure.csml.ControleeInfo;
 import com.android.server.uwb.secure.csml.DispatchResponse;
+import com.android.server.uwb.secure.csml.FiRaCommand;
+import com.android.server.uwb.secure.csml.UwbCapability;
 import com.android.server.uwb.secure.iso7816.ResponseApdu;
 import com.android.server.uwb.util.DataTypeConversionUtil;
+import com.android.server.uwb.util.ObjectIdentifier;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -37,6 +42,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Optional;
+
 public class ControleeResponderSessionTest {
     @Mock
     private FiRaSecureChannel mFiRaSecureChannel;
@@ -55,18 +62,26 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+    }
+
+    private void doInit(RunningProfileSessionInfo runningProfileSessionInfo) {
 
         mControleeResponderSession = new ControleeResponderSession(
                 mTestLooper.getLooper(), mFiRaSecureChannel, mSecureSessionCallback,
-                mRunningProfileSessionInfo);
+                runningProfileSessionInfo);
 
         mControleeResponderSession.startSession();
 
         verify(mFiRaSecureChannel).init(mSecureChannelCallbackCaptor.capture());
     }
 
+    private void doInit() {
+        doInit(mRunningProfileSessionInfo);
+    }
+
     @Test
     public void onSetupError() {
+        doInit();
         mSecureChannelCallbackCaptor.getValue()
                 .onSetUpError(FiRaSecureChannel.SetupError.OPEN_SE_CHANNEL);
 
@@ -75,7 +90,33 @@
     }
 
     @Test
+    public void onSessionEstablishedPutControleeInfoFail() {
+        RunningProfileSessionInfo runningProfileSessionInfo =
+                new RunningProfileSessionInfo.Builder(
+                        mock(UwbCapability.class), mock(ObjectIdentifier.class))
+                        .setControleeInfo(new ControleeInfo.Builder().build())
+                        .build();
+        doInit(runningProfileSessionInfo);
+        mSecureChannelCallbackCaptor.getValue().onEstablished(Optional.empty());
+
+        ArgumentCaptor<FiRaCommand> cmdCaptor = ArgumentCaptor.forClass(FiRaCommand.class);
+        ArgumentCaptor<FiRaSecureChannel.ExternalRequestCallback> cbCaptor =
+                ArgumentCaptor.forClass(FiRaSecureChannel.ExternalRequestCallback.class);
+
+        verify(mFiRaSecureChannel).sendLocalFiRaCommand(cmdCaptor.capture(), cbCaptor.capture());
+        assertThat(cmdCaptor.getValue().getCommandApdu().getIns()).isEqualTo((byte) 0xDB);
+        assertThat(cmdCaptor.getValue().getCommandApdu().getP1()).isEqualTo((byte) 0x3F);
+        assertThat(cmdCaptor.getValue().getCommandApdu().getP2()).isEqualTo((byte) 0xFF);
+
+        cbCaptor.getValue().onFailure();
+        mTestLooper.dispatchAll();
+        verify(mFiRaSecureChannel).terminateLocally();
+        verify(mSecureSessionCallback).onSessionAborted();
+    }
+
+    @Test
     public void onTerminated() {
+        doInit();
         mSecureChannelCallbackCaptor.getValue()
                 .onTerminated(/*withError=*/ false);
 
@@ -84,6 +125,7 @@
 
     @Test
     public void terminateSession() {
+        doInit();
         mControleeResponderSession.terminateSession();
         mTestLooper.dispatchAll();
 
@@ -92,6 +134,7 @@
 
     @Test
     public void abortSessionNotification() {
+        doInit();
         byte[] data = DataTypeConversionUtil.hexStringToByteArray(
                 "71038001FF"); // transaction complete with errors
         ResponseApdu responseApdu = ResponseApdu.fromDataAndStatusWord(data, 0x9000);
@@ -106,6 +149,7 @@
 
     @Test
     public void abortSessionWithWrongDispatchResponseStatusWord() {
+        doInit();
         ResponseApdu responseApdu = ResponseApdu.fromDataAndStatusWord(new byte[0], 0x9032);
         DispatchResponse dispatchResponse = DispatchResponse.fromResponseApdu(responseApdu);
 
@@ -118,6 +162,7 @@
 
     @Test
     public void rdsAvailableNotificationWithSessionData() {
+        doInit();
         byte[] data = DataTypeConversionUtil.hexStringToByteArray(
                 "711B80018181029000E112800100810102820A010107BF780480020101");
         ResponseApdu responseApdu = ResponseApdu.fromDataAndStatusWord(data, 0x9000);
@@ -130,6 +175,7 @@
 
     @Test
     public void rdsAvailableNotificationWithSessionDataInApplet() {
+        doInit();
         byte[] data = DataTypeConversionUtil.hexStringToByteArray(
                 "711380018181029000E10A80010081010282020101");
         ResponseApdu responseApdu = ResponseApdu.fromDataAndStatusWord(data, 0x9000);
@@ -149,6 +195,7 @@
 
     @Test
     public void failedToGetSessionDataFromApplet() {
+        doInit();
         byte[] data = DataTypeConversionUtil.hexStringToByteArray(
                 "711380018181029000E10A80010081010282020101");
         ResponseApdu responseApdu = ResponseApdu.fromDataAndStatusWord(data, 0x9000);
@@ -167,6 +214,7 @@
 
     @Test
     public void outboundDataToRemote() {
+        doInit();
         byte[] data = DataTypeConversionUtil.hexStringToByteArray(
                 "710780018081029000");
         ResponseApdu responseApdu = ResponseApdu.fromDataAndStatusWord(data, 0x9000);