mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Bug 915533 - Patch 2/2: [bludroid OPP] BluetoothSocket, r=echou
This commit is contained in:
parent
1d917ad645
commit
8472e8db0c
@ -158,11 +158,7 @@ public:
|
||||
void Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mSocket->GetConnectionStatus() ==
|
||||
SocketConnectionStatus::SOCKET_CONNECTED) {
|
||||
mSocket->Disconnect();
|
||||
}
|
||||
mSocket->CloseDroidSocket();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -189,7 +185,7 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
|
||||
, mWaitingToSendPutFinal(false)
|
||||
, mCurrentBlobIndex(-1)
|
||||
{
|
||||
mConnectedDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
|
||||
mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
|
||||
}
|
||||
|
||||
BluetoothOppManager::~BluetoothOppManager()
|
||||
@ -211,7 +207,14 @@ BluetoothOppManager::Init()
|
||||
return false;
|
||||
}
|
||||
|
||||
Listen();
|
||||
/**
|
||||
* We don't start listening here as BluetoothServiceBluedroid calls Listen()
|
||||
* immediately when BT stops.
|
||||
*
|
||||
* If we start listening here, the listening fails when device boots up since
|
||||
* Listen() is called again and restarts server socket. The restart causes
|
||||
* absence of read events when device boots up.
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -244,14 +247,9 @@ BluetoothOppManager::ConnectInternal(const nsAString& aDeviceAddress)
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Stop listening because currently we only support one connection at a time.
|
||||
if (mRfcommSocket) {
|
||||
mRfcommSocket->Disconnect();
|
||||
mRfcommSocket = nullptr;
|
||||
}
|
||||
|
||||
if (mL2capSocket) {
|
||||
mL2capSocket->Disconnect();
|
||||
mL2capSocket = nullptr;
|
||||
if (mServerSocket) {
|
||||
mServerSocket->Disconnect();
|
||||
mServerSocket = nullptr;
|
||||
}
|
||||
|
||||
mIsServer = false;
|
||||
@ -262,18 +260,9 @@ BluetoothOppManager::ConnectInternal(const nsAString& aDeviceAddress)
|
||||
return;
|
||||
}
|
||||
|
||||
mNeedsUpdatingSdpRecords = true;
|
||||
|
||||
nsString uuid;
|
||||
BluetoothUuidHelper::GetString(BluetoothServiceClass::OBJECT_PUSH, uuid);
|
||||
|
||||
if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
|
||||
OnSocketConnectError(mSocket);
|
||||
return;
|
||||
}
|
||||
|
||||
mSocket =
|
||||
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
|
||||
mSocket->Connect(aDeviceAddress, -1);
|
||||
}
|
||||
|
||||
void
|
||||
@ -286,13 +275,9 @@ BluetoothOppManager::HandleShutdown()
|
||||
mSocket->Disconnect();
|
||||
mSocket = nullptr;
|
||||
}
|
||||
if (mRfcommSocket) {
|
||||
mRfcommSocket->Disconnect();
|
||||
mRfcommSocket = nullptr;
|
||||
}
|
||||
if (mL2capSocket) {
|
||||
mL2capSocket->Disconnect();
|
||||
mL2capSocket = nullptr;
|
||||
if (mServerSocket) {
|
||||
mServerSocket->Disconnect();
|
||||
mServerSocket = nullptr;
|
||||
}
|
||||
sBluetoothOppManager = nullptr;
|
||||
}
|
||||
@ -307,29 +292,24 @@ BluetoothOppManager::Listen()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mRfcommSocket) {
|
||||
mRfcommSocket =
|
||||
/**
|
||||
* Restart server socket since its underlying fd becomes invalid when
|
||||
* BT stops; otherwise no more read events would be received even if
|
||||
* BT restarts.
|
||||
*/
|
||||
if (mServerSocket) {
|
||||
mServerSocket->Disconnect();
|
||||
mServerSocket = nullptr;
|
||||
}
|
||||
|
||||
mServerSocket =
|
||||
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
|
||||
|
||||
if (!mRfcommSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH)) {
|
||||
if (!mServerSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH)) {
|
||||
BT_WARNING("[OPP] Can't listen on RFCOMM socket!");
|
||||
mRfcommSocket = nullptr;
|
||||
mServerSocket = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mL2capSocket) {
|
||||
mL2capSocket =
|
||||
new BluetoothSocket(this, BluetoothSocketType::EL2CAP, true, true);
|
||||
|
||||
if (!mL2capSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH_L2CAP)) {
|
||||
BT_WARNING("[OPP] Can't listen on L2CAP socket!");
|
||||
mRfcommSocket->Disconnect();
|
||||
mRfcommSocket = nullptr;
|
||||
mL2capSocket = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mIsServer = true;
|
||||
|
||||
@ -1250,7 +1230,7 @@ BluetoothOppManager::SendObexData(uint8_t* aData, uint8_t aOpcode, int aSize)
|
||||
|
||||
UnixSocketRawData* s = new UnixSocketRawData(aSize);
|
||||
memcpy(s->mData, aData, s->mSize);
|
||||
mSocket->SendSocketData(s);
|
||||
mSocket->SendDroidSocketData(s);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1266,7 +1246,7 @@ BluetoothOppManager::FileTransferComplete()
|
||||
type.AssignLiteral("bluetooth-opp-transfer-complete");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mConnectedDeviceAddress;
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("success");
|
||||
@ -1306,7 +1286,7 @@ BluetoothOppManager::StartFileTransfer()
|
||||
type.AssignLiteral("bluetooth-opp-transfer-start");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mConnectedDeviceAddress;
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("received");
|
||||
@ -1342,7 +1322,7 @@ BluetoothOppManager::UpdateProgress()
|
||||
type.AssignLiteral("bluetooth-opp-update-progress");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mConnectedDeviceAddress;
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("received");
|
||||
@ -1372,7 +1352,7 @@ BluetoothOppManager::ReceivingFileConfirmation()
|
||||
type.AssignLiteral("bluetooth-opp-receiving-file-confirmation");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mConnectedDeviceAddress;
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileName");
|
||||
@ -1412,28 +1392,19 @@ BluetoothOppManager::OnSocketConnectSuccess(BluetoothSocket* aSocket)
|
||||
MOZ_ASSERT(aSocket);
|
||||
|
||||
/**
|
||||
* If the created connection is an inbound connection, close another server
|
||||
* socket because currently only one file-transfer session is allowed. After
|
||||
* that, we need to make sure that both server socket would be nulled out.
|
||||
* If the created connection is an inbound connection, close server socket
|
||||
* because currently only one file-transfer session is allowed. After that,
|
||||
* we need to make sure that server socket would be nulled out.
|
||||
* As for outbound connections, we just notify the controller that it's done.
|
||||
*/
|
||||
if (aSocket == mRfcommSocket) {
|
||||
if (aSocket == mServerSocket) {
|
||||
MOZ_ASSERT(!mSocket);
|
||||
mRfcommSocket.swap(mSocket);
|
||||
|
||||
mL2capSocket->Disconnect();
|
||||
mL2capSocket = nullptr;
|
||||
} else if (aSocket == mL2capSocket) {
|
||||
MOZ_ASSERT(!mSocket);
|
||||
mL2capSocket.swap(mSocket);
|
||||
|
||||
mRfcommSocket->Disconnect();
|
||||
mRfcommSocket = nullptr;
|
||||
mServerSocket.swap(mSocket);
|
||||
}
|
||||
|
||||
// Cache device address since we can't get socket address when a remote
|
||||
// device disconnect with us.
|
||||
mSocket->GetAddress(mConnectedDeviceAddress);
|
||||
mSocket->GetAddress(mDeviceAddress);
|
||||
|
||||
// Start sending file if we connect as a client
|
||||
if (!mIsServer) {
|
||||
@ -1446,8 +1417,7 @@ BluetoothOppManager::OnSocketConnectError(BluetoothSocket* aSocket)
|
||||
{
|
||||
BT_LOGR("%s: [%s]", __FUNCTION__, (mIsServer)? "server" : "client");
|
||||
|
||||
mRfcommSocket = nullptr;
|
||||
mL2capSocket = nullptr;
|
||||
mServerSocket = nullptr;
|
||||
mSocket = nullptr;
|
||||
|
||||
if (!mIsServer) {
|
||||
@ -1464,13 +1434,12 @@ BluetoothOppManager::OnSocketConnectError(BluetoothSocket* aSocket)
|
||||
void
|
||||
BluetoothOppManager::OnSocketDisconnect(BluetoothSocket* aSocket)
|
||||
{
|
||||
BT_LOGR("%s: [%s]", __FUNCTION__, (mIsServer)? "server" : "client");
|
||||
MOZ_ASSERT(aSocket);
|
||||
|
||||
if (aSocket != mSocket) {
|
||||
// Do nothing when a listening server socket is closed.
|
||||
return;
|
||||
}
|
||||
BT_LOGR("%s: [%s]", __FUNCTION__, (mIsServer) ? "client" : "server");
|
||||
|
||||
/**
|
||||
* It is valid for a bluetooth device which is transfering file via OPP
|
||||
@ -1492,7 +1461,7 @@ BluetoothOppManager::OnSocketDisconnect(BluetoothSocket* aSocket)
|
||||
}
|
||||
|
||||
AfterOppDisconnected();
|
||||
mConnectedDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
|
||||
mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
|
||||
mSuccessFlag = false;
|
||||
|
||||
mSocket = nullptr;
|
||||
@ -1502,50 +1471,6 @@ BluetoothOppManager::OnSocketDisconnect(BluetoothSocket* aSocket)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
|
||||
const nsAString& aServiceUuid,
|
||||
int aChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
if (aChannel < 0) {
|
||||
if (mNeedsUpdatingSdpRecords) {
|
||||
mNeedsUpdatingSdpRecords = false;
|
||||
bs->UpdateSdpRecords(aDeviceAddress, this);
|
||||
} else {
|
||||
OnSocketConnectError(mSocket);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mSocket->Connect(NS_ConvertUTF16toUTF8(aDeviceAddress), aChannel)) {
|
||||
OnSocketConnectError(mSocket);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
nsString uuid;
|
||||
BluetoothUuidHelper::GetString(BluetoothServiceClass::OBJECT_PUSH, uuid);
|
||||
|
||||
if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
|
||||
OnSocketConnectError(mSocket);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(BluetoothOppManager, nsIObserver)
|
||||
|
||||
bool
|
||||
@ -1561,6 +1486,20 @@ BluetoothOppManager::AcquireSdcardMountLock()
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
|
||||
const nsAString& aServiceUuid,
|
||||
int aChannel)
|
||||
{
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
|
||||
{
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::Connect(const nsAString& aDeviceAddress,
|
||||
BluetoothProfileController* aController)
|
||||
|
@ -122,7 +122,7 @@ private:
|
||||
* Set when OBEX session is established.
|
||||
*/
|
||||
bool mConnected;
|
||||
nsString mConnectedDeviceAddress;
|
||||
nsString mDeviceAddress;
|
||||
|
||||
/**
|
||||
* Remote information
|
||||
@ -212,15 +212,13 @@ private:
|
||||
|
||||
// If a connection has been established, mSocket will be the socket
|
||||
// communicating with the remote socket. We maintain the invariant that if
|
||||
// mSocket is non-null, mRfcommSocket and mL2capSocket must be null (and vice
|
||||
// versa).
|
||||
// mSocket is non-null, mServerSocket must be null (and vice versa).
|
||||
nsRefPtr<BluetoothSocket> mSocket;
|
||||
|
||||
// Server sockets. Once an inbound connection is established, it will hand
|
||||
// over the ownership to mSocket, and get a new server socket while Listen()
|
||||
// is called.
|
||||
nsRefPtr<BluetoothSocket> mRfcommSocket;
|
||||
nsRefPtr<BluetoothSocket> mL2capSocket;
|
||||
nsRefPtr<BluetoothSocket> mServerSocket;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
@ -6,60 +6,692 @@
|
||||
|
||||
#include "BluetoothSocket.h"
|
||||
|
||||
#include <hardware/bluetooth.h>
|
||||
#include <hardware/bt_sock.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "BluetoothServiceBluedroid.h"
|
||||
#include "BluetoothSocketObserver.h"
|
||||
#include "BluetoothUnixSocketConnector.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#define FIRST_SOCKET_INFO_MSG_LENGTH 4
|
||||
#define TOTAL_SOCKET_INFO_LENGTH 20
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
static const size_t MAX_READ_SIZE = 1 << 16;
|
||||
static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {
|
||||
0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
|
||||
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
|
||||
};
|
||||
static const btsock_interface_t* sBluetoothSocketInterface = nullptr;
|
||||
|
||||
// helper functions
|
||||
static bool
|
||||
EnsureBluetoothSocketHalLoad()
|
||||
{
|
||||
if (sBluetoothSocketInterface) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const bt_interface_t* btInf = GetBluetoothInterface();
|
||||
NS_ENSURE_TRUE(btInf, false);
|
||||
|
||||
sBluetoothSocketInterface =
|
||||
(btsock_interface_t *) btInf->get_profile_interface(BT_PROFILE_SOCKETS_ID);
|
||||
NS_ENSURE_TRUE(sBluetoothSocketInterface, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int16_t
|
||||
ReadInt16(const uint8_t* aData, size_t* aOffset)
|
||||
{
|
||||
int16_t value = (aData[*aOffset + 1] << 8) | aData[*aOffset];
|
||||
|
||||
*aOffset += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
ReadInt32(const uint8_t* aData, size_t* aOffset)
|
||||
{
|
||||
int32_t value = (aData[*aOffset + 3] << 24) |
|
||||
(aData[*aOffset + 2] << 16) |
|
||||
(aData[*aOffset + 1] << 8) |
|
||||
aData[*aOffset];
|
||||
*aOffset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void
|
||||
ReadBdAddress(const uint8_t* aData, size_t* aOffset, nsAString& aDeviceAddress)
|
||||
{
|
||||
char bdstr[18];
|
||||
sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
aData[*aOffset], aData[*aOffset + 1], aData[*aOffset + 2],
|
||||
aData[*aOffset + 3], aData[*aOffset + 4], aData[*aOffset + 5]);
|
||||
|
||||
aDeviceAddress.AssignLiteral(bdstr);
|
||||
*aOffset += 6;
|
||||
}
|
||||
|
||||
class mozilla::dom::bluetooth::DroidSocketImpl
|
||||
: public MessageLoopForIO::Watcher
|
||||
{
|
||||
public:
|
||||
DroidSocketImpl(BluetoothSocket* aConsumer, int aFd)
|
||||
: mConsumer(aConsumer)
|
||||
, mIOLoop(nullptr)
|
||||
, mFd(aFd)
|
||||
, mShuttingDownOnIOThread(false)
|
||||
{
|
||||
}
|
||||
|
||||
~DroidSocketImpl()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
void QueueWriteData(UnixSocketRawData* aData)
|
||||
{
|
||||
mOutgoingQ.AppendElement(aData);
|
||||
OnFileCanWriteWithoutBlocking(mFd);
|
||||
}
|
||||
|
||||
bool IsShutdownOnMainThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mConsumer == nullptr;
|
||||
}
|
||||
|
||||
bool IsShutdownOnIOThread()
|
||||
{
|
||||
return mShuttingDownOnIOThread;
|
||||
}
|
||||
|
||||
void ShutdownOnMainThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!IsShutdownOnMainThread());
|
||||
mConsumer = nullptr;
|
||||
}
|
||||
|
||||
void ShutdownOnIOThread()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
||||
|
||||
mReadWatcher.StopWatchingFileDescriptor();
|
||||
mWriteWatcher.StopWatchingFileDescriptor();
|
||||
|
||||
mShuttingDownOnIOThread = true;
|
||||
}
|
||||
|
||||
void SetUpIO(bool aWrite)
|
||||
{
|
||||
MOZ_ASSERT(!mIOLoop);
|
||||
MOZ_ASSERT(mFd >= 0);
|
||||
mIOLoop = MessageLoopForIO::current();
|
||||
|
||||
// Set up a read watch
|
||||
mIOLoop->WatchFileDescriptor(mFd,
|
||||
true,
|
||||
MessageLoopForIO::WATCH_READ,
|
||||
&mReadWatcher,
|
||||
this);
|
||||
|
||||
if (aWrite) {
|
||||
// Set up a write watch
|
||||
mIOLoop->WatchFileDescriptor(mFd.get(),
|
||||
false,
|
||||
MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectClientFd()
|
||||
{
|
||||
// Stop current read watch
|
||||
mReadWatcher.StopWatchingFileDescriptor();
|
||||
mIOLoop = nullptr;
|
||||
|
||||
// Restart read & write watch on client fd
|
||||
SetUpIO(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
|
||||
* directly from main thread. All non-main-thread accesses should happen with
|
||||
* mImpl as container.
|
||||
*/
|
||||
RefPtr<BluetoothSocket> mConsumer;
|
||||
|
||||
private:
|
||||
/**
|
||||
* libevent triggered functions that reads data from socket when available and
|
||||
* guarenteed non-blocking. Only to be called on IO thread.
|
||||
*
|
||||
* @param aFd [in] File descriptor to read from
|
||||
*/
|
||||
virtual void OnFileCanReadWithoutBlocking(int aFd);
|
||||
|
||||
/**
|
||||
* libevent or developer triggered functions that writes data to socket when
|
||||
* available and guarenteed non-blocking. Only to be called on IO thread.
|
||||
*
|
||||
* @param aFd [in] File descriptor to read from
|
||||
*/
|
||||
virtual void OnFileCanWriteWithoutBlocking(int aFd);
|
||||
|
||||
/**
|
||||
* Read message to get data and client fd wrapped in message header
|
||||
*
|
||||
* @param aFd [in] File descriptor to read message from
|
||||
* @param aBuffer [out] Data buffer read
|
||||
* @param aLength [out] Number of bytes read
|
||||
*/
|
||||
ssize_t ReadMsg(int aFd, void *aBuffer, size_t aLength);
|
||||
|
||||
/**
|
||||
* IO Loop pointer. Must be initalized and called from IO thread only.
|
||||
*/
|
||||
MessageLoopForIO* mIOLoop;
|
||||
|
||||
/**
|
||||
* Raw data queue. Must be pushed/popped from IO thread only.
|
||||
*/
|
||||
typedef nsTArray<UnixSocketRawData* > UnixSocketRawDataQueue;
|
||||
UnixSocketRawDataQueue mOutgoingQ;
|
||||
|
||||
/**
|
||||
* Read watcher for libevent. Only to be accessed on IO Thread.
|
||||
*/
|
||||
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
|
||||
|
||||
/**
|
||||
* Write watcher for libevent. Only to be accessed on IO Thread.
|
||||
*/
|
||||
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
|
||||
|
||||
/**
|
||||
* File descriptor to read from/write to. Connection happens on user provided
|
||||
* thread. Read/write/close happens on IO thread.
|
||||
*/
|
||||
mozilla::ScopedClose mFd;
|
||||
|
||||
/**
|
||||
* If true, do not requeue whatever task we're running
|
||||
*/
|
||||
bool mShuttingDownOnIOThread;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class DeleteInstanceRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DeleteInstanceRunnable(T* aInstance)
|
||||
: mInstance(aInstance)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
delete mInstance;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
T* mInstance;
|
||||
};
|
||||
|
||||
class RequestClosingSocketTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
RequestClosingSocketTask(DroidSocketImpl* aImpl) : mImpl(aImpl)
|
||||
{
|
||||
MOZ_ASSERT(aImpl);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mImpl->IsShutdownOnMainThread()) {
|
||||
NS_WARNING("CloseSocket has already been called!");
|
||||
// Since we've already explicitly closed and the close happened before
|
||||
// this, this isn't really an error. Since we've warned, return OK.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Start from here, same handling flow as calling CloseSocket() from
|
||||
// upper layer
|
||||
mImpl->mConsumer->CloseDroidSocket();
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
DroidSocketImpl* mImpl;
|
||||
};
|
||||
|
||||
class ShutdownSocketTask : public Task {
|
||||
virtual void Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
// At this point, there should be no new events on the IO thread after this
|
||||
// one with the possible exception of a SocketAcceptTask that
|
||||
// ShutdownOnIOThread will cancel for us. We are now fully shut down, so we
|
||||
// can send a message to the main thread that will delete mImpl safely knowing
|
||||
// that no more tasks reference it.
|
||||
mImpl->ShutdownOnIOThread();
|
||||
|
||||
nsRefPtr<nsIRunnable> t(new DeleteInstanceRunnable<
|
||||
mozilla::dom::bluetooth::DroidSocketImpl>(mImpl));
|
||||
nsresult rv = NS_DispatchToMainThread(t);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}
|
||||
|
||||
DroidSocketImpl* mImpl;
|
||||
|
||||
public:
|
||||
ShutdownSocketTask(DroidSocketImpl* aImpl) : mImpl(aImpl) { }
|
||||
};
|
||||
|
||||
class SocketReceiveTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SocketReceiveTask(DroidSocketImpl* aImpl, UnixSocketRawData* aData) :
|
||||
mImpl(aImpl),
|
||||
mRawData(aData)
|
||||
{
|
||||
MOZ_ASSERT(aImpl);
|
||||
MOZ_ASSERT(aData);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mImpl->IsShutdownOnMainThread()) {
|
||||
NS_WARNING("mConsumer is null, aborting receive!");
|
||||
// Since we've already explicitly closed and the close happened before
|
||||
// this, this isn't really an error. Since we've warned, return OK.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mImpl->mConsumer);
|
||||
mImpl->mConsumer->ReceiveSocketData(mRawData);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
DroidSocketImpl* mImpl;
|
||||
nsAutoPtr<UnixSocketRawData> mRawData;
|
||||
};
|
||||
|
||||
class SocketSendTask : public Task
|
||||
{
|
||||
public:
|
||||
SocketSendTask(BluetoothSocket* aConsumer, DroidSocketImpl* aImpl,
|
||||
UnixSocketRawData* aData)
|
||||
: mConsumer(aConsumer),
|
||||
mImpl(aImpl),
|
||||
mData(aData)
|
||||
{
|
||||
MOZ_ASSERT(aConsumer);
|
||||
MOZ_ASSERT(aImpl);
|
||||
MOZ_ASSERT(aData);
|
||||
}
|
||||
|
||||
void
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!mImpl->IsShutdownOnIOThread());
|
||||
|
||||
mImpl->QueueWriteData(mData);
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothSocket> mConsumer;
|
||||
DroidSocketImpl* mImpl;
|
||||
UnixSocketRawData* mData;
|
||||
};
|
||||
|
||||
class SocketSetUpIOTask : public Task
|
||||
{
|
||||
virtual void Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
mImpl->SetUpIO(mWrite);
|
||||
}
|
||||
|
||||
DroidSocketImpl* mImpl;
|
||||
bool mWrite;
|
||||
public:
|
||||
SocketSetUpIOTask(DroidSocketImpl* aImpl, bool aWrite)
|
||||
: mImpl(aImpl), mWrite(aWrite) { }
|
||||
};
|
||||
|
||||
class SocketConnectClientFdTask : public Task
|
||||
{
|
||||
virtual void Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
mImpl->ConnectClientFd();
|
||||
}
|
||||
|
||||
DroidSocketImpl* mImpl;
|
||||
public:
|
||||
SocketConnectClientFdTask(DroidSocketImpl* aImpl) : mImpl(aImpl) { }
|
||||
};
|
||||
|
||||
ssize_t
|
||||
DroidSocketImpl::ReadMsg(int aFd, void *aBuffer, size_t aLength)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct msghdr msg;
|
||||
struct iovec iv;
|
||||
struct cmsghdr cmsgbuf[2 * sizeof(cmsghdr) + 0x100];
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
memset(&iv, 0, sizeof(iv));
|
||||
|
||||
iv.iov_base = (unsigned char *)aBuffer;
|
||||
iv.iov_len = aLength;
|
||||
|
||||
msg.msg_iov = &iv;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
|
||||
ret = recvmsg(mFd.get(), &msg, MSG_NOSIGNAL);
|
||||
if (ret < 0 && errno == EPIPE) {
|
||||
// Treat this as an end of stream
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_ENSURE_FALSE(ret < 0, -1);
|
||||
NS_ENSURE_FALSE(msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE), -1);
|
||||
|
||||
// Extract client fd from message header
|
||||
for (struct cmsghdr *cmsgptr = CMSG_FIRSTHDR(&msg);
|
||||
cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
|
||||
if (cmsgptr->cmsg_level != SOL_SOCKET) {
|
||||
continue;
|
||||
}
|
||||
if (cmsgptr->cmsg_type == SCM_RIGHTS) {
|
||||
int *pDescriptors = (int *)CMSG_DATA(cmsgptr);
|
||||
// Overwrite fd with client fd
|
||||
mFd.reset(pDescriptors[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
DroidSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
||||
|
||||
// Read all of the incoming data.
|
||||
while (true) {
|
||||
nsAutoPtr<UnixSocketRawData> incoming(new UnixSocketRawData(MAX_READ_SIZE));
|
||||
|
||||
ssize_t ret;
|
||||
if (!mConsumer->IsWaitingForClientFd()) {
|
||||
ret = read(aFd, incoming->mData, incoming->mSize);
|
||||
} else {
|
||||
ret = ReadMsg(aFd, incoming->mData, incoming->mSize);
|
||||
}
|
||||
|
||||
if (ret <= 0) {
|
||||
if (ret == -1) {
|
||||
if (errno == EINTR) {
|
||||
continue; // retry system call when interrupted
|
||||
}
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return; // no data available: return and re-poll
|
||||
}
|
||||
|
||||
BT_WARNING("Cannot read from network");
|
||||
// else fall through to error handling on other errno's
|
||||
}
|
||||
|
||||
// We're done with our descriptors. Ensure that spurious events don't
|
||||
// cause us to end up back here.
|
||||
mReadWatcher.StopWatchingFileDescriptor();
|
||||
mWriteWatcher.StopWatchingFileDescriptor();
|
||||
nsRefPtr<RequestClosingSocketTask> t = new RequestClosingSocketTask(this);
|
||||
NS_DispatchToMainThread(t);
|
||||
return;
|
||||
}
|
||||
|
||||
incoming->mSize = ret;
|
||||
nsRefPtr<SocketReceiveTask> t =
|
||||
new SocketReceiveTask(this, incoming.forget());
|
||||
NS_DispatchToMainThread(t);
|
||||
|
||||
// If ret is less than MAX_READ_SIZE, there's no
|
||||
// more data in the socket for us to read now.
|
||||
if (ret < ssize_t(MAX_READ_SIZE)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_CRASH("We returned early");
|
||||
}
|
||||
|
||||
void
|
||||
DroidSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
||||
MOZ_ASSERT(aFd >= 0);
|
||||
|
||||
// Try to write the bytes of mCurrentRilRawData. If all were written, continue.
|
||||
//
|
||||
// Otherwise, save the byte position of the next byte to write
|
||||
// within mCurrentWriteOffset, and request another write when the
|
||||
// system won't block.
|
||||
//
|
||||
while (true) {
|
||||
UnixSocketRawData* data;
|
||||
if (mOutgoingQ.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
data = mOutgoingQ.ElementAt(0);
|
||||
const uint8_t *toWrite;
|
||||
toWrite = data->mData;
|
||||
|
||||
while (data->mCurrentWriteOffset < data->mSize) {
|
||||
ssize_t write_amount = data->mSize - data->mCurrentWriteOffset;
|
||||
ssize_t written;
|
||||
written = write (aFd, toWrite + data->mCurrentWriteOffset,
|
||||
write_amount);
|
||||
if (written > 0) {
|
||||
data->mCurrentWriteOffset += written;
|
||||
}
|
||||
if (written != write_amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->mCurrentWriteOffset != data->mSize) {
|
||||
MessageLoopForIO::current()->WatchFileDescriptor(
|
||||
aFd,
|
||||
false,
|
||||
MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher,
|
||||
this);
|
||||
return;
|
||||
}
|
||||
mOutgoingQ.RemoveElementAt(0);
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
|
||||
BluetoothSocketType aType,
|
||||
bool aAuth,
|
||||
bool aEncrypt)
|
||||
: mObserver(aObserver)
|
||||
, mType(aType)
|
||||
, mImpl(nullptr)
|
||||
, mAuth(aAuth)
|
||||
, mEncrypt(aEncrypt)
|
||||
, mReceivedSocketInfoLength(0)
|
||||
{
|
||||
MOZ_ASSERT(aObserver);
|
||||
|
||||
EnsureBluetoothSocketHalLoad();
|
||||
mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothSocket::CloseDroidSocket()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mImpl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// From this point on, we consider mImpl as being deleted.
|
||||
// We sever the relationship here so any future calls to listen or connect
|
||||
// will create a new implementation.
|
||||
mImpl->ShutdownOnMainThread();
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
new ShutdownSocketTask(mImpl));
|
||||
mImpl = nullptr;
|
||||
|
||||
OnDisconnect();
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothSocket::Connect(const nsACString& aDeviceAddress, int aChannel)
|
||||
BluetoothSocket::CreateDroidSocket(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_FALSE(mImpl, false);
|
||||
|
||||
mImpl = new DroidSocketImpl(this, aFd);
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
new SocketSetUpIOTask(mImpl, !mIsServer));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothSocket::Connect(const nsAString& aDeviceAddress, int aChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
|
||||
NS_ENSURE_TRUE(sBluetoothSocketInterface, false);
|
||||
|
||||
nsAutoPtr<BluetoothUnixSocketConnector> c(
|
||||
new BluetoothUnixSocketConnector(mType, aChannel, mAuth, mEncrypt));
|
||||
bt_bdaddr_t remoteBdAddress;
|
||||
StringToBdAddressType(aDeviceAddress, &remoteBdAddress);
|
||||
|
||||
if (!ConnectSocket(c.forget(), aDeviceAddress.BeginReading())) {
|
||||
nsAutoString addr;
|
||||
GetAddress(addr);
|
||||
BT_LOGD("%s failed. Current connected device address: %s",
|
||||
__FUNCTION__, NS_ConvertUTF16toUTF8(addr).get());
|
||||
return false;
|
||||
}
|
||||
// TODO: uuid as argument
|
||||
int fd;
|
||||
NS_ENSURE_TRUE(BT_STATUS_SUCCESS ==
|
||||
sBluetoothSocketInterface->connect((bt_bdaddr_t *) &remoteBdAddress,
|
||||
(btsock_type_t) BTSOCK_RFCOMM,
|
||||
UUID_OBEX_OBJECT_PUSH,
|
||||
aChannel, &fd, (mAuth << 1) | mEncrypt),
|
||||
false);
|
||||
NS_ENSURE_TRUE(fd >= 0, false);
|
||||
|
||||
return true;
|
||||
mIsServer = false;
|
||||
return CreateDroidSocket(fd);
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothSocket::Listen(int aChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(sBluetoothSocketInterface, false);
|
||||
|
||||
nsAutoPtr<BluetoothUnixSocketConnector> c(
|
||||
new BluetoothUnixSocketConnector(mType, aChannel, mAuth, mEncrypt));
|
||||
// TODO: uuid and service name as arguments
|
||||
nsAutoCString serviceName("OBEX Object Push");
|
||||
int fd;
|
||||
NS_ENSURE_TRUE(BT_STATUS_SUCCESS ==
|
||||
sBluetoothSocketInterface->listen((btsock_type_t) BTSOCK_RFCOMM,
|
||||
serviceName.get(),
|
||||
UUID_OBEX_OBJECT_PUSH,
|
||||
aChannel, &fd, (mAuth << 1) | mEncrypt),
|
||||
false);
|
||||
NS_ENSURE_TRUE(fd >= 0, false);
|
||||
|
||||
if (!ListenSocket(c.forget())) {
|
||||
nsAutoString addr;
|
||||
GetAddress(addr);
|
||||
BT_LOGD("%s failed. Current connected device address: %s",
|
||||
__FUNCTION__, NS_ConvertUTF16toUTF8(addr).get());
|
||||
mIsServer = true;
|
||||
return CreateDroidSocket(fd);
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothSocket::SendDroidSocketData(UnixSocketRawData* aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(mImpl, false);
|
||||
|
||||
MOZ_ASSERT(!mImpl->IsShutdownOnMainThread());
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
new SocketSendTask(this, mImpl, aData));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothSocket::IsWaitingForClientFd()
|
||||
{
|
||||
return (mIsServer &&
|
||||
mReceivedSocketInfoLength == FIRST_SOCKET_INFO_MSG_LENGTH);
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothSocket::ReceiveSocketInfo(nsAutoPtr<UnixSocketRawData>& aMessage)
|
||||
{
|
||||
/**
|
||||
* 2 socket info messages (20 bytes) to receive at the beginning:
|
||||
* - 1st message: [channel:4]
|
||||
* - 2nd message: [size:2][bd address:6][channel:4][connection status:4]
|
||||
*/
|
||||
if (mReceivedSocketInfoLength >= TOTAL_SOCKET_INFO_LENGTH) {
|
||||
// We've got both socket info messages
|
||||
return false;
|
||||
}
|
||||
mReceivedSocketInfoLength += aMessage->mSize;
|
||||
|
||||
size_t offset = 0;
|
||||
if (mReceivedSocketInfoLength == FIRST_SOCKET_INFO_MSG_LENGTH) {
|
||||
// 1st message: [channel:4]
|
||||
int32_t channel = ReadInt32(aMessage->mData, &offset);
|
||||
|
||||
BT_LOGR("%s: channel %d", __FUNCTION__, channel);
|
||||
} else if (mReceivedSocketInfoLength == TOTAL_SOCKET_INFO_LENGTH) {
|
||||
// 2nd message: [size:2][bd address:6][channel:4][connection status:4]
|
||||
int16_t size = ReadInt16(aMessage->mData, &offset);
|
||||
ReadBdAddress(aMessage->mData, &offset, mDeviceAddress);
|
||||
int32_t channel = ReadInt32(aMessage->mData, &offset);
|
||||
int32_t connectionStatus = ReadInt32(aMessage->mData, &offset);
|
||||
|
||||
BT_LOGR("%s: size %d channel %d remote addr %s status %d", __FUNCTION__,
|
||||
size, channel, NS_ConvertUTF16toUTF8(mDeviceAddress).get(), connectionStatus);
|
||||
|
||||
if (connectionStatus != 0) {
|
||||
OnConnectError();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mIsServer) {
|
||||
// Connect client fd on IO thread
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
new SocketConnectClientFdTask(mImpl));
|
||||
}
|
||||
OnConnectSuccess();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -67,6 +699,10 @@ BluetoothSocket::Listen(int aChannel)
|
||||
void
|
||||
BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
|
||||
{
|
||||
if (ReceiveSocketInfo(aMessage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mObserver);
|
||||
mObserver->ReceiveSocketData(this, aMessage);
|
||||
|
@ -13,6 +13,7 @@
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothSocketObserver;
|
||||
class DroidSocketImpl;
|
||||
|
||||
class BluetoothSocket : public mozilla::ipc::UnixSocketConsumer
|
||||
{
|
||||
@ -22,11 +23,35 @@ public:
|
||||
bool aAuth,
|
||||
bool aEncrypt);
|
||||
|
||||
bool Connect(const nsACString& aDeviceAddress, int aChannel);
|
||||
/**
|
||||
* Connect to remote server as a client.
|
||||
*
|
||||
* The steps are as following:
|
||||
* 1) BluetoothSocket acquires fd from bluedroid, and creates
|
||||
* a DroidSocketImpl to watch read/write of the fd.
|
||||
* 2) DroidSocketImpl receives first 2 messages to get socket info.
|
||||
* 3) Obex client session starts.
|
||||
*/
|
||||
bool Connect(const nsAString& aDeviceAddress, int aChannel);
|
||||
|
||||
/**
|
||||
* Listen to incoming connection as a server.
|
||||
*
|
||||
* The steps are as following:
|
||||
* 1) BluetoothSocket acquires fd from bluedroid, and creates
|
||||
* a DroidSocketImpl to watch read of the fd. DroidSocketImpl
|
||||
* receives the 1st message immediately.
|
||||
* 2) When there's incoming connection, DroidSocketImpl receives
|
||||
* 2nd message to get socket info and client fd.
|
||||
* 3) DroidSocketImpl stops watching read of original fd and
|
||||
* starts to watch read/write of client fd.
|
||||
* 4) Obex server session starts.
|
||||
*/
|
||||
bool Listen(int aChannel);
|
||||
|
||||
inline void Disconnect()
|
||||
{
|
||||
CloseSocket();
|
||||
CloseDroidSocket();
|
||||
}
|
||||
|
||||
virtual void OnConnectSuccess() MOZ_OVERRIDE;
|
||||
@ -37,14 +62,24 @@ public:
|
||||
|
||||
inline void GetAddress(nsAString& aDeviceAddress)
|
||||
{
|
||||
GetSocketAddr(aDeviceAddress);
|
||||
aDeviceAddress = mDeviceAddress;
|
||||
}
|
||||
|
||||
void CloseDroidSocket();
|
||||
bool IsWaitingForClientFd();
|
||||
bool SendDroidSocketData(mozilla::ipc::UnixSocketRawData* aData);
|
||||
|
||||
private:
|
||||
BluetoothSocketObserver* mObserver;
|
||||
BluetoothSocketType mType;
|
||||
DroidSocketImpl* mImpl;
|
||||
nsString mDeviceAddress;
|
||||
bool mAuth;
|
||||
bool mEncrypt;
|
||||
bool mIsServer;
|
||||
int mReceivedSocketInfoLength;
|
||||
|
||||
bool CreateDroidSocket(int aFd);
|
||||
bool ReceiveSocketInfo(nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage);
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
@ -20,8 +20,9 @@
|
||||
|
||||
#include <hardware/hardware.h>
|
||||
|
||||
#include "bluedroid/BluetoothA2dpManager.h"
|
||||
#include "bluedroid/BluetoothHfpManager.h"
|
||||
#include "BluetoothA2dpManager.h"
|
||||
#include "BluetoothHfpManager.h"
|
||||
#include "BluetoothOppManager.h"
|
||||
#include "BluetoothProfileController.h"
|
||||
#include "BluetoothReplyRunnable.h"
|
||||
#include "BluetoothUtils.h"
|
||||
@ -115,6 +116,12 @@ public:
|
||||
bs->AdapterAddedReceived();
|
||||
bs->TryFiringAdapterAdded();
|
||||
|
||||
// Trigger BluetoothOppManager to listen
|
||||
BluetoothOppManager* opp = BluetoothOppManager::Get();
|
||||
if (!opp || !opp->Listen()) {
|
||||
BT_LOGR("%s: Fail to start BluetoothOppManager listening", __FUNCTION__);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
@ -1290,14 +1297,45 @@ BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress,
|
||||
BlobChild* aBlobChild,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Force to stop discovery, otherwise socket connecting would fail
|
||||
if (!IsReady() || BT_STATUS_SUCCESS != sBtInterface->cancel_discovery()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Calling cancel_discovery() failed");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Currently we only support one device sending one file at a time,
|
||||
// so we don't need aDeviceAddress here because the target device
|
||||
// has been determined when calling 'Connect()'. Nevertheless, keep
|
||||
// it for future use.
|
||||
BluetoothOppManager* opp = BluetoothOppManager::Get();
|
||||
nsAutoString errorStr;
|
||||
if (!opp || !opp->SendFile(aDeviceAddress, aBlobParent)) {
|
||||
errorStr.AssignLiteral("Calling SendFile() failed");
|
||||
}
|
||||
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::StopSendingFile(const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Currently we only support one device sending one file at a time,
|
||||
// so we don't need aDeviceAddress here because the target device
|
||||
// has been determined when calling 'Connect()'. Nevertheless, keep
|
||||
// it for future use.
|
||||
BluetoothOppManager* opp = BluetoothOppManager::Get();
|
||||
nsAutoString errorStr;
|
||||
if (!opp || !opp->StopSendingFile()) {
|
||||
errorStr.AssignLiteral("Calling StopSendingFile() failed");
|
||||
}
|
||||
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1305,7 +1343,19 @@ BluetoothServiceBluedroid::ConfirmReceivingFile(
|
||||
const nsAString& aDeviceAddress, bool aConfirm,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be called from main thread!");
|
||||
|
||||
// Currently we only support one device sending one file at a time,
|
||||
// so we don't need aDeviceAddress here because the target device
|
||||
// has been determined when calling 'Connect()'. Nevertheless, keep
|
||||
// it for future use.
|
||||
BluetoothOppManager* opp = BluetoothOppManager::Get();
|
||||
nsAutoString errorStr;
|
||||
if (!opp || !opp->ConfirmReceivingFile(aConfirm)) {
|
||||
errorStr.AssignLiteral("Calling ConfirmReceivingFile() failed");
|
||||
}
|
||||
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2971,10 +2971,8 @@ BluetoothDBusService::SendFile(const nsAString& aDeviceAddress,
|
||||
// has been determined when calling 'Connect()'. Nevertheless, keep
|
||||
// it for future use.
|
||||
BluetoothOppManager* opp = BluetoothOppManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(opp);
|
||||
|
||||
nsAutoString errorStr;
|
||||
if (!opp->SendFile(aDeviceAddress, aBlobParent)) {
|
||||
if (!opp || !opp->SendFile(aDeviceAddress, aBlobParent)) {
|
||||
errorStr.AssignLiteral("Calling SendFile() failed");
|
||||
}
|
||||
|
||||
@ -2992,10 +2990,8 @@ BluetoothDBusService::StopSendingFile(const nsAString& aDeviceAddress,
|
||||
// has been determined when calling 'Connect()'. Nevertheless, keep
|
||||
// it for future use.
|
||||
BluetoothOppManager* opp = BluetoothOppManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(opp);
|
||||
|
||||
nsAutoString errorStr;
|
||||
if (!opp->StopSendingFile()) {
|
||||
if (!opp || !opp->StopSendingFile()) {
|
||||
errorStr.AssignLiteral("Calling StopSendingFile() failed");
|
||||
}
|
||||
|
||||
@ -3007,17 +3003,15 @@ BluetoothDBusService::ConfirmReceivingFile(const nsAString& aDeviceAddress,
|
||||
bool aConfirm,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be called from main thread!");
|
||||
|
||||
// Currently we only support one device sending one file at a time,
|
||||
// so we don't need aDeviceAddress here because the target device
|
||||
// has been determined when calling 'Connect()'. Nevertheless, keep
|
||||
// it for future use.
|
||||
BluetoothOppManager* opp = BluetoothOppManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(opp);
|
||||
|
||||
nsAutoString errorStr;
|
||||
if (!opp->ConfirmReceivingFile(aConfirm)) {
|
||||
if (!opp || !opp->ConfirmReceivingFile(aConfirm)) {
|
||||
errorStr.AssignLiteral("Calling ConfirmReceivingFile() failed");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user