You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
8.6 KiB
274 lines
8.6 KiB
/******************************************************************************
|
|
*
|
|
* Copyright 2021 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 "BtGdWakelock"
|
|
|
|
#include "os/wakelock_manager.h"
|
|
|
|
#include <cerrno>
|
|
#include <mutex>
|
|
|
|
#include "os/internal/wakelock_native.h"
|
|
#include "os/log.h"
|
|
|
|
namespace bluetooth {
|
|
namespace os {
|
|
|
|
using internal::WakelockNative;
|
|
using StatusCode = WakelockNative::StatusCode;
|
|
|
|
uint64_t now_ms() {
|
|
struct timespec ts = {};
|
|
if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1) {
|
|
LOG_ERROR("unable to get current time: %s", strerror(errno));
|
|
return 0;
|
|
}
|
|
return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
|
|
}
|
|
|
|
const std::string WakelockManager::kBtWakelockId = "bluetooth_gd_timer";
|
|
|
|
// Wakelock statistics for the "bluetooth_timer"
|
|
struct WakelockManager::Stats {
|
|
bool is_acquired = false;
|
|
size_t acquired_count = 0;
|
|
size_t released_count = 0;
|
|
size_t acquired_errors = 0;
|
|
size_t released_errors = 0;
|
|
uint64_t min_acquired_interval_ms = 0;
|
|
uint64_t max_acquired_interval_ms = 0;
|
|
uint64_t last_acquired_interval_ms = 0;
|
|
uint64_t total_acquired_interval_ms = 0;
|
|
uint64_t last_acquired_timestamp_ms = 0;
|
|
uint64_t last_released_timestamp_ms = 0;
|
|
uint64_t last_reset_timestamp_ms = now_ms();
|
|
StatusCode last_acquired_error = StatusCode::SUCCESS;
|
|
StatusCode last_released_error = StatusCode::SUCCESS;
|
|
|
|
void Reset() {
|
|
is_acquired = false;
|
|
acquired_count = 0;
|
|
released_count = 0;
|
|
acquired_errors = 0;
|
|
released_errors = 0;
|
|
min_acquired_interval_ms = 0;
|
|
max_acquired_interval_ms = 0;
|
|
last_acquired_interval_ms = 0;
|
|
total_acquired_interval_ms = 0;
|
|
last_acquired_timestamp_ms = 0;
|
|
last_released_timestamp_ms = 0;
|
|
last_reset_timestamp_ms = now_ms();
|
|
last_acquired_error = StatusCode::SUCCESS;
|
|
last_released_error = StatusCode::SUCCESS;
|
|
}
|
|
|
|
// Update the Bluetooth acquire wakelock statistics.
|
|
//
|
|
// This function should be called every time when the wakelock is acquired.
|
|
// |acquired_status| is the status code that was return when the wakelock was
|
|
// acquired.
|
|
void UpdateAcquiredStats(StatusCode acquired_status) {
|
|
const uint64_t just_now_ms = now_ms();
|
|
if (acquired_status != StatusCode::SUCCESS) {
|
|
acquired_errors++;
|
|
last_acquired_error = acquired_status;
|
|
}
|
|
|
|
if (is_acquired) {
|
|
return;
|
|
}
|
|
|
|
is_acquired = true;
|
|
acquired_count++;
|
|
last_acquired_timestamp_ms = just_now_ms;
|
|
}
|
|
|
|
// Update the Bluetooth release wakelock statistics.
|
|
//
|
|
// This function should be called every time when the wakelock is released.
|
|
// |released_status| is the status code that was return when the wakelock was
|
|
// released.
|
|
void UpdateReleasedStats(StatusCode released_status) {
|
|
const uint64_t just_now_ms = now_ms();
|
|
if (released_status != StatusCode::SUCCESS) {
|
|
released_errors++;
|
|
last_released_error = released_status;
|
|
}
|
|
|
|
if (!is_acquired) {
|
|
return;
|
|
}
|
|
|
|
is_acquired = false;
|
|
released_count++;
|
|
last_released_timestamp_ms = just_now_ms;
|
|
|
|
// Compute the acquired interval and update the statistics
|
|
uint64_t delta_ms = just_now_ms - last_acquired_timestamp_ms;
|
|
if (delta_ms < min_acquired_interval_ms || released_count == 1) {
|
|
min_acquired_interval_ms = delta_ms;
|
|
}
|
|
if (delta_ms > max_acquired_interval_ms) {
|
|
max_acquired_interval_ms = delta_ms;
|
|
}
|
|
last_acquired_interval_ms = delta_ms;
|
|
total_acquired_interval_ms += delta_ms;
|
|
}
|
|
|
|
flatbuffers::Offset<WakelockManagerData> GetDumpsysData(
|
|
flatbuffers::FlatBufferBuilder* fb_builder, bool is_native) const {
|
|
const uint64_t just_now_ms = now_ms();
|
|
// Compute the last acquired interval if the wakelock is still acquired
|
|
uint64_t delta_ms = 0;
|
|
uint64_t last_interval_ms = last_acquired_interval_ms;
|
|
uint64_t min_interval_ms = min_acquired_interval_ms;
|
|
uint64_t max_interval_ms = max_acquired_interval_ms;
|
|
uint64_t avg_interval_ms = 0;
|
|
|
|
if (is_acquired) {
|
|
delta_ms = just_now_ms - last_acquired_timestamp_ms;
|
|
if (delta_ms > max_interval_ms) {
|
|
max_interval_ms = delta_ms;
|
|
}
|
|
if (delta_ms < min_interval_ms) {
|
|
min_interval_ms = delta_ms;
|
|
}
|
|
last_interval_ms = delta_ms;
|
|
}
|
|
uint64_t total_interval_ms = total_acquired_interval_ms + delta_ms;
|
|
|
|
if (acquired_count > 0) {
|
|
avg_interval_ms = total_interval_ms / acquired_count;
|
|
}
|
|
|
|
WakelockManagerDataBuilder builder(*fb_builder);
|
|
builder.add_title(fb_builder->CreateString("Bluetooth Wakelock Statistics"));
|
|
builder.add_is_acquired(is_acquired);
|
|
builder.add_is_native(is_native);
|
|
builder.add_acquired_count(acquired_count);
|
|
builder.add_released_count(released_count);
|
|
builder.add_acquired_error_count(acquired_errors);
|
|
builder.add_released_error_count(released_errors);
|
|
builder.add_last_acquire_error_code(last_acquired_error);
|
|
builder.add_last_release_error_code(last_released_error);
|
|
builder.add_last_acquired_timestamp_millis(last_interval_ms);
|
|
builder.add_last_released_timestamp_millis(last_released_timestamp_ms);
|
|
builder.add_last_interval_millis(last_acquired_interval_ms);
|
|
builder.add_max_interval_millis(max_interval_ms);
|
|
builder.add_min_interval_millis(min_interval_ms);
|
|
builder.add_avg_interval_millis(avg_interval_ms);
|
|
builder.add_total_interval_millis(total_interval_ms);
|
|
builder.add_total_time_since_reset_millis(just_now_ms - last_reset_timestamp_ms);
|
|
return builder.Finish();
|
|
}
|
|
};
|
|
|
|
void WakelockManager::SetOsCallouts(OsCallouts* callouts, Handler* handler) {
|
|
std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
|
|
if (initialized_) {
|
|
LOG_WARN("Setting OS callouts after initialization can lead to wakelock leak!");
|
|
}
|
|
os_callouts_ = callouts;
|
|
os_callouts_handler_ = handler;
|
|
is_native_ = (os_callouts_ == nullptr);
|
|
if (is_native_) {
|
|
ASSERT_LOG(os_callouts_handler_ != nullptr, "handler must not be null when callout is not null");
|
|
}
|
|
LOG_INFO("set to %s", is_native_ ? "native" : "non-native");
|
|
}
|
|
|
|
bool WakelockManager::Acquire() {
|
|
std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
|
|
if (!initialized_) {
|
|
if (is_native_) {
|
|
WakelockNative::Get().Initialize();
|
|
}
|
|
initialized_ = true;
|
|
}
|
|
|
|
StatusCode status;
|
|
if (is_native_) {
|
|
status = WakelockNative::Get().Acquire(kBtWakelockId);
|
|
} else {
|
|
os_callouts_handler_->CallOn(os_callouts_, &OsCallouts::AcquireCallout, kBtWakelockId);
|
|
status = StatusCode::SUCCESS;
|
|
}
|
|
|
|
pstats_->UpdateAcquiredStats(status);
|
|
|
|
if (status != StatusCode::SUCCESS) {
|
|
LOG_ERROR("unable to acquire wake lock, error code: %u", status);
|
|
}
|
|
|
|
return status == StatusCode ::SUCCESS;
|
|
}
|
|
|
|
bool WakelockManager::Release() {
|
|
std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
|
|
if (!initialized_) {
|
|
if (is_native_) {
|
|
WakelockNative::Get().Initialize();
|
|
}
|
|
initialized_ = true;
|
|
}
|
|
|
|
StatusCode status;
|
|
if (is_native_) {
|
|
status = WakelockNative::Get().Release(kBtWakelockId);
|
|
} else {
|
|
os_callouts_handler_->CallOn(os_callouts_, &OsCallouts::ReleaseCallout, kBtWakelockId);
|
|
status = StatusCode ::SUCCESS;
|
|
}
|
|
|
|
pstats_->UpdateReleasedStats(status);
|
|
|
|
if (status != StatusCode::SUCCESS) {
|
|
LOG_ERROR("unable to release wake lock, error code: %u", status);
|
|
}
|
|
|
|
return status == StatusCode ::SUCCESS;
|
|
}
|
|
|
|
void WakelockManager::CleanUp() {
|
|
std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
|
|
if (!initialized_) {
|
|
LOG_ERROR("Already uninitialized");
|
|
return;
|
|
}
|
|
if (pstats_->is_acquired) {
|
|
LOG_ERROR("Releasing wake lock as part of cleanup");
|
|
Release();
|
|
}
|
|
if (is_native_) {
|
|
WakelockNative::Get().CleanUp();
|
|
}
|
|
pstats_->Reset();
|
|
initialized_ = false;
|
|
}
|
|
|
|
flatbuffers::Offset<WakelockManagerData> WakelockManager::GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) {
|
|
std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
|
|
return pstats_->GetDumpsysData(fb_builder, is_native_);
|
|
}
|
|
|
|
WakelockManager::WakelockManager() : pstats_(std::make_unique<Stats>()) {}
|
|
|
|
WakelockManager::~WakelockManager() = default;
|
|
|
|
} // namespace os
|
|
} // namespace bluetooth
|