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

Commit 0a832d13 authored by Liang Li's avatar Liang Li Committed by Automerger Merge Worker
Browse files

Send signal to indicate if app is accepting incoming connection on listen...

Send signal to indicate if app is accepting incoming connection on listen socket am: 88ba5e07 am: fde86181

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/3349375



Change-Id: I5a1bb44fd9a9a421d15bdefe4585083d61d1377a
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 36fe6cf5 fde86181
Loading
Loading
Loading
Loading
+39 −1
Original line number Diff line number Diff line
@@ -193,6 +193,7 @@ public final class BluetoothSocket implements Closeable {

    private static final int SOCK_CONNECTION_SIGNAL_SIZE = 44;
    private static final long INVALID_SOCKET_ID = 0;
    private static final int SOCK_ACCEPT_SIGNAL_SIZE = 4;

    private ByteBuffer mL2capBuffer = null;
    private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer.
@@ -931,7 +932,13 @@ public final class BluetoothSocket implements Closeable {
        if (timeout > 0) {
            mSocket.setSoTimeout(timeout);
        }
        String RemoteAddr = waitSocketSignal(mSocketIS);
        sendSocketAcceptSignal(mSocketOS, true);
        String RemoteAddr;
        try {
            RemoteAddr = waitSocketSignal(mSocketIS);
        } finally {
            sendSocketAcceptSignal(mSocketOS, false);
        }
        if (timeout > 0) {
            mSocket.setSoTimeout(0);
        }
@@ -1284,6 +1291,37 @@ public final class BluetoothSocket implements Closeable {
                addr[5]);
    }

    /**
     * Sends a socket accept signal to the host stack.
     *
     * <p>This method is used to notify the host stack whether the host application is actively
     * accepting a new connection or not. It sends a signal containing the acceptance status to the
     * output stream associated with the socket.
     *
     * <p>This method is only effective when the data path is not {@link
     * BluetoothSocketSettings#DATA_PATH_NO_OFFLOAD}.
     *
     * @param os The output stream to write the signal to.
     * @param isAccepting {@code true} if the socket connection is being accepted, {@code false}
     *     otherwise.
     * @throws IOException If an I/O error occurs while writing to the output stream.
     * @hide
     */
    private void sendSocketAcceptSignal(OutputStream os, boolean isAccepting) throws IOException {
        if (Flags.socketSettingsApi()) {
            if (mDataPath == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
                return;
            }
            Log.d(TAG, "sendSocketAcceptSignal" + " isAccepting " + isAccepting);
            byte[] sig = new byte[SOCK_ACCEPT_SIGNAL_SIZE];
            ByteBuffer bb = ByteBuffer.wrap(sig);
            bb.order(ByteOrder.nativeOrder());
            bb.putShort((short) SOCK_ACCEPT_SIGNAL_SIZE);
            bb.putShort((short) (isAccepting ? 1 : 0));
            os.write(sig, 0, SOCK_ACCEPT_SIGNAL_SIZE);
        }
    }

    private String waitSocketSignal(InputStream is) throws IOException {
        byte[] sig = new byte[SOCK_CONNECTION_SIGNAL_SIZE];
        int ret = readAll(is, sig);
+79 −38
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ typedef struct l2cap_socket {
  char socket_name[128];         // descriptive socket name
  uint64_t hub_id;               // ID of the hub to which the end point belongs
  uint64_t endpoint_id;          // ID of the hub end point
  bool is_accepting;             // is app accepting on server socket?
} l2cap_socket;

static void btsock_l2cap_server_listen(l2cap_socket* sock);
@@ -351,6 +352,7 @@ static l2cap_socket* btsock_l2cap_alloc_l(const char* name, const RawAddress* ad
  sock->data_path = BTSOCK_DATA_PATH_NO_OFFLOAD;
  sock->hub_id = 0;
  sock->endpoint_id = 0;
  sock->is_accepting = false;

  if (name) {
    strncpy(sock->name, name, sizeof(sock->name) - 1);
@@ -543,7 +545,7 @@ static void on_cl_l2cap_init(tBTA_JV_L2CAP_CL_INIT* p_init, uint32_t id) {
 * will be a clone of the sock representing the BluetoothServerSocket.
 * */
static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket* sock) {
  // std::mutex locked by caller
  // state_lock taken by caller
  l2cap_socket* accept_rs = btsock_l2cap_alloc_l(sock->name, &p_open->rem_bda, false, 0);
  accept_rs->connected = true;
  accept_rs->security = sock->security;
@@ -591,6 +593,8 @@ static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket*
  // But for some reason we still leak a FD - either the server socket
  // one or the accept socket one.
  btsock_l2cap_server_listen(sock);
  // start monitoring the socketpair to get call back when app is accepting on server socket
  btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
}

static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket* sock) {
@@ -912,6 +916,8 @@ static bt_status_t btsock_l2cap_listen_or_connect(const char* name, const RawAdd
  /* "role" is never initialized in rfcomm code */
  if (listen) {
    btsock_l2cap_server_listen(sock);
    // start monitoring the socketpair to get call back when app is accepting on server socket
    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
  } else {
    tBTA_JV_CONN_TYPE connection_type =
            sock->is_le_coc ? tBTA_JV_CONN_TYPE::L2CAP_LE : tBTA_JV_CONN_TYPE::L2CAP;
@@ -999,20 +1005,12 @@ inline uint8_t* get_l2cap_sdu_start_ptr(BT_HDR* msg) {
  return (uint8_t*)(msg) + BT_HDR_SIZE + msg->offset;
}

void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) {
  char drop_it = false;

  /* We use MSG_DONTWAIT when sending data to JAVA, hence it can be accepted to
   * hold the lock. */
  std::unique_lock<std::mutex> lock(state_lock);
  l2cap_socket* sock = btsock_l2cap_find_by_id_l(user_id);
  if (!sock) {
    return;
// state_lock taken by caller
bool btsock_l2cap_read_signaled_on_connected_socket(int fd, int flags, uint32_t user_id,
                                                    l2cap_socket* sock) {
  if (!sock->connected) {
    return false;
  }

  if ((flags & SOCK_THREAD_FD_RD) && !sock->server) {
    // app sending data
    if (sock->connected) {
  int size = 0;
  bool ioctl_success = ioctl(sock->our_fd, FIONREAD, &size) == 0;
  if (!(flags & SOCK_THREAD_FD_EXCEPTION) || (ioctl_success && size)) {
@@ -1046,10 +1044,53 @@ void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) {
    // will take care of freeing buffer
    BTA_JvL2capWrite(sock->handle, PTR_TO_UINT(buffer), buffer, user_id);
  }
  return true;
}

// state_lock taken by caller
bool btsock_l2cap_read_signaled_on_listen_socket(int fd, int /* flags */, uint32_t /* user_id */,
                                                 l2cap_socket* sock) {
  int size = 0;
  bool ioctl_success = ioctl(sock->our_fd, FIONREAD, &size) == 0;
  if (ioctl_success && size) {
    sock_accept_signal_t accept_signal = {};
    ssize_t count;
    OSI_NO_INTR(count = recv(fd, reinterpret_cast<uint8_t*>(&accept_signal), sizeof(accept_signal),
                             MSG_NOSIGNAL | MSG_DONTWAIT | MSG_TRUNC));
    if (count != sizeof(accept_signal) || count != accept_signal.size) {
      log::error("Unexpected count {} sizeof(accept_signal) {} accept_signal.size {}", count,
                 sizeof(accept_signal), accept_signal.size);
      return false;
    }
    sock->is_accepting = accept_signal.is_accepting;
    log::info("Server socket {} is_accepting {}", sock->id, sock->is_accepting);
  }
  return true;
}

void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) {
  char drop_it = false;

  /* We use MSG_DONTWAIT when sending data to JAVA, hence it can be accepted to
   * hold the lock. */
  std::unique_lock<std::mutex> lock(state_lock);
  l2cap_socket* sock = btsock_l2cap_find_by_id_l(user_id);
  if (!sock) {
    return;
  }
  if (flags & SOCK_THREAD_FD_RD) {
    if (!sock->server) {
      // app sending data on connection socket
      if (!btsock_l2cap_read_signaled_on_connected_socket(fd, flags, user_id, sock)) {
        drop_it = true;
      }
    } else {
      // app sending signal on listen socket
      if (!btsock_l2cap_read_signaled_on_listen_socket(fd, flags, user_id, sock)) {
        drop_it = true;
      }
    }
  }
  if (flags & SOCK_THREAD_FD_WR) {
    // app is ready to receive more data, tell stack to enable the data flow
    if (flush_incoming_que_on_wr_signal_l(sock) && sock->connected) {
+5 −0
Original line number Diff line number Diff line
@@ -73,6 +73,11 @@ typedef struct {
  uint64_t socket_id;
} __attribute__((packed)) sock_connect_signal_t;

typedef struct {
  uint16_t size;
  uint16_t is_accepting;
} __attribute__((packed)) sock_accept_signal_t;

typedef struct {
  /** set to size of this struct*/
  size_t size;