Commit c7c949d2 authored by Jie Jiang's avatar Jie Jiang Committed by Commit Bot

arc: bluetooth: Make RFCOMM available for arcvm

Currently RFCOMM is not available on arcvm because we need some
operations (listen(), connect(), etc.) on the bluetooth socket in
Android, which is not supported by VSockProxy. This change moves such
operations into Chrome.

See http://ag/9487891 for change in Android.

- For RFCOMM listen, we keep the listening socket in Chrome. When a new
connection is accepted, we give the new socket by accept() to Android.
- For RFCOMM connect, we keep the socket when connection is not
established. When connect is ready, we give this socket to Android.
- We use mojo interface to wrap the sockets live in Chrome. The
following events (e.g., connect() succeeds) are notified via these
interfaces.

BUG=b:142090057
TEST=cts-tradefed run commandAndExit cts -m CtsBluetoothTestCases;
manually wrote some apps, Android on DUT can communicate with my
workstation via RFCOMM, both as client and server

Change-Id: If366aaeca5297a011bbd9ff6584831afbf2b86ee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1837329
Commit-Queue: Jie Jiang <jiejiang@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarHidehiko Abe <hidehiko@chromium.org>
Reviewed-by: default avatarMiao-chen Chou <mcchou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#721893}
parent 8b426107
......@@ -9,12 +9,16 @@
#include <map>
#include <memory>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "base/callback_forward.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/files/file.h"
#include "base/files/file_descriptor_watcher_posix.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.h"
......@@ -306,6 +310,15 @@ class ArcBluetoothBridge
void RemoveSdpRecord(uint32_t service_handle,
RemoveSdpRecordCallback callback) override;
// Bluetooth Mojo host interface - Bluetooth RFCOMM functions
void RfcommListen(int32_t channel,
int32_t optval,
RfcommListenCallback callback) override;
void RfcommConnect(mojom::BluetoothAddressPtr remote_addr,
int32_t channel,
int32_t optval,
RfcommConnectCallback callback) override;
// Set up or disable multiple advertising.
void ReserveAdvertisementHandle(
ReserveAdvertisementHandleCallback callback) override;
......@@ -505,6 +518,49 @@ class ArcBluetoothBridge
void SendDevice(const device::BluetoothDevice* device) const;
// Data structures for RFCOMM listening/connecting sockets that live in
// Chrome.
struct RfcommListeningSocket {
mojom::RfcommListeningSocketClientPtr remote;
base::ScopedFD file;
std::unique_ptr<base::FileDescriptorWatcher::Controller> controller;
RfcommListeningSocket();
~RfcommListeningSocket();
};
struct RfcommConnectingSocket {
mojom::RfcommConnectingSocketClientPtr remote;
base::ScopedFD file;
std::unique_ptr<base::FileDescriptorWatcher::Controller> controller;
RfcommConnectingSocket();
~RfcommConnectingSocket();
};
// Creates a bluetooth socket with socket option |optval|, and then bind()
// and listen() with requested RFCOMM |channel| number. The actual channel
// number will be filled in |channel| as the return value. Returns a
// RfcommListeningSocket that holds the socket.
std::unique_ptr<RfcommListeningSocket> RfcommCreateListenSocket(
int32_t optval,
uint8_t* channel);
// Creates a bluetooth socket with socket option |optval|, and then calls
// connect() to (|addr|, |channel|). This connect() call is non-blocking.
// Returns a RfcommConnectingSocket that holds the socket.
std::unique_ptr<RfcommConnectingSocket> RfcommCreateConnectSocket(
mojom::BluetoothAddressPtr addr,
uint8_t channel,
int32_t optval);
// Closes RFCOMM sockets. Releases the corresponding resources.
void RfcommCloseListeningSocket(RfcommListeningSocket* socket);
void RfcommCloseConnectingSocket(RfcommConnectingSocket* socket);
// Called when the listening socket is ready to accept().
void OnRfcommListeningSocketReady(
ArcBluetoothBridge::RfcommListeningSocket* socket);
// Called when the connecting socket is ready.
void OnRfcommConnectingSocketReady(
ArcBluetoothBridge::RfcommConnectingSocket* socket);
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
scoped_refptr<bluez::BluetoothAdapterBlueZ> bluetooth_adapter_;
......@@ -573,6 +629,12 @@ class ArcBluetoothBridge
ArcBluetoothTaskQueue advertisement_queue_;
ArcBluetoothTaskQueue discovery_queue_;
// Rfcomm sockets that live in Chrome.
std::set<std::unique_ptr<RfcommListeningSocket>, base::UniquePtrComparator>
listening_sockets_;
std::set<std::unique_ptr<RfcommConnectingSocket>, base::UniquePtrComparator>
connecting_sockets_;
THREAD_CHECKER(thread_checker_);
// WeakPtrFactory to use for callbacks.
......
......@@ -68,6 +68,29 @@ std::string TypeConverter<std::string, arc::mojom::BluetoothAddress>::Convert(
return addr_stream.str();
}
// static
arc::mojom::BluetoothAddressPtr
TypeConverter<arc::mojom::BluetoothAddressPtr, bdaddr_t>::Convert(
const bdaddr_t& address) {
arc::mojom::BluetoothAddressPtr mojo_addr =
arc::mojom::BluetoothAddress::New();
mojo_addr->address.resize(kAddressSize);
std::reverse_copy(std::begin(address.b), std::end(address.b),
std::begin(mojo_addr->address));
return mojo_addr;
}
// static
bdaddr_t TypeConverter<bdaddr_t, arc::mojom::BluetoothAddress>::Convert(
const arc::mojom::BluetoothAddress& address) {
bdaddr_t ret;
std::reverse_copy(std::begin(address.address), std::end(address.address),
std::begin(ret.b));
return ret;
}
// static
arc::mojom::BluetoothSdpAttributePtr
TypeConverter<arc::mojom::BluetoothSdpAttributePtr,
......
......@@ -5,6 +5,7 @@
#ifndef COMPONENTS_ARC_BLUETOOTH_BLUETOOTH_TYPE_CONVERTERS_H_
#define COMPONENTS_ARC_BLUETOOTH_BLUETOOTH_TYPE_CONVERTERS_H_
#include <bluetooth/bluetooth.h>
#include <stddef.h>
#include <stdint.h>
#include <string>
......@@ -40,6 +41,16 @@ struct TypeConverter<std::string, arc::mojom::BluetoothAddress> {
static std::string Convert(const arc::mojom::BluetoothAddress& ptr);
};
template <>
struct TypeConverter<arc::mojom::BluetoothAddressPtr, bdaddr_t> {
static arc::mojom::BluetoothAddressPtr Convert(const bdaddr_t& address);
};
template <>
struct TypeConverter<bdaddr_t, arc::mojom::BluetoothAddress> {
static bdaddr_t Convert(const arc::mojom::BluetoothAddress& address);
};
template <>
struct TypeConverter<arc::mojom::BluetoothSdpAttributePtr,
bluez::BluetoothServiceAttributeValueBlueZ> {
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Next MinVersion: 15
// Next MinVersion: 16
module arc.mojom;
......@@ -286,7 +286,37 @@ struct BluetoothCreateSdpRecordResult {
uint32 service_handle;
};
// Next Method ID: 45
// BluetoothRfcommConnection contains the information for a new RFCOMM
// connection. Since we cannot get socket (or peer) name on the transferred
// socket on Android side, we also need to pass the peer address and channel
// number.
struct BluetoothRfcommConnection {
handle sock;
BluetoothAddress addr;
int32 channel;
};
// The mojo connection represents a listening socket.
// Next Method ID: 1
interface RfcommListeningSocketClient {
// Called when accept() succeeds. |channel| in |connection| is the peer
// channel number.
OnAccepted@0(BluetoothRfcommConnection connection);
};
// The mojo connection represents a connecting (not connected yet) socket.
// After connect() either succeeds or fails, Android is responsible for closing
// this mojo connection.
// Next Method ID: 2
interface RfcommConnectingSocketClient {
// Called when connect() succeeds. |channel| in |connection| is the channel
// number on our side.
OnConnected@0(BluetoothRfcommConnection connection);
// Called when connect() fails.
OnConnectFailed@1();
};
// Next Method ID: 47
// Deprecated Method ID: 4, 5, 6, 7, 20, 21
interface BluetoothHost {
EnableAdapter@0() => (BluetoothAdapterState state);
......@@ -393,6 +423,24 @@ interface BluetoothHost {
=> (BluetoothGattStatus status);
[MinVersion=8] DisableAdvertisement@43(int32 adv_handle)
=> (BluetoothGattStatus status);
// RFCOMM functions
// Opens a bluetooth socket with socket option |optval|, and then bind() and
// listen() with the requested RFCOMM |channel| number. When |channel| = 0,
// we will select a channel number automatically. If this process succeeds,
// returns SUCCESS in |status|, the actual listening channel in |channel|,
// and a new mojo connection which represents the listening socket.
[MinVersion=15] RfcommListen@45(int32 channel, int32 optval)
=> (BluetoothStatus status, int32 channel,
RfcommListeningSocketClient&? client);
// Opens a bluetooth socket with socket option |optval|, and then connect()
// to (|remote_addr|, |channel|). If this process succeeds, returns SUCCESS
// in |status| and a new mojo connection which holds the connecting socket.
// Unlike in RfcommListen(), |channel| here could not be 0, since this is the
// peer channel number.
[MinVersion=15] RfcommConnect@46(BluetoothAddress remote_addr,
int32 channel, int32 optval)
=> (BluetoothStatus status, RfcommConnectingSocketClient&? client);
};
// Next Method ID: 22
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment