Add vendor logging code within the CHRE daemon
Bug: 207156504
Test: Verify by device logs
Change-Id: I2cc5f24570f2abf3f656560855bdb2b3b26a5e04
diff --git a/Android.mk b/Android.mk
index 78df3fb..86db98c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -39,6 +39,7 @@
LOCAL_CPP_EXTENSION := .cc
LOCAL_CFLAGS += -Wall -Werror -Wextra
+LOCAL_CFLAGS += -DCHRE_DAEMON_METRIC_ENABLED
LOCAL_TIDY_CHECKS := -google-runtime-int
# bug:205155753, external/pigweed/pw_tokenizer/decode.cc:161 has this warning as error
@@ -87,7 +88,9 @@
android.hardware.soundtrigger@2.0 \
libpower \
libprotobuf-cpp-lite \
- pixelatoms-cpp
+ pixelatoms-cpp \
+ android.frameworks.stats-V1-ndk \
+ libbinder_ndk
LOCAL_CPPFLAGS += -std=c++20
LOCAL_CFLAGS += -Wno-sign-compare
diff --git a/host/common/daemon_base.cc b/host/common/daemon_base.cc
index 5925537..402fb9c 100644
--- a/host/common/daemon_base.cc
+++ b/host/common/daemon_base.cc
@@ -21,9 +21,19 @@
#include "chre_host/log.h"
#include "chre_host/napp_header.h"
-#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
#include <json/json.h>
+#ifdef CHRE_DAEMON_METRIC_ENABLED
+#include <aidl/android/frameworks/stats/IStats.h>
+#include <android/binder_manager.h>
+#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
+
+using ::aidl::android::frameworks::stats::IStats;
+using ::aidl::android::frameworks::stats::VendorAtom;
+using ::aidl::android::frameworks::stats::VendorAtomValue;
+namespace PixelAtoms = ::android::hardware::google::pixel::PixelAtoms;
+#endif // CHRE_DAEMON_METRIC_ENABLED
+
// Aliased for consistency with the way these symbols are referenced in
// CHRE-side code
namespace fbs = ::chre::fbs;
@@ -114,7 +124,11 @@
if (!success) {
LOGE("Failed to send nanoapp filename.");
} else {
- mPreloadedNanoappPendingTransactionIds.push(transactionId);
+ Transaction transaction = {
+ .transactionId = transactionId,
+ .nanoappId = appId,
+ };
+ mPreloadedNanoappPendingTransactions.push(transaction);
}
return success;
@@ -202,10 +216,12 @@
} else if (messageType == fbs::ChreMessage::LowPowerMicAccessRelease) {
configureLpma(false /* enabled */);
} else if (messageType == fbs::ChreMessage::MetricLog) {
+#ifdef CHRE_DAEMON_METRIC_ENABLED
std::unique_ptr<fbs::MessageContainerT> container =
fbs::UnPackMessageContainer(messageBuffer);
const auto *metricMsg = container->message.AsMetricLog();
handleMetricLog(metricMsg);
+#endif // CHRE_DAEMON_METRIC_ENABLED
} else if (hostClientId == kHostClientIdDaemon) {
handleDaemonMessage(messageBuffer);
} else if (hostClientId == ::chre::kHostClientIdUnspecified) {
@@ -245,27 +261,43 @@
LOGE("Invalid message from CHRE directed to daemon");
} else {
const auto *response = container->message.AsLoadNanoappResponse();
- if (mPreloadedNanoappPendingTransactionIds.empty()) {
+ if (mPreloadedNanoappPendingTransactions.empty()) {
LOGE("Received nanoapp load response with no pending load");
- } else if (mPreloadedNanoappPendingTransactionIds.front() !=
+ } else if (mPreloadedNanoappPendingTransactions.front().transactionId !=
response->transaction_id) {
LOGE("Received nanoapp load response with ID %" PRIu32
" expected transaction id %" PRIu32,
response->transaction_id,
- mPreloadedNanoappPendingTransactionIds.front());
+ mPreloadedNanoappPendingTransactions.front().transactionId);
} else {
if (!response->success) {
LOGE("Received unsuccessful nanoapp load response with ID %" PRIu32,
- mPreloadedNanoappPendingTransactionIds.front());
+ mPreloadedNanoappPendingTransactions.front().transactionId);
+
+#ifdef CHRE_DAEMON_METRIC_ENABLED
+ std::vector<VendorAtomValue> values(3);
+ values[0].set<VendorAtomValue::longValue>(
+ mPreloadedNanoappPendingTransactions.front().nanoappId);
+ values[1].set<VendorAtomValue::intValue>(
+ PixelAtoms::ChreHalNanoappLoadFailed::TYPE_PRELOADED);
+ values[2].set<VendorAtomValue::intValue>(
+ PixelAtoms::ChreHalNanoappLoadFailed::REASON_ERROR_GENERIC);
+ const VendorAtom atom{
+ .reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
+ .atomId = PixelAtoms::Atom::kChreHalNanoappLoadFailed,
+ .values{std::move(values)},
+ };
+ reportMetric(atom);
+#endif // CHRE_DAEMON_METRIC_ENABLED
}
- mPreloadedNanoappPendingTransactionIds.pop();
+ mPreloadedNanoappPendingTransactions.pop();
}
}
}
+#ifdef CHRE_DAEMON_METRIC_ENABLED
void ChreDaemonBase::handleMetricLog(const ::chre::fbs::MetricLogT *metricMsg) {
const std::vector<int8_t> &encodedMetric = metricMsg->encoded_metric;
- namespace PixelAtoms = ::android::hardware::google::pixel::PixelAtoms;
switch (metricMsg->id) {
case PixelAtoms::Atom::kChrePalOpenFailed: {
@@ -273,7 +305,15 @@
if (!metric.ParseFromArray(encodedMetric.data(), encodedMetric.size())) {
LOGE("Failed to parse metric data");
} else {
- // TODO(b/207156504): Log the metric
+ std::vector<VendorAtomValue> values(2);
+ values[0].set<VendorAtomValue::intValue>(metric.pal());
+ values[1].set<VendorAtomValue::intValue>(metric.type());
+ const VendorAtom atom{
+ .reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
+ .atomId = PixelAtoms::Atom::kChrePalOpenFailed,
+ .values{std::move(values)},
+ };
+ reportMetric(atom);
}
break;
}
@@ -282,6 +322,26 @@
}
}
}
+#endif // CHRE_DAEMON_METRIC_ENABLED
+
+#ifdef CHRE_DAEMON_METRIC_ENABLED
+void ChreDaemonBase::reportMetric(const VendorAtom &atom) {
+ const std::string statsServiceName =
+ std::string(IStats::descriptor).append("/default");
+ if (!AServiceManager_isDeclared(statsServiceName.c_str())) {
+ LOGE("Stats service is not declared.");
+ return;
+ }
+
+ std::shared_ptr<IStats> stats_client = IStats::fromBinder(ndk::SpAIBinder(
+ AServiceManager_waitForService(statsServiceName.c_str())));
+
+ const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(atom);
+ if (!ret.isOk()) {
+ LOGE("Failed to report vendor atom");
+ }
+}
+#endif // CHRE_DAEMON_METRIC_ENABLED
} // namespace chre
} // namespace android
diff --git a/host/common/include/chre_host/daemon_base.h b/host/common/include/chre_host/daemon_base.h
index 6b5c6f2..5154f2e 100644
--- a/host/common/include/chre_host/daemon_base.h
+++ b/host/common/include/chre_host/daemon_base.h
@@ -27,6 +27,11 @@
#include "chre_host/log_message_parser.h"
#include "chre_host/socket_server.h"
+#ifdef CHRE_DAEMON_METRIC_ENABLED
+#include <aidl/android/frameworks/stats/IStats.h>
+#include <android/binder_manager.h>
+#endif
+
namespace android {
namespace chre {
@@ -86,6 +91,12 @@
//! with any clients after the server starts.
static constexpr uint16_t kHostClientIdDaemon = UINT16_MAX;
+ //! Contains the transaction ID and app ID used to preload nanoapps.
+ struct Transaction {
+ uint32_t transactionId;
+ uint64_t nanoappId;
+ };
+
void setShutdownRequested(bool request) {
mChreShutdownRequested = request;
}
@@ -194,10 +205,22 @@
*/
virtual void configureLpma(bool enabled) = 0;
+#ifdef CHRE_DAEMON_METRIC_ENABLED
/**
* Handles a metric log message sent from CHRE
*/
virtual void handleMetricLog(const ::chre::fbs::MetricLogT *metric_msg);
+#endif // CHRE_DAEMON_METRIC_ENABLED
+
+#ifdef CHRE_DAEMON_METRIC_ENABLED
+ /**
+ * Create and report CHRE vendor atom and send it to stats_client
+ *
+ * @param atom the vendor atom to be reported
+ */
+ virtual void reportMetric(
+ const aidl::android::frameworks::stats::VendorAtom &atom);
+#endif // CHRE_DAEMON_METRIC_ENABLED
/**
* Returns the CHRE log message parser instance.
@@ -216,9 +239,9 @@
//! Set to true when we request a graceful shutdown of CHRE
std::atomic<bool> mChreShutdownRequested;
- //! Contains a set of transaction IDs used to load the preloaded nanoapps.
- //! The IDs are stored in the order they are sent.
- std::queue<uint32_t> mPreloadedNanoappPendingTransactionIds;
+ //! Contains a set of transaction IDs and app IDs used to load the preloaded
+ //! nanoapps. The IDs are stored in the order they are sent.
+ std::queue<Transaction> mPreloadedNanoappPendingTransactions;
/**
* Computes and returns the clock drift between the system clock
diff --git a/host/common/include/chre_host/log.h b/host/common/include/chre_host/log.h
index eb85334..a247e87 100644
--- a/host/common/include/chre_host/log.h
+++ b/host/common/include/chre_host/log.h
@@ -25,7 +25,8 @@
/**
* Logs a message to both logcat and stdout. Don't use this directly; prefer one
- * of LOGE, LOGW, etc. to populate the level.
+ * of LOGE, LOGW, etc. to populate the level. Use LOG_PRI directly rather than
+ * ALOG to avoid misinterpreting LOG_* macros that may be incorrectly evaluated.
*
* @param level log level to pass to ALOG (LOG_ERROR, LOG_WARN, etc.)
* @param stream output stream to print to (e.g. stdout)
@@ -33,7 +34,7 @@
*/
#define CHRE_LOG(level, stream, format, ...) \
do { \
- ALOG(level, LOG_TAG, format, ##__VA_ARGS__); \
+ LOG_PRI(ANDROID_##level, LOG_TAG, format, ##__VA_ARGS__); \
fprintf(stream, "%s:%d: " format "\n", __func__, __LINE__, ##__VA_ARGS__); \
} while (0)