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

Commit 6e2a3d98 authored by Hyundo Moon's avatar Hyundo Moon Committed by Android (Google) Code Review
Browse files

Merge "Add SapRilReceiverTest" into tm-qpr-dev

parents 43ff73c0 d75408b8
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) {}
    }
}