blob: f73edfb5fcc318a7e715d4da946e34647cc1a22b [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2017, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright (C) 2017 Google, Inc.
*
* 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.
*
******************************************************************************/
#include "android/hardware/bluetooth/1.0/IBluetoothHci.h"
#include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
#include <android/hardware/bluetooth/1.0/types.h>
#include <hwbinder/ProcessState.h>
#include <com/qualcomm/qti/ant/1.0/IAntHci.h>
#include <com/qualcomm/qti/ant/1.0/IAntHciCallbacks.h>
#include <com/qualcomm/qti/ant/1.0/types.h>
#include <vendor/qti/hardware/fm/1.0/IFmHci.h>
#include <vendor/qti/hardware/fm/1.0/IFmHciCallbacks.h>
#include <vendor/qti/hardware/fm/1.0/types.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <semaphore.h>
#include <errno.h>
#include <stdlib.h>
#include <utils/Log.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include "hidl_client.h"
#include "hci_internals.h"
using android::hardware::bluetooth::V1_0::IBluetoothHci;
using android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
using android::hardware::bluetooth::V1_0::HciPacket;
using android::hardware::bluetooth::V1_0::Status;
using com::qualcomm::qti::ant::V1_0::IAntHci;
using com::qualcomm::qti::ant::V1_0::IAntHciCallbacks;
using vendor::qti::hardware::fm::V1_0::IFmHci;
using vendor::qti::hardware::fm::V1_0::IFmHciCallbacks;
using android::hardware::ProcessState;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
extern void initialization_complete();
extern void *process_tool_data(void *arg);
static int safe_write(int server_fd, unsigned char* buf, int write_len);
static pthread_t client_rthread;
#define BT_CMD_PACKET_TYPE 0x01
#define BT_ACL_PACKET_TYPE 0x02
#define BT_SCO_PACKET_TYPE 0x03
#define BT_EVT_PACKET_TYPE 0x04
#define ANT_CTRL_PACKET_TYPE 0x0c
#define ANT_DATA_PACKET_TYPE 0x0e
#define FM_CMD_PACKET_TYPE 0x11
#define FM_EVT_PACKET_TYPE 0x14
#define INVALID_FD (-1)
static sem_t s_cond;
static int mode_type;
static volatile bool hidl_init = false;
int server_fd = -1;
int client_fd = -1;
android::sp<IBluetoothHci> btHci;
android::sp<IAntHci> antHci;
android::sp<IFmHci> fmHci;
class BluetoothHciCallbacks : public IBluetoothHciCallbacks {
public:
Return<void> initializationComplete(Status status) {
if (status == Status::SUCCESS) {
hidl_init = true;
} else {
ALOGE("Error in HIDL initialization");
}
sem_post(&s_cond);
return Void();
}
Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
int len = static_cast<int>(event.size());
unsigned char val = BT_EVT_PACKET_TYPE;
if (safe_write(server_fd, &val, 1) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
if (safe_write(server_fd, const_cast<unsigned char*>(event.data()), len) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
return Void();
}
Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
int len = static_cast<int>(data.size());
unsigned char val = BT_ACL_PACKET_TYPE;
if (safe_write(server_fd, &val, 1) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
if (safe_write(server_fd, const_cast<unsigned char*>(data.data()), len) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
return Void();
}
Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
int len = static_cast<int>(data.size());
unsigned char val = BT_SCO_PACKET_TYPE;
if (safe_write(server_fd, &val, 1) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
if (safe_write(server_fd, const_cast<unsigned char*>(data.data()), len) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
return Void();
}
};
namespace
{
using com::qualcomm::qti::ant::V1_0::AntPacket;
using com::qualcomm::qti::ant::V1_0::Status;
class AntHciCallbacks : public IAntHciCallbacks {
public:
AntHciCallbacks() {};
virtual ~AntHciCallbacks() = default;
Return<void> initializationComplete(Status status)
{
ALOGI("%s: start ", __func__);
if (status == Status::SUCCESS) {
hidl_init = true;
} else {
ALOGE("Error in HIDL initialization");
}
sem_post(&s_cond);
ALOGI("%s:end", __func__);
return Void();
}
Return<void> antControlReceived(const hidl_vec<uint8_t>& event)
{
int len = static_cast<int>(event.size());
unsigned char val = ANT_CTRL_PACKET_TYPE;
if (safe_write(server_fd, &val, 1) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
if (safe_write(server_fd, const_cast<unsigned char*>(event.data()), len) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
return Void();
}
Return<void> antDataReceived(const hidl_vec<uint8_t>& event)
{
int len = static_cast<int>(event.size());
unsigned char val = ANT_DATA_PACKET_TYPE;
if (safe_write(server_fd, &val, 1) == -1) {
return Void();
}
if (safe_write(server_fd, const_cast<unsigned char*>(event.data()), len) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
return Void();
}
};
namespace
{
using vendor::qti::hardware::fm::V1_0::HciPacket;
using vendor::qti::hardware::fm::V1_0::Status;
class FmHciCallbacks : public IFmHciCallbacks {
public:
FmHciCallbacks() {
};
virtual ~FmHciCallbacks() = default;
Return<void> initializationComplete(Status status) {
ALOGV("%s: start ", __func__);
if (status == Status::SUCCESS) {
hidl_init = true;
} else {
ALOGE("Error in HIDL initialization");
}
sem_post(&s_cond);
ALOGI("%s:end", __func__);
return Void();
}
Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
int len = static_cast<int>(event.size());
ALOGV("%s: start ", __func__);
unsigned char val = FM_EVT_PACKET_TYPE;
if (safe_write(server_fd, &val, 1) == -1) {
return Void();
}
if (safe_write(server_fd, const_cast<unsigned char*>(event.data()), len) == -1) {
ALOGE("%s: failed to write event to tool socket", __func__);
return Void();
}
return Void();
}
};
}
}
#ifdef __cplusplus
extern "C"
{
#endif
bool hidl_client_initialize(int mode, int *tool_fd) {
mode_type = mode;
if (tool_fd == NULL) {
ALOGE("%s: Invalid tool FD", __func__);
return false;
}
switch (mode) {
case MODE_BT:
ALOGI("%s: Initialize the HIDL with Mode BT", __func__);
btHci = IBluetoothHci::getService();
// If android.hardware.bluetooth* is not found, Bluetooth can not continue.
if (btHci != nullptr) {
ALOGI("%s: IBluetoothHci::getService() returned %p (%s)",
__func__, btHci.get(), (btHci->isRemote() ? "remote" : "local"));
} else {
ALOGE("Unable to initialize the HIDL");
return false;
}
{
android::sp<IBluetoothHciCallbacks> callbacks = new BluetoothHciCallbacks();
hidl_init = false;
sem_init(&s_cond, 0, 0);
btHci->initialize(callbacks);
// waiting for initialisation callback
sem_wait(&s_cond);
}
if (hidl_init == true) {
break;
} else {
ALOGE("%s: HIDL failed to initialize, sending invalid FD to tool", __func__);
return false;
}
case MODE_ANT:
ALOGI("%s: Initialize the HIDL with Mode ANT", __func__);
antHci = IAntHci::getService();
if (antHci != nullptr) {
ALOGI("%s: IAntHci::getService() returned %p (%s)",
__func__, antHci.get(), (antHci->isRemote() ? "remote" : "local"));
} else {
ALOGE("Unable to initialize the HIDL");
return false;
}
{
android::sp<IAntHciCallbacks> callbacks = new AntHciCallbacks();
hidl_init = false;
sem_init(&s_cond, 0, 0);
antHci->initialize(callbacks);
// waiting for initialisation callback
ALOGV("%s: Wait for initialisation callback", __func__);
sem_wait(&s_cond);
}
if (hidl_init == true) {
break;
} else {
ALOGE("%s: HIDL failed to initialize, sending invalid FD to tool", __func__);
return false;
}
case MODE_FM:
ALOGI("%s: Initialize the HIDL with Mode FM", __func__);
fmHci = IFmHci::getService();
if (fmHci != nullptr) {
ALOGI("%s: IFmHci::getService() returned %p (%s)",
__func__, fmHci.get(), (fmHci->isRemote() ? "remote" : "local"));
} else {
ALOGE("Unable to initialize the HIDL");
return false;
}
{
android::sp<IFmHciCallbacks> callbacks = new FmHciCallbacks();
hidl_init = false;
sem_init(&s_cond, 0, 0);
fmHci->initialize(callbacks);
// waiting for initialisation callback
ALOGV("%s: Wait for initialisation callback", __func__);
sem_wait(&s_cond);
}
if (hidl_init == true) {
if (client_fd > 0) {
*tool_fd = client_fd;
return true;
}
break;
} else {
ALOGE("%s: HIDL failed to initialize, sending invalid FD to tool", __func__);
return false;
}
break;
default:
ALOGE("Unsupported mode");
return false;
}
// creating a scoket pair
int fds[2] = {INVALID_FD, INVALID_FD};
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) == -1) {
ALOGE("%s error creating socketpair: %s", __func__,strerror(errno));
return false;
}
server_fd = fds[0];
if (pthread_create(&client_rthread, NULL, process_tool_data, NULL) != 0) {
ALOGE("%s:Unable to create pthread err = %s", __func__, strerror(errno));
close(server_fd);
close(fds[1]);
return false;
}
client_fd = fds[1];
ALOGE("Server FD=%d Client FD: %d\n",server_fd,client_fd);
*tool_fd = client_fd;
return true;
}
// Close HIDL Client to prevent callbacks.
void hidl_client_close() {
if (hidl_init == false) {
return;
}
if (server_fd != -1) {
close(server_fd);
}
pthread_join(client_rthread, NULL);
server_fd = -1;
switch (mode_type) {
case MODE_BT:
ALOGI("%s: Close HIDL with Mode BT", __func__);
btHci->close();
btHci = nullptr;
break;
case MODE_ANT:
ALOGI("%s: Close HIDL with Mode ANT", __func__);
antHci->close();
antHci = nullptr;
break;
case MODE_FM:
ALOGI("%s: Close HIDL with Mode FM", __func__);
fmHci->close();
fmHci = nullptr;
break;
default:
ALOGE("Unsupported mode");
break;
}
return;
}
#ifdef __cplusplus
}
#endif
static int safe_write(int server_fd, unsigned char* buf, int write_len) {
int bytes_written = 0;
int ret;
if (buf == NULL) {
ALOGE("%s: The buffer is NULL", __func__);
return -1;
}
if (!write_len) {
ALOGE("%s: No data to write", __func__);
return 0;
}
while (write_len > 0) {
CLIENT_NO_INTR(ret = write(server_fd, buf+bytes_written, write_len));
if (ret < 0) {
ALOGE("%s: Write error: (%s)", __func__, strerror(errno));
return -1;
} else if (ret == 0) {
ALOGE("%s: Write returned 0, err = %s, bytes written: %d",
__func__, strerror(errno), (unsigned int)(bytes_written));
return -1;
} else {
write_len -= ret;
bytes_written += ret;
}
}
return bytes_written;
}