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

Commit 9bde803d authored by Bo Hu's avatar Bo Hu Committed by Gerrit Code Review
Browse files

Merge "Update Bluetooth Client to Support AIDL"

parents 942859d9 24c5bd1e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ android_app {
    ],
    static_libs: [
        "android.hardware.radio-V1.0-java",
        "android.hardware.radio.sap-V1-java",
        "androidx.core_core",
        "androidx.media_media",
        "androidx.lifecycle_lifecycle-livedata",
+49 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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 android.hardware.radio.sap.ISap;

/**
 * ISapRilReceiver is used to send messages
 */
public interface ISapRilReceiver extends ISap {
    /**
     * Set mSapProxy to null
     */
    void resetSapProxy();

    /**
     * Notify SapServer that this class is ready for shutdown.
     */
    void notifyShutdown();

    /**
     * Notify SapServer that the RIL socket is connected
     */
    void sendRilConnectMessage();

    /**
     * Get mSapProxyLock
     */
    Object getSapProxyLock();

    /**
     * Verifies mSapProxy is not null
     */
    boolean isProxyValid();
}
+24 −29
Original line number Diff line number Diff line
package com.android.bluetooth.sap;

import android.hardware.radio.V1_0.ISap;
import android.hardware.radio.V1_0.SapApduType;
import android.hardware.radio.V1_0.SapTransferProtocol;
import android.hardware.radio.sap.SapApduType;
import android.hardware.radio.sap.SapTransferProtocol;
import android.os.RemoteException;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

import com.google.protobuf.micro.CodedOutputStreamMicro;
import com.google.protobuf.micro.InvalidProtocolBufferMicroException;

import org.android.btsap.SapApi;
@@ -26,7 +24,6 @@ import org.android.btsap.SapApi.RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@@ -35,7 +32,6 @@ import java.util.concurrent.atomic.AtomicInteger;
 * SapMessage is used for incoming and outgoing messages.
 *
 * For incoming messages
 *
 */
public class SapMessage {

@@ -194,6 +190,7 @@ public class SapMessage {

    /**
     * Create a SapMessage
     *
     * @param msgType the SAP message type
     */
    public SapMessage(int msgType) {
@@ -374,6 +371,7 @@ public class SapMessage {

    /**
     * Construct a SapMessage based on the incoming rfcomm request.
     *
     * @param requestType The type of the request
     * @param is          the input stream to read the data from
     * @return the resulting message, or null if an error occurs
@@ -443,6 +441,7 @@ public class SapMessage {

    /**
     * Blocking read of an entire array of data.
     *
     * @param is     the input stream to read from
     * @param buffer the buffer to read into - the length of the buffer will
     *               determine how many bytes will be read.
@@ -463,6 +462,7 @@ public class SapMessage {

    /**
     * Skip a number of bytes in an InputStream.
     *
     * @param is    the input stream
     * @param count the number of bytes to skip
     * @throws IOException In case of reaching EOF or a stream error
@@ -477,10 +477,10 @@ public class SapMessage {
     * Read the parameters from the stream and update the relevant members.
     * This function will ensure that all parameters are read from the stream, even
     * if an error is detected.
     *
     * @param count the number of parameters to read
     * @param is    the input stream
     * @return True if all parameters were successfully parsed, False if an error were detected.
     * @throws IOException
     */
    private boolean parseParameters(int count, InputStream is) throws IOException {
        int paramId;
@@ -621,6 +621,7 @@ public class SapMessage {

    /**
     * Writes a single value parameter of 1 or 2 bytes in length.
     *
     * @param os     The BufferedOutputStream to write to.
     * @param id     The Parameter ID
     * @param value  The parameter value
@@ -656,6 +657,7 @@ public class SapMessage {

    /**
     * Writes a byte[] parameter of any length.
     *
     * @param os    The BufferedOutputStream to write to.
     * @param id    The Parameter ID
     * @param value The byte array to write, the length will be extracted from the array.
@@ -729,18 +731,11 @@ public class SapMessage {
     * RILD Interface message conversion functions.
     ***************************************************************************/

    private ArrayList<Byte> primitiveArrayToContainerArrayList(byte[] arr) {
        ArrayList<Byte> arrayList = new ArrayList<>(arr.length);
        for (byte b : arr) {
            arrayList.add(b);
        }
        return arrayList;
    }

    /**
     * Send the message by calling corresponding ISap api.
     */
    public void send(ISap sapProxy) throws RemoteException, RuntimeException {
    public void send(ISapRilReceiver sapProxy) throws RemoteException, RuntimeException {
        int rilSerial = sNextSerial.getAndIncrement();

        Log.e(TAG, "callISapReq: called for mMsgType " + mMsgType + " rilSerial " + rilSerial);
@@ -763,13 +758,13 @@ public class SapMessage {
            }
            case ID_TRANSFER_APDU_REQ: {
                int type;
                ArrayList<Byte> command;
                byte[] command;
                if (mApdu != null) {
                    type = SapApduType.APDU;
                    command = primitiveArrayToContainerArrayList(mApdu);
                    command = mApdu;
                } else if (mApdu7816 != null) {
                    type = SapApduType.APDU7816;
                    command = primitiveArrayToContainerArrayList(mApdu7816);
                    command = mApdu7816;
                } else {
                    Log.e(TAG, "Missing Apdu parameter in TRANSFER_APDU_REQ");
                    throw new IllegalArgumentException();
+199 −44
Original line number Diff line number Diff line
/*
 * Copyright (C) 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 android.hardware.radio.V1_0.ISap;
import android.hardware.radio.V1_0.ISapCallback;
import android.hardware.radio.sap.ISap;
import android.hardware.radio.sap.ISapCallback;
import android.os.Handler;
import android.os.HwBinder;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import com.android.modules.utils.build.SdkLevel;

import java.util.concurrent.atomic.AtomicLong;

public class SapRilReceiver {
/**
 * SapRiilReceiver is the AIDL implementation of ISapRilReceiver
 */
public class SapRilReceiver implements ISapRilReceiver {
    private static final String TAG = "SapRilReceiver";
    public static final boolean DEBUG = true;
    public static final boolean VERBOSE = true;

    private static final String SERVICE_NAME_RIL_BT = "slot1";
    // match with constant in ril.cpp - as in RIL.java
    private static final int SOCKET_OPEN_RETRY_MILLIS = 4 * 1000;
    // todo: add support for slot2 and slot3
    private static final String HAL_INSTANCE_NAME = ISap.DESCRIPTOR + "/slot1";

    SapCallback mSapCallback;
    volatile ISap mSapProxy = null;
    Object mSapProxyLock = new Object();
    final Object mSapProxyLock = new Object();
    final AtomicLong mSapProxyCookie = new AtomicLong(0);
    final SapProxyDeathRecipient mSapProxyDeathRecipient;

@@ -35,15 +52,129 @@ public class SapRilReceiver {
    public static final int RIL_MAX_COMMAND_BYTES = (8 * 1024);
    public byte[] buffer = new byte[RIL_MAX_COMMAND_BYTES];

    final class SapProxyDeathRecipient implements HwBinder.DeathRecipient {
    /**
     * TRANSFER_APDU_REQ from SAP 1.1 spec 5.1.6
     *
     * @param serial  Id to match req-resp. Resp must include same serial.
     * @param type    APDU command type
     * @param command CommandAPDU/CommandAPDU7816 parameter depending on type
     */
    @Override
    public void apduReq(int serial, int type, byte[] command) throws android.os.RemoteException {
        mSapProxy.apduReq(serial, type, command);
    }

    /**
     * CONNECT_REQ from SAP 1.1 spec 5.1.1
     *
     * @param serial          Id to match req-resp. Resp must include same serial.
     * @param maxMsgSizeBytes MaxMsgSize to be used for SIM Access Profile connection
     */
    @Override
    public void connectReq(int serial, int maxMsgSizeBytes) throws android.os.RemoteException {
        mSapProxy.connectReq(serial, maxMsgSizeBytes);
    }

    /**
     * DISCONNECT_REQ from SAP 1.1 spec 5.1.3
     *
     * @param serial Id to match req-resp. Resp must include same serial.
     */
    @Override
    public void disconnectReq(int serial) throws android.os.RemoteException {
        mSapProxy.disconnectReq(serial);
    }

    /**
     * POWER_SIM_OFF_REQ and POWER_SIM_ON_REQ from SAP 1.1 spec 5.1.10 + 5.1.12
     *
     * @param serial  Id to match req-resp. Resp must include same serial.
     * @param powerOn true for on, false for off
     */
    @Override
    public void powerReq(int serial, boolean powerOn) throws android.os.RemoteException {
        mSapProxy.powerReq(serial, powerOn);
    }

    /**
     * RESET_SIM_REQ from SAP 1.1 spec 5.1.14
     *
     * @param serial Id to match req-resp. Resp must include same serial.
     */
    @Override
    public void resetSimReq(int serial) throws android.os.RemoteException {
        mSapProxy.resetSimReq(serial);
    }

    /**
     * Set callback that has response and unsolicited indication functions
     *
     * @param sapCallback Object containing response and unosolicited indication callbacks
     */
    @Override
    public void setCallback(android.hardware.radio.sap.ISapCallback sapCallback)
            throws android.os.RemoteException {
        Log.e(TAG, "setCallback should never be called");
    }

    /**
     * SET_TRANSPORT_PROTOCOL_REQ from SAP 1.1 spec 5.1.20
     *
     * @param serial           Id to match req-resp. Resp must include same serial.
     * @param transferProtocol Transport Protocol
     */
    @Override
        public void serviceDied(long cookie) {
    public void setTransferProtocolReq(int serial, int transferProtocol)
            throws android.os.RemoteException {
        mSapProxy.setTransferProtocolReq(serial, transferProtocol);
    }

    /**
     * TRANSFER_ATR_REQ from SAP 1.1 spec 5.1.8
     *
     * @param serial Id to match req-resp. Resp must include same serial.
     */
    @Override
    public void transferAtrReq(int serial) throws android.os.RemoteException {
        mSapProxy.transferAtrReq(serial);
    }

    /**
     * TRANSFER_CARD_READER_STATUS_REQ from SAP 1.1 spec 5.1.17
     *
     * @param serial Id to match req-resp. Resp must include same serial.
     */
    @Override
    public void transferCardReaderStatusReq(int serial) throws android.os.RemoteException {
        mSapProxy.transferCardReaderStatusReq(serial);
    }

    @Override
    public int getInterfaceVersion() {
        Log.e(TAG, "getInterfaceVersion should never be called");
        return 0;
    }

    @Override
    public String getInterfaceHash() {
        Log.e(TAG, "getInterfaceHash should never be called");
        return "";
    }

    @Override
    public android.os.IBinder asBinder() {
        Log.e(TAG, "asBinder should never be called");
        return null;
    }

    final class SapProxyDeathRecipient implements IBinder.DeathRecipient {
        @Override
        public void binderDied() {
            // Deal with service going away
            Log.d(TAG, "serviceDied");
            // todo: temp hack to send delayed message so that rild is back up by then
            // mSapHandler.sendMessage(mSapHandler.obtainMessage(EVENT_SAP_PROXY_DEAD, cookie));
            mSapServerMsgHandler.sendMessageDelayed(
                    mSapServerMsgHandler.obtainMessage(SapServer.SAP_PROXY_DEAD, cookie),
                    mSapServerMsgHandler.obtainMessage(SapServer.SAP_PROXY_DEAD, (long) 0),
                    SapServer.ISAP_GET_SERVICE_DELAY_MILLIS);
        }
    }
@@ -100,25 +231,25 @@ public class SapRilReceiver {
        }

        @Override
        public void apduResponse(int token, int resultCode, ArrayList<Byte> apduRsp) {
        public void apduResponse(int token, int resultCode, byte[] apduRsp) {
            Log.d(TAG, "apduResponse: token " + token);
            SapService.notifyUpdateWakeLock(mSapServiceHandler);
            SapMessage sapMessage = new SapMessage(SapMessage.ID_TRANSFER_APDU_RESP);
            sapMessage.setResultCode(resultCode);
            if (resultCode == SapMessage.RESULT_OK) {
                sapMessage.setApduResp(arrayListToPrimitiveArray(apduRsp));
                sapMessage.setApduResp(apduRsp);
            }
            removeOngoingReqAndSendMessage(token, sapMessage);
        }

        @Override
        public void transferAtrResponse(int token, int resultCode, ArrayList<Byte> atr) {
        public void transferAtrResponse(int token, int resultCode, byte[] atr) {
            Log.d(TAG, "transferAtrResponse: token " + token + " resultCode " + resultCode);
            SapService.notifyUpdateWakeLock(mSapServiceHandler);
            SapMessage sapMessage = new SapMessage(SapMessage.ID_TRANSFER_ATR_RESP);
            sapMessage.setResultCode(resultCode);
            if (resultCode == SapMessage.RESULT_OK) {
                sapMessage.setAtr(arrayListToPrimitiveArray(atr));
                sapMessage.setAtr(atr);
            }
            removeOngoingReqAndSendMessage(token, sapMessage);
        }
@@ -195,20 +326,39 @@ public class SapRilReceiver {
            sapMessage.setResultCode(resultCode);
            removeOngoingReqAndSendMessage(token, sapMessage);
        }

        @Override
        public String getInterfaceHash() {
            return ISapCallback.HASH;
        }

    public static byte[] arrayListToPrimitiveArray(List<Byte> bytes) {
        byte[] ret = new byte[bytes.size()];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = bytes.get(i);
        @Override
        public int getInterfaceVersion() {
            return ISapCallback.VERSION;
        }
        return ret;
    }

    @Override
    public Object getSapProxyLock() {
        return mSapProxyLock;
    }

    @Override
    public boolean isProxyValid() {
        // Only call when synchronized with getSapProxyLock
        return mSapProxy != null;
    }

    /**
     * Check if AIDL is supported
     */
    public static boolean isAidlSupported() {
        return SdkLevel.isAtLeastU() && ServiceManager.isDeclared(HAL_INSTANCE_NAME);
    }

    /**
     * Obtain a valid sapProxy
     */
    public ISap getSapProxy() {
        synchronized (mSapProxyLock) {
            if (mSapProxy != null) {
@@ -216,10 +366,11 @@ public class SapRilReceiver {
            }

            try {
                mSapProxy = ISap.getService(SERVICE_NAME_RIL_BT);
                IBinder service = ServiceManager.waitForDeclaredService(HAL_INSTANCE_NAME);
                mSapProxy = ISap.Stub.asInterface(service);
                if (mSapProxy != null) {
                    mSapProxy.linkToDeath(mSapProxyDeathRecipient,
                            mSapProxyCookie.incrementAndGet());
                    service.linkToDeath(mSapProxyDeathRecipient,
                            /* flags= */ 0);
                    mSapProxy.setCallback(mSapCallback);
                } else {
                    Log.e(TAG, "getSapProxy: mSapProxy == null");
@@ -240,16 +391,17 @@ public class SapRilReceiver {
        }
    }

    @Override
    public void resetSapProxy() {
        synchronized (mSapProxyLock) {
            if (DEBUG) Log.d(TAG, "resetSapProxy :" + mSapProxy);
            try {
                if (mSapProxy != null) {
                    mSapProxy.unlinkToDeath(mSapProxyDeathRecipient);
            if (mSapProxy == null) {
                return;
            }
            } catch (RemoteException | RuntimeException e) {
                Log.e(TAG, "resetSapProxy: exception: " + e);
            if (mSapProxy.asBinder() == null) {
                Log.e(TAG, "asdf asBinder is null");
            }
            mSapProxy.asBinder().unlinkToDeath(mSapProxyDeathRecipient, /* flags= */ 0);
            mSapProxy = null;
        }
    }
@@ -264,25 +416,26 @@ public class SapRilReceiver {
        }
    }

    /**
     * Notify SapServer that this class is ready for shutdown.
     */
    void notifyShutdown() {
    @Override
    public void notifyShutdown() {
        if (DEBUG) {
            Log.i(TAG, "notifyShutdown()");
        }
        // If we are already shutdown, don't bother sending a notification.
        synchronized (mSapProxyLock) {
            // If we are already shutdown, don't bother sending a notification.
            if (mSapProxy != null) {
                sendShutdownMessage();
            }
            resetSapProxy();

            // todo: rild should be back up since the message was sent with a delay. this is
            // a hack.
            getSapProxy();
        }
    }

    /**
     * Notify SapServer that the RIL socket is connected
     */
    void sendRilConnectMessage() {
    @Override
    public void sendRilConnectMessage() {
        if (mSapServerMsgHandler != null) {
            mSapServerMsgHandler.sendEmptyMessage(SapServer.SAP_MSG_RIL_CONNECT);
        }
@@ -290,6 +443,7 @@ public class SapRilReceiver {

    /**
     * Send reply (solicited) message from the RIL to the Sap Server Handler Thread
     *
     * @param sapMsg The message to send
     */
    private void sendClientMessage(SapMessage sapMsg) {
@@ -308,6 +462,7 @@ public class SapRilReceiver {

    /**
     * Send indication (unsolicited) message from RIL to the Sap Server Handler Thread
     *
     * @param sapMsg The message to send
     */
    private void sendRilIndMessage(SapMessage sapMsg) {
+481 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading