179 lines
6.5 KiB
C++
179 lines
6.5 KiB
C++
/*
|
|
* Copyright (C) 2022 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/core/telemetry_manager.h"
|
|
|
|
#include <pb_encode.h>
|
|
|
|
#include "chre/core/event_loop_manager.h"
|
|
#include "chre/platform/fatal_error.h"
|
|
#include "chre/platform/shared/host_protocol_chre.h"
|
|
#include "chre/util/macros.h"
|
|
#include "chre/util/nested_data_ptr.h"
|
|
#include "chre/util/time.h"
|
|
#include "pixelatoms.nanopb.h"
|
|
|
|
namespace chre {
|
|
|
|
namespace {
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! DISCLAIMER !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// The metrics implemented in this class makes use of open-sourced PixelAtoms,
|
|
// but they are not Pixel-specific, and can be extended to OEM use. If you
|
|
// would like to use this code for telemetry purposes, please contact us for
|
|
// details.
|
|
|
|
//! Helper define macros for nanopb types.
|
|
#define PIXELATOMS_GET(x) android_hardware_google_pixel_PixelAtoms_##x
|
|
#define PIXELATOMS_GET_PAL_TYPE(x) \
|
|
_android_hardware_google_pixel_PixelAtoms_ChrePalType:: \
|
|
android_hardware_google_pixel_PixelAtoms_ChrePalType_CHRE_PAL_TYPE_##x
|
|
|
|
void sendMetricToHost(uint32_t atomId, const pb_field_t fields[],
|
|
const void *data) {
|
|
size_t size;
|
|
if (!pb_get_encoded_size(&size, PIXELATOMS_GET(ChrePalOpenFailed_fields),
|
|
data)) {
|
|
LOGE("Failed to get message size");
|
|
} else {
|
|
pb_byte_t *bytes = static_cast<pb_byte_t *>(memoryAlloc(size));
|
|
if (bytes == nullptr) {
|
|
LOG_OOM();
|
|
} else {
|
|
pb_ostream_t stream = pb_ostream_from_buffer(bytes, size);
|
|
if (!pb_encode(&stream, PIXELATOMS_GET(ChrePalOpenFailed_fields), data)) {
|
|
LOGE("Failed to metric error %s", PB_GET_ERROR(&stream));
|
|
} else {
|
|
HostCommsManager &manager =
|
|
EventLoopManagerSingleton::get()->getHostCommsManager();
|
|
if (!manager.sendMetricLog(
|
|
PIXELATOMS_GET(Atom_chre_pal_open_failed_tag), bytes, size)) {
|
|
LOGE("Failed to send metric message");
|
|
}
|
|
}
|
|
memoryFree(bytes);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sendPalOpenFailedMetric(
|
|
_android_hardware_google_pixel_PixelAtoms_ChrePalType pal) {
|
|
_android_hardware_google_pixel_PixelAtoms_ChrePalOpenFailed result =
|
|
PIXELATOMS_GET(ChrePalOpenFailed_init_default);
|
|
result.has_pal = true;
|
|
result.pal = pal;
|
|
result.has_type = true;
|
|
result
|
|
.type = _android_hardware_google_pixel_PixelAtoms_ChrePalOpenFailed_Type::
|
|
android_hardware_google_pixel_PixelAtoms_ChrePalOpenFailed_Type_INITIAL_OPEN;
|
|
|
|
sendMetricToHost(PIXELATOMS_GET(Atom_chre_pal_open_failed_tag),
|
|
PIXELATOMS_GET(ChrePalOpenFailed_fields), &result);
|
|
}
|
|
|
|
void sendEventLoopStats(uint32_t maxQueueSize, uint32_t meanQueueSize,
|
|
uint32_t numDroppedEvents) {
|
|
_android_hardware_google_pixel_PixelAtoms_ChreEventQueueSnapshotReported
|
|
result = PIXELATOMS_GET(ChreEventQueueSnapshotReported_init_default);
|
|
result.has_snapshot_chre_get_time_ms = true;
|
|
result.snapshot_chre_get_time_ms =
|
|
SystemTime::getMonotonicTime().toRawNanoseconds() /
|
|
kOneMillisecondInNanoseconds;
|
|
result.has_max_event_queue_size = true;
|
|
result.max_event_queue_size = maxQueueSize;
|
|
result.has_mean_event_queue_size = true;
|
|
result.mean_event_queue_size = meanQueueSize;
|
|
result.has_num_dropped_events = true;
|
|
result.num_dropped_events = numDroppedEvents;
|
|
|
|
sendMetricToHost(PIXELATOMS_GET(Atom_chre_event_queue_snapshot_reported_tag),
|
|
PIXELATOMS_GET(ChreEventQueueSnapshotReported_fields),
|
|
&result);
|
|
}
|
|
|
|
_android_hardware_google_pixel_PixelAtoms_ChrePalType toAtomPalType(
|
|
TelemetryManager::PalType type) {
|
|
switch (type) {
|
|
case TelemetryManager::PalType::SENSOR:
|
|
return PIXELATOMS_GET_PAL_TYPE(SENSOR);
|
|
case TelemetryManager::PalType::WIFI:
|
|
return PIXELATOMS_GET_PAL_TYPE(WIFI);
|
|
case TelemetryManager::PalType::GNSS:
|
|
return PIXELATOMS_GET_PAL_TYPE(GNSS);
|
|
case TelemetryManager::PalType::WWAN:
|
|
return PIXELATOMS_GET_PAL_TYPE(WWAN);
|
|
case TelemetryManager::PalType::AUDIO:
|
|
return PIXELATOMS_GET_PAL_TYPE(AUDIO);
|
|
case TelemetryManager::PalType::BLE:
|
|
return PIXELATOMS_GET_PAL_TYPE(BLE);
|
|
case TelemetryManager::PalType::UNKNOWN:
|
|
default:
|
|
LOGW("Unknown PAL type %" PRIu8, type);
|
|
return PIXELATOMS_GET_PAL_TYPE(UNKNOWN);
|
|
}
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
TelemetryManager::TelemetryManager() {
|
|
scheduleMetricTimer();
|
|
}
|
|
|
|
void TelemetryManager::onPalOpenFailure(PalType type) {
|
|
auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
|
|
_android_hardware_google_pixel_PixelAtoms_ChrePalType palType =
|
|
toAtomPalType(NestedDataPtr<PalType>(data));
|
|
|
|
if (palType != PIXELATOMS_GET_PAL_TYPE(UNKNOWN)) {
|
|
sendPalOpenFailedMetric(palType);
|
|
}
|
|
};
|
|
|
|
// Defer the metric sending callback to better ensure that the host can
|
|
// receive this message, as this method may be called prior to chre::init()
|
|
// completion.
|
|
EventLoopManagerSingleton::get()->deferCallback(
|
|
SystemCallbackType::DeferredMetricPostEvent, NestedDataPtr<PalType>(type),
|
|
callback);
|
|
}
|
|
|
|
void TelemetryManager::collectSystemMetrics() {
|
|
EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
|
|
sendEventLoopStats(eventLoop.getMaxEventQueueSize(),
|
|
eventLoop.getMeanEventQueueSize(),
|
|
eventLoop.getNumEventsDropped());
|
|
|
|
scheduleMetricTimer();
|
|
}
|
|
|
|
void TelemetryManager::scheduleMetricTimer() {
|
|
constexpr Seconds kDelay = Seconds(60 * 60 * 24); // 24 hours
|
|
auto callback = [](uint16_t /* eventType */, void * /* data */,
|
|
void * /* extraData */) {
|
|
EventLoopManagerSingleton::get()
|
|
->getTelemetryManager()
|
|
.collectSystemMetrics();
|
|
};
|
|
TimerHandle handle = EventLoopManagerSingleton::get()->setDelayedCallback(
|
|
SystemCallbackType::DeferredMetricPostEvent, nullptr /* data */, callback,
|
|
kDelay);
|
|
if (handle == CHRE_TIMER_INVALID) {
|
|
LOGE("Failed to set daily metric timer");
|
|
}
|
|
}
|
|
|
|
} // namespace chre
|