blob: 8f188291e2f828fc80d8f28950cb8e012cfbf9cf [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2016 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.
*
******************************************************************************/
#define LOG_TAG "bt_osi_metrics"
#include "osi/include/metrics.h"
#include <errno.h>
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "osi/src/protos/bluetooth.pb.h"
#include <base/base64.h>
#include <google/protobuf/text_format.h>
#include <mutex>
using clearcut::connectivity::A2DPSession;
using clearcut::connectivity::BluetoothLog;
using clearcut::connectivity::BluetoothSession;
using clearcut::connectivity::DeviceInfo;
using clearcut::connectivity::DeviceInfo_DeviceType;
using clearcut::connectivity::PairEvent;
using clearcut::connectivity::ScanEvent;
using clearcut::connectivity::ScanEvent_ScanTechnologyType;
using clearcut::connectivity::ScanEvent_ScanEventType;
using clearcut::connectivity::WakeEvent;
using clearcut::connectivity::WakeEvent_WakeEventType;
BluetoothLog* pending;
std::mutex log_lock;
static void lazy_initialize(void) {
if (pending == nullptr) {
pending = BluetoothLog::default_instance().New();
}
}
void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
uint32_t device_class, device_type_t device_type) {
std::lock_guard<std::mutex> lock(log_lock);
lazy_initialize();
PairEvent* event = pending->add_pair_event();
DeviceInfo* info = event->mutable_device_paired_with();
info->set_device_class(device_class);
DeviceInfo_DeviceType type = DeviceInfo::DEVICE_TYPE_UNKNOWN;
if (device_type == DEVICE_TYPE_BREDR) type = DeviceInfo::DEVICE_TYPE_BREDR;
if (device_type == DEVICE_TYPE_LE) type = DeviceInfo::DEVICE_TYPE_LE;
if (device_type == DEVICE_TYPE_DUMO) type = DeviceInfo::DEVICE_TYPE_DUMO;
info->set_device_type(type);
event->set_disconnect_reason(disconnect_reason);
event->set_event_time_millis(timestamp_ms);
}
void metrics_wake_event(wake_event_type_t type, const char* requestor,
const char* name, uint64_t timestamp_ms) {
std::lock_guard<std::mutex> lock(log_lock);
lazy_initialize();
WakeEvent* event = pending->add_wake_event();
WakeEvent_WakeEventType waketype = WakeEvent::UNKNOWN;
if (type == WAKE_EVENT_ACQUIRED) waketype = WakeEvent::ACQUIRED;
if (type == WAKE_EVENT_RELEASED) waketype = WakeEvent::RELEASED;
event->set_wake_event_type(waketype);
if (requestor) event->set_requestor(requestor);
if (name) event->set_name(name);
event->set_event_time_millis(timestamp_ms);
}
void metrics_scan_event(bool start, const char* initator, scan_tech_t type,
uint32_t results, uint64_t timestamp_ms) {
std::lock_guard<std::mutex> lock(log_lock);
lazy_initialize();
ScanEvent* event = pending->add_scan_event();
if (start)
event->set_scan_event_type(ScanEvent::SCAN_EVENT_START);
else
event->set_scan_event_type(ScanEvent::SCAN_EVENT_STOP);
if (initator) event->set_initiator(initator);
ScanEvent::ScanTechnologyType scantype = ScanEvent::SCAN_TYPE_UNKNOWN;
if (type == SCAN_TECH_TYPE_LE) scantype = ScanEvent::SCAN_TECH_TYPE_LE;
if (type == SCAN_TECH_TYPE_BREDR) scantype = ScanEvent::SCAN_TECH_TYPE_BREDR;
if (type == SCAN_TECH_TYPE_BOTH) scantype = ScanEvent::SCAN_TECH_TYPE_BOTH;
event->set_scan_technology_type(scantype);
event->set_number_results(results);
event->set_event_time_millis(timestamp_ms);
}
void metrics_a2dp_session(
int64_t session_duration_sec, const char* disconnect_reason,
uint32_t device_class, int32_t media_timer_min_ms,
int32_t media_timer_max_ms, int32_t media_timer_avg_ms,
int32_t buffer_overruns_max_count, int32_t buffer_overruns_total,
float buffer_underruns_average, int32_t buffer_underruns_count) {
std::lock_guard<std::mutex> lock(log_lock);
lazy_initialize();
BluetoothSession* bt_session = pending->add_session();
// Set connection type: for A2DP it is always BR/EDR
BluetoothSession::ConnectionTechnologyType conn_type =
BluetoothSession::CONNECTION_TECHNOLOGY_TYPE_BREDR;
bt_session->set_connection_technology_type(conn_type);
bt_session->set_session_duration_sec(session_duration_sec);
if (disconnect_reason != NULL)
bt_session->set_disconnect_reason(disconnect_reason);
// Set device: class and type are pre-defined
DeviceInfo* info = bt_session->mutable_device_connected_to();
info->set_device_class(device_class);
info->set_device_type(DeviceInfo::DEVICE_TYPE_BREDR);
A2DPSession* a2dp_session = bt_session->mutable_a2dp_session();
a2dp_session->set_media_timer_min_millis(media_timer_min_ms);
a2dp_session->set_media_timer_max_millis(media_timer_max_ms);
a2dp_session->set_media_timer_avg_millis(media_timer_avg_ms);
a2dp_session->set_buffer_overruns_max_count(buffer_overruns_max_count);
a2dp_session->set_buffer_overruns_total(buffer_overruns_total);
a2dp_session->set_buffer_underruns_average(buffer_underruns_average);
a2dp_session->set_buffer_underruns_count(buffer_underruns_count);
}
void metrics_write(int fd, bool clear) {
log_lock.lock();
LOG_DEBUG(LOG_TAG, "%s serializing metrics", __func__);
lazy_initialize();
std::string serialized;
if (!pending->SerializeToString(&serialized)) {
LOG_ERROR(LOG_TAG, "%s: error serializing metrics", __func__);
return;
}
if (clear) {
pending->Clear();
}
log_lock.unlock();
std::string protoBase64;
base::Base64Encode(serialized, &protoBase64);
ssize_t ret;
OSI_NO_INTR(ret = write(fd, protoBase64.c_str(), protoBase64.size()));
if (ret == -1) {
LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__,
strerror(errno), errno);
}
}