Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ed762bd authored by Hyundo Moon's avatar Hyundo Moon Committed by Gerrit Code Review
Browse files

Merge "Add SapRilReceiverTest"

parents 958483f5 f3a3b87f
Loading
Loading
Loading
Loading
+0 −54
Original line number Diff line number Diff line
@@ -279,60 +279,6 @@ public class SapRilReceiver {
        }
    }

    /**
     * Read the message into buffer
     * @param is
     * @param buffer
     * @return the length of the message
     * @throws IOException
     */
    private static int readMessage(InputStream is, byte[] buffer) throws IOException {
        int countRead;
        int offset;
        int remaining;
        int messageLength;

        // Read in the length of the message
        offset = 0;
        remaining = 4;
        do {
            countRead = is.read(buffer, offset, remaining);

            if (countRead < 0) {
                Log.e(TAG, "Hit EOS reading message length");
                return -1;
            }

            offset += countRead;
            remaining -= countRead;
        } while (remaining > 0);

        messageLength =
                ((buffer[0] & 0xff) << 24) | ((buffer[1] & 0xff) << 16) | ((buffer[2] & 0xff) << 8)
                        | (buffer[3] & 0xff);
        if (VERBOSE) {
            Log.e(TAG, "Message length found to be: " + messageLength);
        }
        // Read the message
        offset = 0;
        remaining = messageLength;
        do {
            countRead = is.read(buffer, offset, remaining);

            if (countRead < 0) {
                Log.e(TAG,
                        "Hit EOS reading message.  messageLength=" + messageLength + " remaining="
                                + remaining);
                return -1;
            }

            offset += countRead;
            remaining -= countRead;
        } while (remaining > 0);

        return messageLength;
    }

    /**
     * Notify SapServer that the RIL socket is connected
     */
+435 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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.bluetooth.sap;

import static com.android.bluetooth.sap.SapMessage.CON_STATUS_OK;
import static com.android.bluetooth.sap.SapMessage.DISC_GRACEFULL;
import static com.android.bluetooth.sap.SapMessage.ID_CONNECT_RESP;
import static com.android.bluetooth.sap.SapMessage.ID_DISCONNECT_RESP;
import static com.android.bluetooth.sap.SapMessage.ID_POWER_SIM_OFF_REQ;
import static com.android.bluetooth.sap.SapMessage.ID_POWER_SIM_OFF_RESP;
import static com.android.bluetooth.sap.SapMessage.ID_POWER_SIM_ON_REQ;
import static com.android.bluetooth.sap.SapMessage.ID_POWER_SIM_ON_RESP;
import static com.android.bluetooth.sap.SapMessage.ID_RESET_SIM_RESP;
import static com.android.bluetooth.sap.SapMessage.ID_RIL_UNKNOWN;
import static com.android.bluetooth.sap.SapMessage.ID_RIL_UNSOL_DISCONNECT_IND;
import static com.android.bluetooth.sap.SapMessage.ID_SET_TRANSPORT_PROTOCOL_RESP;
import static com.android.bluetooth.sap.SapMessage.ID_STATUS_IND;
import static com.android.bluetooth.sap.SapMessage.ID_TRANSFER_APDU_RESP;
import static com.android.bluetooth.sap.SapMessage.ID_TRANSFER_ATR_RESP;
import static com.android.bluetooth.sap.SapMessage.ID_TRANSFER_CARD_READER_STATUS_RESP;
import static com.android.bluetooth.sap.SapMessage.RESULT_OK;
import static com.android.bluetooth.sap.SapMessage.STATUS_CARD_INSERTED;
import static com.android.bluetooth.sap.SapServer.ISAP_GET_SERVICE_DELAY_MILLIS;
import static com.android.bluetooth.sap.SapServer.SAP_MSG_RFC_REPLY;
import static com.android.bluetooth.sap.SapServer.SAP_MSG_RIL_CONNECT;
import static com.android.bluetooth.sap.SapServer.SAP_MSG_RIL_IND;
import static com.android.bluetooth.sap.SapServer.SAP_PROXY_DEAD;
import static com.android.bluetooth.sap.SapServer.SAP_RIL_SOCK_CLOSED;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.any;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;

