blob: 1c22680454f15f0cf71edd96671351f09f839cd3 [file] [log] [blame] [edit]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* 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 "chre_host/metrics_reporter.h"
#include <chre_atoms_log.h>
#include "chre_host/log.h"
#include <cinttypes>
#include <limits>
#include <mutex>
#include <android/binder_manager.h>
namespace android::chre {
using ::aidl::android::frameworks::stats::IStats;
using ::aidl::android::frameworks::stats::VendorAtom;
using ::aidl::android::frameworks::stats::VendorAtomValue;
using ::android::chre::Atoms::CHRE_AP_WAKE_UP_OCCURRED;
using ::android::chre::Atoms::CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED;
using ::android::chre::Atoms::CHRE_HAL_NANOAPP_LOAD_FAILED;
using ::android::chre::Atoms::CHRE_PAL_OPEN_FAILED;
using ::android::chre::Atoms::ChreHalNanoappLoadFailed;
using ::android::chre::Atoms::ChrePalOpenFailed;
std::shared_ptr<IStats> MetricsReporter::getStatsService() {
const std::string statsServiceName =
std::string(IStats::descriptor).append("/default");
if (!AServiceManager_isDeclared(statsServiceName.c_str())) {
LOGE("Stats service is not declared.");
return nullptr;
}
ndk::SpAIBinder statsServiceBinder =
ndk::SpAIBinder(AServiceManager_waitForService(statsServiceName.c_str()));
if (statsServiceBinder.get() == nullptr) {
LOGE("Failed to get the IStats service binder");
return nullptr;
}
binder_status_t status = AIBinder_linkToDeath(
statsServiceBinder.get(), AIBinder_DeathRecipient_new([](void *cookie) {
auto *metricsReporter = static_cast<MetricsReporter *>(cookie);
metricsReporter->onBinderDied();
}),
this);
if (status != STATUS_OK) {
LOGE("Failed to link to death the stats service binder");
return nullptr;
}
std::shared_ptr<IStats> statsService = IStats::fromBinder(statsServiceBinder);
if (statsService == nullptr) {
LOGE("Failed to get IStats service");
return nullptr;
}
return statsService;
}
bool MetricsReporter::reportMetric(const VendorAtom &atom) {
ndk::ScopedAStatus ret;
{
std::lock_guard<std::mutex> lock(mStatsServiceMutex);
if (mStatsService == nullptr) {
mStatsService = getStatsService();
if (mStatsService == nullptr) {
return false;
}
}
ret = mStatsService->reportVendorAtom(atom);
}
if (!ret.isOk()) {
LOGE("Failed to report vendor atom with ID %" PRIi32, atom.atomId);
}
return ret.isOk();
}
bool MetricsReporter::logApWakeupOccurred(uint64_t nanoappId) {
std::vector<VendorAtomValue> values(1);
values[0].set<VendorAtomValue::longValue>(nanoappId);
const VendorAtom atom{
.atomId = CHRE_AP_WAKE_UP_OCCURRED,
.values{std::move(values)},
};
return reportMetric(atom);
}
bool MetricsReporter::logNanoappLoadFailed(
uint64_t nanoappId, ChreHalNanoappLoadFailed::Type type,
ChreHalNanoappLoadFailed::Reason reason) {
std::vector<VendorAtomValue> values(3);
values[0].set<VendorAtomValue::longValue>(nanoappId);
values[1].set<VendorAtomValue::intValue>(type);
values[2].set<VendorAtomValue::intValue>(reason);
const VendorAtom atom{
.atomId = CHRE_HAL_NANOAPP_LOAD_FAILED,
.values{std::move(values)},
};
return reportMetric(atom);
}
bool MetricsReporter::logPalOpenFailed(ChrePalOpenFailed::ChrePalType pal,
ChrePalOpenFailed::Type type) {
std::vector<VendorAtomValue> values(2);
values[0].set<VendorAtomValue::intValue>(pal);
values[1].set<VendorAtomValue::intValue>(type);
const VendorAtom atom{
.atomId = CHRE_PAL_OPEN_FAILED,
.values{std::move(values)},
};
return reportMetric(atom);
}
bool MetricsReporter::logEventQueueSnapshotReported(
int32_t snapshotChreGetTimeMs, int32_t maxEventQueueSize,
int32_t meanEventQueueSize, int32_t numDroppedEvents) {
std::vector<VendorAtomValue> values(6);
values[0].set<VendorAtomValue::intValue>(snapshotChreGetTimeMs);
values[1].set<VendorAtomValue::intValue>(maxEventQueueSize);
values[2].set<VendorAtomValue::intValue>(meanEventQueueSize);
values[3].set<VendorAtomValue::intValue>(numDroppedEvents);
// TODO(b/298459533): Implement these two values
// Last two values are not currently populated and will be implemented
// later. To avoid confusion of the interpretation, we use UINT32_MAX
// as a placeholder value.
values[4].set<VendorAtomValue::longValue>(
std::numeric_limits<int64_t>::max());
values[5].set<VendorAtomValue::longValue>(
std::numeric_limits<int64_t>::max());
const VendorAtom atom{
.atomId = CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED,
.values{std::move(values)},
};
return reportMetric(atom);
}
void MetricsReporter::onBinderDied() {
LOGI("MetricsReporter: stats service died - reconnecting");
std::lock_guard<std::mutex> lock(mStatsServiceMutex);
mStatsService.reset();
mStatsService = getStatsService();
}
} // namespace android::chre