import android.hardware.radio.V1_0.ISap;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;

import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;

import java.util.ArrayList;
import java.util.Arrays;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class SapRilReceiverTest {

    private static final long TIMEOUT_MS = 1_000;

    private HandlerThread mHandlerThread;
    private Handler mServerMsgHandler;

    @Spy
    private TestHandlerCallback mCallback = new TestHandlerCallback();

    @Mock
    private Handler mServiceHandler;

    @Mock
    private ISap mSapProxy;

    private SapRilReceiver mReceiver;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        mHandlerThread = new HandlerThread("SapRilReceiverTest");
        mHandlerThread.start();

        mServerMsgHandler = new Handler(mHandlerThread.getLooper(), mCallback);
        mReceiver = new SapRilReceiver(mServerMsgHandler, mServiceHandler);
        mReceiver.mSapProxy = mSapProxy;
    }

    @After
    public void tearDown() {
        mHandlerThread.quit();
    }

    @Test
    public void getSapProxyLock() {
        assertThat(mReceiver.getSapProxyLock()).isNotNull();
    }

    @Test
    public void resetSapProxy() throws Exception {
        mReceiver.resetSapProxy();

        assertThat(mReceiver.mSapProxy).isNull();
        verify(mSapProxy).unlinkToDeath(any());
    }

    @Test
    public void notifyShutdown() throws Exception {
        mReceiver.notifyShutdown();

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_RIL_SOCK_CLOSED), any());
    }

    @Test
    public void sendRilConnectMessage() throws Exception {
        mReceiver.sendRilConnectMessage();

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RIL_CONNECT), any());
    }

    @Test
    public void serviceDied() throws Exception {
        long cookie = 1;
        mReceiver.mSapProxyDeathRecipient.serviceDied(cookie);

        verify(mCallback, timeout(ISAP_GET_SERVICE_DELAY_MILLIS + TIMEOUT_MS))
                .receiveMessage(eq(SAP_PROXY_DEAD), argThat(
                        arg -> (arg instanceof Long) && ((Long) arg == cookie)
                ));
    }

    @Test
    public void callback_connectResponse() throws Exception {
        int token = 1;
        int sapConnectRsp = CON_STATUS_OK;
        int maxMsgSize = 512;
        mReceiver.mSapCallback.connectResponse(token, sapConnectRsp, maxMsgSize);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_CONNECT_RESP
                                && sapMsg.getConnectionStatus() == sapConnectRsp;
                    }
                }
        ));
    }

    @Test
    public void callback_disconnectResponse() throws Exception {
        int token = 1;
        mReceiver.mSapCallback.disconnectResponse(token);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_DISCONNECT_RESP;
                    }
                }
        ));
    }

    @Test
    public void callback_disconnectIndication() throws Exception {
        int token = 1;
        int disconnectType = DISC_GRACEFULL;
        mReceiver.mSapCallback.disconnectIndication(token, disconnectType);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RIL_IND), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_RIL_UNSOL_DISCONNECT_IND
                                && sapMsg.getDisconnectionType() == disconnectType;
                    }
                }
        ));
    }

    @Test
    public void callback_apduResponse() throws Exception {
        int token = 1;
        int resultCode = RESULT_OK;
        byte[] apduRsp = new byte[]{0x03, 0x04};
        ArrayList<Byte> apduRspList = new ArrayList<>();
        for (byte b : apduRsp) {
            apduRspList.add(b);
        }

        mReceiver.mSapCallback.apduResponse(token, resultCode, apduRspList);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_TRANSFER_APDU_RESP
                                && sapMsg.getResultCode() == resultCode
                                && Arrays.equals(sapMsg.getApduResp(), apduRsp);
                    }
                }
        ));
    }

    @Test
    public void callback_transferAtrResponse() throws Exception {
        int token = 1;
        int resultCode = RESULT_OK;
        byte[] atr = new byte[]{0x03, 0x04};
        ArrayList<Byte> atrList = new ArrayList<>();
        for (byte b : atr) {
            atrList.add(b);
        }

        mReceiver.mSapCallback.transferAtrResponse(token, resultCode, atrList);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_TRANSFER_ATR_RESP
                                && sapMsg.getResultCode() == resultCode
                                && Arrays.equals(sapMsg.getAtr(), atr);
                    }
                }
        ));
    }

    @Test
    public void callback_powerResponse_powerOff() throws Exception {
        int token = 1;
        int reqType = ID_POWER_SIM_OFF_REQ;
        int resultCode = RESULT_OK;
        SapMessage.sOngoingRequests.clear();
        SapMessage.sOngoingRequests.put(token, reqType);

        mReceiver.mSapCallback.powerResponse(token, resultCode);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_POWER_SIM_OFF_RESP
                                && sapMsg.getResultCode() == resultCode;
                    }
                }
        ));
    }

    @Test
    public void callback_powerResponse_powerOn() throws Exception {
        int token = 1;
        int reqType = ID_POWER_SIM_ON_REQ;
        int resultCode = RESULT_OK;
        SapMessage.sOngoingRequests.clear();
        SapMessage.sOngoingRequests.put(token, reqType);

        mReceiver.mSapCallback.powerResponse(token, resultCode);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_POWER_SIM_ON_RESP
                                && sapMsg.getResultCode() == resultCode;
                    }
                }
        ));
    }

    @Test
    public void callback_resetSimResponse() throws Exception {
        int token = 1;
        int resultCode = RESULT_OK;

        mReceiver.mSapCallback.resetSimResponse(token, resultCode);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_RESET_SIM_RESP
                                && sapMsg.getResultCode() == resultCode;
                    }
                }
        ));
    }

    @Test
    public void callback_statusIndication() throws Exception {
        int token = 1;
        int statusChange = 2;

        mReceiver.mSapCallback.statusIndication(token, statusChange);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_STATUS_IND
                                && sapMsg.getStatusChange() == statusChange;
                    }
                }
        ));
    }

    @Test
    public void callback_transferCardReaderStatusResponse() throws Exception {
        int token = 1;
        int resultCode = RESULT_OK;
        int cardReaderStatus = STATUS_CARD_INSERTED;

        mReceiver.mSapCallback.transferCardReaderStatusResponse(
                token, resultCode, cardReaderStatus);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_TRANSFER_CARD_READER_STATUS_RESP
                                && sapMsg.getResultCode() == resultCode;
                    }
                }
        ));
    }

    @Test
    public void callback_errorResponse() throws Exception {
        int token = 1;

        mReceiver.mSapCallback.errorResponse(token);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RIL_IND), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_RIL_UNKNOWN;
                    }
                }
        ));
    }

    @Test
    public void callback_transferProtocolResponse() throws Exception {
        int token = 1;
        int resultCode = RESULT_OK;

        mReceiver.mSapCallback.transferProtocolResponse(token, resultCode);

        verify(mCallback, timeout(TIMEOUT_MS)).receiveMessage(eq(SAP_MSG_RFC_REPLY), argThat(
                new ArgumentMatcher<Object>() {
                    @Override
                    public boolean matches(Object arg) {
                        if (!(arg instanceof SapMessage)) {
                            return false;
                        }
                        SapMessage sapMsg = (SapMessage) arg;
                        return sapMsg.getMsgType() == ID_SET_TRANSPORT_PROTOCOL_RESP
                                && sapMsg.getResultCode() == resultCode;
                    }
                }
        ));
    }

    public static class TestHandlerCallback implements Handler.Callback {

        @Override
        public boolean handleMessage(Message msg) {
            receiveMessage(msg.what, msg.obj);
            return true;
        }

        public void receiveMessage(int what, Object obj) {}
    }
}