Get it to build with new HealthMonitor files
Bug: 245779999
Test: Presubmit
Change-Id: I3fd11218e54c15f315165d588e6307e3e0b71de4
diff --git a/BUILD.gn b/BUILD.gn
index 0cfe286..88145db 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -6,6 +6,11 @@
"android-emu/android/base/AndroidSubAllocator.cpp",
"android-emu/android/base/AndroidSubAllocator.h",
"android-emu/android/base/BumpPool.h",
+ "android-emu/android/base/AndroidHealthMonitor.cpp",
+ "android-emu/android/base/AndroidHealthMonitor.h",
+ "android-emu/android/base/AndroidHealthMonitorConsumer.h",
+ "android-emu/android/base/AndroidHealthMonitorConsumerBasic.cpp",
+ "android-emu/android/base/AndroidHealthMonitorConsumerBasic.h",
"android-emu/android/base/Pool.cpp",
"android-emu/android/base/Pool.h",
"android-emu/android/base/Tracing.cpp",
@@ -28,6 +33,7 @@
"android-emu/android/base/synchronization/AndroidLock.h",
"android-emu/android/base/synchronization/AndroidMessageChannel.cpp",
"android-emu/android/base/synchronization/AndroidMessageChannel.h",
+ "android-emu/android/base/testing/TestClock.h",
"android-emu/android/base/threads/AndroidFunctorThread.cpp",
"android-emu/android/base/threads/AndroidFunctorThread.h",
"android-emu/android/base/threads/AndroidThread.h",
diff --git a/android-emu/Android.bp b/android-emu/Android.bp
index b83cab9..f147361 100644
--- a/android-emu/Android.bp
+++ b/android-emu/Android.bp
@@ -24,6 +24,8 @@
"android/base/threads/AndroidThreadStore.cpp",
"android/base/threads/AndroidThread_pthread.cpp",
"android/base/threads/AndroidWorkPool.cpp",
+ "android/base/AndroidHealthMonitor.cpp",
+ "android/base/AndroidHealthMonitorConsumerBasic.cpp",
"android/base/Tracing.cpp",
"android/utils/debug.c",
],
diff --git a/android-emu/Android.mk b/android-emu/Android.mk
index 88a296c..fa40f9b 100644
--- a/android-emu/Android.mk
+++ b/android-emu/Android.mk
@@ -24,6 +24,8 @@
android/base/threads/AndroidThreadStore.cpp \
android/base/threads/AndroidThread_pthread.cpp \
android/base/threads/AndroidWorkPool.cpp \
+ android/base/AndroidHealthMonitor.cpp \
+ android/base/AndroidHealthMonitorConsumerBasic.cpp \
android/base/Tracing.cpp \
android/utils/debug.c \
diff --git a/android-emu/CMakeLists.txt b/android-emu/CMakeLists.txt
index 7d42043..0e86fed 100644
--- a/android-emu/CMakeLists.txt
+++ b/android-emu/CMakeLists.txt
@@ -1,9 +1,9 @@
# This is an autogenerated file! Do not edit!
# instead run make from .../device/generic/goldfish-opengl
# which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/android-emu/Android.mk" "e1609bbe85546522a8f71488322e5c9919d4e81107cf10a1413e5ed0d86211e2")
-set(androidemu_src android/base/AlignedBuf.cpp android/base/files/MemStream.cpp android/base/files/Stream.cpp android/base/files/StreamSerializing.cpp android/base/Pool.cpp android/base/StringFormat.cpp android/base/AndroidSubAllocator.cpp android/base/synchronization/AndroidMessageChannel.cpp android/base/threads/AndroidFunctorThread.cpp android/base/threads/AndroidThreadStore.cpp android/base/threads/AndroidThread_pthread.cpp android/base/threads/AndroidWorkPool.cpp android/base/Tracing.cpp android/utils/debug.c)
-android_add_library(TARGET androidemu SHARED LICENSE Apache-2.0 SRC android/base/AlignedBuf.cpp android/base/files/MemStream.cpp android/base/files/Stream.cpp android/base/files/StreamSerializing.cpp android/base/Pool.cpp android/base/StringFormat.cpp android/base/AndroidSubAllocator.cpp android/base/synchronization/AndroidMessageChannel.cpp android/base/threads/AndroidFunctorThread.cpp android/base/threads/AndroidThreadStore.cpp android/base/threads/AndroidThread_pthread.cpp android/base/threads/AndroidWorkPool.cpp android/base/Tracing.cpp android/utils/debug.c)
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/android-emu/Android.mk" "d9538b030db1f66591d881f0be80d53d84365d25195197924eb23059fe96ab03")
+set(androidemu_src android/base/AlignedBuf.cpp android/base/files/MemStream.cpp android/base/files/Stream.cpp android/base/files/StreamSerializing.cpp android/base/Pool.cpp android/base/StringFormat.cpp android/base/AndroidSubAllocator.cpp android/base/synchronization/AndroidMessageChannel.cpp android/base/threads/AndroidFunctorThread.cpp android/base/threads/AndroidThreadStore.cpp android/base/threads/AndroidThread_pthread.cpp android/base/threads/AndroidWorkPool.cpp android/base/AndroidHealthMonitor.cpp android/base/AndroidHealthMonitorConsumerBasic.cpp android/base/Tracing.cpp android/utils/debug.c)
+android_add_library(TARGET androidemu SHARED LICENSE Apache-2.0 SRC android/base/AlignedBuf.cpp android/base/files/MemStream.cpp android/base/files/Stream.cpp android/base/files/StreamSerializing.cpp android/base/Pool.cpp android/base/StringFormat.cpp android/base/AndroidSubAllocator.cpp android/base/synchronization/AndroidMessageChannel.cpp android/base/threads/AndroidFunctorThread.cpp android/base/threads/AndroidThreadStore.cpp android/base/threads/AndroidThread_pthread.cpp android/base/threads/AndroidWorkPool.cpp android/base/AndroidHealthMonitor.cpp android/base/AndroidHealthMonitorConsumerBasic.cpp android/base/Tracing.cpp android/utils/debug.c)
target_include_directories(androidemu PRIVATE ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
target_compile_definitions(androidemu PRIVATE "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGFXSTREAM" "-DLOG_TAG=\"androidemu\"")
target_compile_options(androidemu PRIVATE "-fvisibility=default" "-Wno-unused-parameter" "-Wno-missing-field-initializers" "-fstrict-aliasing")
@@ -11,7 +11,7 @@
# This is an autogenerated file! Do not edit!
# instead run make from .../device/generic/goldfish-opengl
# which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/android-emu/Android.mk" "e1609bbe85546522a8f71488322e5c9919d4e81107cf10a1413e5ed0d86211e2")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/android-emu/Android.mk" "d9538b030db1f66591d881f0be80d53d84365d25195197924eb23059fe96ab03")
set(ringbuffer_src android/base/ring_buffer.c)
android_add_library(TARGET ringbuffer LICENSE Apache-2.0 SRC android/base/ring_buffer.c)
target_include_directories(ringbuffer PRIVATE ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
diff --git a/android-emu/android/base/HealthMonitor.cpp b/android-emu/android/base/AndroidHealthMonitor.cpp
similarity index 83%
rename from android-emu/android/base/HealthMonitor.cpp
rename to android-emu/android/base/AndroidHealthMonitor.cpp
index 4a9ab93..d2bd4d7 100644
--- a/android-emu/android/base/HealthMonitor.cpp
+++ b/android-emu/android/base/AndroidHealthMonitor.cpp
@@ -13,24 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "base/HealthMonitor.h"
+#include "android/base/AndroidHealthMonitor.h"
#include <map>
+#include <sys/time.h>
-#include "base/System.h"
-#include "base/testing/TestClock.h"
-#include "host-common/logging.h"
-#include "host-common/GfxstreamFatalError.h"
+namespace android {
+namespace base {
+namespace guest {
-namespace emugl {
-
-using android::base::AutoLock;
-using android::base::MetricEventHang;
-using android::base::MetricEventUnHang;
-using android::base::TestClock;
+using android::base::guest::AutoLock;
using std::chrono::duration_cast;
-using emugl::ABORT_REASON_OTHER;
-using emugl::FatalError;
template <class... Ts>
struct MonitoredEventVisitor : Ts... {
@@ -40,8 +33,8 @@
MonitoredEventVisitor(Ts...) -> MonitoredEventVisitor<Ts...>;
template <class Clock>
-HealthMonitor<Clock>::HealthMonitor(MetricsLogger& metricsLogger, uint64_t heartbeatInterval)
- : mInterval(Duration(std::chrono::milliseconds(heartbeatInterval))), mLogger(metricsLogger) {
+HealthMonitor<Clock>::HealthMonitor(HealthMonitorConsumer& consumer, uint64_t heartbeatInterval)
+ : mInterval(Duration(std::chrono::milliseconds(heartbeatInterval))), mConsumer(consumer) {
start();
}
@@ -63,8 +56,9 @@
uint64_t timeout, std::optional<Id> parentId) {
auto intervalMs = duration_cast<std::chrono::milliseconds>(mInterval).count();
if (timeout < intervalMs) {
- WARN("Timeout value %d is too low (heartbeat is every %d). Increasing to %d", timeout,
- intervalMs, intervalMs * 2);
+ ALOGW("Timeout value %llu is too low (heartbeat is every %llu). Increasing to %llu",
+ (unsigned long long)timeout, (unsigned long long) intervalMs,
+ (unsigned long long)intervalMs * 2);
timeout = intervalMs * 2;
}
@@ -121,10 +115,12 @@
int newHungTasks = mHungTasks;
{
AutoLock lock(mLock);
+ struct timeval currentTime;
+ gettimeofday(¤tTime, 0);
if (mEventQueue.empty()) {
mCv.timedWait(
&mLock,
- android::base::getUnixTimeUs() +
+ currentTime.tv_usec +
std::chrono::duration_cast<std::chrono::microseconds>(mInterval).count());
}
mEventQueue.swap(events);
@@ -137,20 +133,20 @@
std::visit(MonitoredEventVisitor{
[](std::monostate& event) {
- ERR("MonitoredEvent type not found");
- GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) <<
- "MonitoredEvent type not found";
+ ALOGE("MonitoredEvent type not found");
+ abort();
},
[this, &events](typename MonitoredEventType::Start& event) {
auto it = mMonitoredTasks.find(event.id);
if (it != mMonitoredTasks.end()) {
- ERR("Registered multiple start events for task %d", event.id);
+ ALOGE("Registered multiple start events for task %llu",
+ (unsigned long long)event.id);
return;
}
if (event.parentId && mMonitoredTasks.find(event.parentId.value()) ==
mMonitoredTasks.end()) {
- WARN("Requested parent task %d does not exist.",
- event.parentId.value());
+ ALOGW("Requested parent task %llu does not exist.",
+ (unsigned long long)event.parentId.value());
event.parentId = std::nullopt;
}
it = mMonitoredTasks
@@ -171,7 +167,8 @@
[this, &events](typename MonitoredEventType::Touch& event) {
auto it = mMonitoredTasks.find(event.id);
if (it == mMonitoredTasks.end()) {
- ERR("HealthMonitor has no task in progress for id %d", event.id);
+ ALOGE("HealthMonitor has no task in progress for id %llu",
+ (unsigned long long)event.id);
return;
}
@@ -183,7 +180,8 @@
&events](typename MonitoredEventType::Stop& event) {
auto it = mMonitoredTasks.find(event.id);
if (it == mMonitoredTasks.end()) {
- ERR("HealthMonitor has no task in progress for id %d", event.id);
+ ALOGE("HealthMonitor has no task in progress for id %llu",
+ (unsigned long long)event.id);
return;
}
@@ -220,9 +218,7 @@
auto newAnnotations = (*task.onHangAnnotationsCallback)();
task.metadata->mergeAnnotations(std::move(newAnnotations));
}
- mLogger.logMetricEvent(MetricEventHang{.taskId = task.id,
- .metadata = task.metadata.get(),
- .otherHungTasks = newHungTasks});
+ mConsumer.consumeHangEvent(task.id, task.metadata.get(), newHungTasks);
task.hungTimestamp = task.timeoutTimestamp;
newHungTasks++;
}
@@ -233,8 +229,7 @@
task.timeoutTimestamp -
(task.hungTimestamp.value() + task.timeoutThreshold))
.count();
- mLogger.logMetricEvent(MetricEventUnHang{
- .taskId = task.id, .metadata = task.metadata.get(), .hung_ms = hangTime});
+ mConsumer.consumeUnHangEvent(task.id, task.metadata.get(), hangTime);
task.hungTimestamp = std::nullopt;
newHungTasks--;
}
@@ -245,7 +240,7 @@
}
if (mHungTasks != newHungTasks) {
- ERR("HealthMonitor: Number of unresponsive tasks %s: %d -> %d",
+ ALOGE("HealthMonitor: Number of unresponsive tasks %s: %d -> %d",
mHungTasks < newHungTasks ? "increased" : "decreaased", mHungTasks, newHungTasks);
mHungTasks = newHungTasks;
}
@@ -270,6 +265,7 @@
}
template class HealthMonitor<steady_clock>;
-template class HealthMonitor<TestClock>;
-} // namespace emugl
+} // namespace guest
+} // namespace base
+} // namespace android
diff --git a/android-emu/android/base/HealthMonitor.h b/android-emu/android/base/AndroidHealthMonitor.h
similarity index 88%
rename from android-emu/android/base/HealthMonitor.h
rename to android-emu/android/base/AndroidHealthMonitor.h
index 55e87fc..9520b94 100644
--- a/android-emu/android/base/HealthMonitor.h
+++ b/android-emu/android/base/AndroidHealthMonitor.h
@@ -27,25 +27,25 @@
#include <unordered_set>
#include <variant>
-#include "base/ConditionVariable.h"
-#include "base/Lock.h"
-#include "base/Metrics.h"
-#include "base/Thread.h"
-#include "host-common/GfxstreamFatalError.h"
-#include "host-common/logging.h"
+#include "android/base/AndroidHealthMonitorConsumer.h"
+#include "android/base/synchronization/AndroidConditionVariable.h"
+#include "android/base/synchronization/AndroidLock.h"
+#include "android/base/threads/AndroidThread.h"
-using android::base::EventHangMetadata;
-using android::base::getCurrentThreadId;
+#include <log/log.h>
-#define WATCHDOG_BUILDER(healthMonitor, msg) \
- ::emugl::HealthWatchdogBuilder<std::decay_t<decltype(healthMonitor)>>(healthMonitor, __FILE__, \
- __func__, msg, __LINE__)
+using android::base::guest::EventHangMetadata;
-namespace emugl {
+#define WATCHDOG_BUILDER(healthMonitor, msg) \
+ ::android::base::guest::HealthWatchdogBuilder<std::decay_t<decltype(healthMonitor)>>( \
+ healthMonitor, __FILE__, __func__, msg, __LINE__)
-using android::base::ConditionVariable;
-using android::base::Lock;
-using android::base::MetricsLogger;
+namespace android {
+namespace base {
+namespace guest {
+
+using android::base::guest::ConditionVariable;
+using android::base::guest::Lock;
using std::chrono::duration;
using std::chrono::steady_clock;
using std::chrono::time_point;
@@ -58,10 +58,10 @@
// HealthMonitor provides the ability to register arbitrary start/touch/stop events associated
// with client defined tasks. At some pre-defined interval, it will periodically consume
// all logged events to assess whether the system is hanging on any task. Via the
-// MetricsLogger, it will log hang and unhang events when it detects tasks hanging/resuming.
+// HealthMonitorConsumer, it will log hang and unhang events when it detects tasks hanging/resuming.
// Design doc: http://go/gfxstream-health-monitor
template <class Clock = steady_clock>
-class HealthMonitor : public android::base::Thread {
+class HealthMonitor : public android::base::guest::Thread {
public:
// Alias for task id.
using Id = uint64_t;
@@ -69,7 +69,7 @@
// Constructor
// `heatbeatIntervalMs` is the interval, in milleseconds, that the thread will sleep for
// in between health checks.
- HealthMonitor(MetricsLogger& metricsLogger, uint64_t heartbeatInterval = kDefaultIntervalMs);
+ HealthMonitor(HealthMonitorConsumer& consumer, uint64_t heartbeatInterval = kDefaultIntervalMs);
// Destructor
// Enqueues an event to end monitoring and waits on thread to process remaining queued events.
@@ -160,11 +160,11 @@
// Members accessed only on the worker thread. Not protected by mutex.
int mHungTasks = 0;
- MetricsLogger& mLogger;
+ HealthMonitorConsumer& mConsumer;
std::unordered_map<Id, MonitoredTask> mMonitoredTasks;
// Lock and cv control access to queue and id counter
- android::base::ConditionVariable mCv;
+ ConditionVariable mCv;
Lock mLock;
Id mNextId = 0;
std::queue<std::unique_ptr<MonitoredEvent>> mEventQueue;
@@ -236,17 +236,18 @@
auto& threadTasks = getMonitoredThreadTasks();
auto& stack = threadTasks[&mHealthMonitor];
if (getCurrentThreadId() != mThreadId) {
- GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
- << "HealthWatchdog destructor thread does not match origin. Destructor must be "
- "called on the same thread.";
+ ALOGE("HealthWatchdog destructor thread does not match origin. Destructor must be "
+ "called on the same thread.");
+ abort();
}
if (stack.empty()) {
- GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
- << "HealthWatchdog thread local stack is empty!";
+ ALOGE("HealthWatchdog thread local stack is empty!");
+ abort();
}
if (stack.top() != id) {
- GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
- << "HealthWatchdog id " << id << " does not match top of stack: " << stack.top();
+ ALOGE("HealthWatchdog id %llu does not match top of stack: %llu",
+ (unsigned long long)id, (unsigned long long)stack.top());
+ abort();
}
stack.pop();
}
@@ -305,4 +306,6 @@
std::optional<std::function<std::unique_ptr<HangAnnotations>()>> mOnHangCallback;
};
-} // namespace emugl
+} // namespace guest
+} // namespace base
+} // namespace android
diff --git a/android-emu/android/base/AndroidHealthMonitorConsumer.h b/android-emu/android/base/AndroidHealthMonitorConsumer.h
new file mode 100644
index 0000000..7144e8b
--- /dev/null
+++ b/android-emu/android/base/AndroidHealthMonitorConsumer.h
@@ -0,0 +1,83 @@
+// Copyright (C) 2022 The Android Open Source Project
+// Copyright (C) 2022 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.
+#pragma once
+
+#include <inttypes.h>
+
+#include <memory>
+#include <string>
+#include <thread>
+#include <unordered_map>
+#include <variant>
+
+#include "android/base/threads/AndroidThread.h"
+
+// Interface for consuming events from HealthMonitor
+
+namespace android {
+namespace base {
+namespace guest {
+
+// Struct for hanging events
+struct EventHangMetadata {
+ const char* file;
+ const char* function;
+ const char* msg;
+ const int line;
+ const unsigned long threadId;
+ // Field for adding custom key value annotations
+ using HangAnnotations = std::unordered_map<std::string, std::string>;
+ // Field for adding custom key value annotations
+ std::unique_ptr<HangAnnotations> data;
+
+ // TODO: willho@ replace this enum with a generic string field embedded in the
+ // proto and replace the individual event codes with a general hang event
+ // Requires a new callback to be passed from the vm to gfxstream_backend_init
+ enum class HangType { kRenderThread, kSyncThread, kOther };
+ HangType hangType;
+
+ EventHangMetadata(const char* file, const char* function, const char* msg, int line,
+ HangType hangType, std::unique_ptr<HangAnnotations> data)
+ : file(file),
+ function(function),
+ msg(msg),
+ line(line),
+ threadId(getCurrentThreadId()),
+ data(std::move(data)),
+ hangType(hangType) {}
+
+ EventHangMetadata()
+ : EventHangMetadata(nullptr, nullptr, nullptr, 0, HangType::kRenderThread, nullptr) {}
+
+ void mergeAnnotations(std::unique_ptr<HangAnnotations> annotations) {
+ if (!data) {
+ data = std::make_unique<HangAnnotations>();
+ }
+ data->merge(*annotations);
+ }
+};
+
+class HealthMonitorConsumer {
+public:
+ virtual void consumeHangEvent(uint64_t taskId, const EventHangMetadata* metadata,
+ int64_t otherHungTasks) = 0;
+ virtual void consumeUnHangEvent(uint64_t taskId, const EventHangMetadata* metadata,
+ int64_t hungMs) = 0;
+ virtual ~HealthMonitorConsumer() {}
+};
+
+} // namespace guest
+} // namespace base
+} // namespace android
diff --git a/android-emu/android/base/AndroidHealthMonitorConsumerBasic.cpp b/android-emu/android/base/AndroidHealthMonitorConsumerBasic.cpp
new file mode 100644
index 0000000..68b4b75
--- /dev/null
+++ b/android-emu/android/base/AndroidHealthMonitorConsumerBasic.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 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.
+
+#include "android/base/AndroidHealthMonitorConsumerBasic.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace base {
+namespace guest {
+
+void logEventHangMetadata(const EventHangMetadata* metadata) {
+ ALOGE("Metadata:");
+ ALOGE("\t file: %s", metadata->file);
+ ALOGE("\t function: %s", metadata->function);
+ ALOGE("\t line: %d", metadata->line);
+ ALOGE("\t msg: %s", metadata->msg);
+ ALOGE("\t thread: %lld (0x%08llx)",
+ (long long)metadata->threadId, (long long)metadata->threadId);
+ if (metadata->data) {
+ ALOGE("\t Additional information:");
+ for (auto& [key, value] : *metadata->data) {
+ ALOGE("\t \t %s: %s", key.c_str(), value.c_str());
+ }
+ }
+}
+
+// HealthMonitorConsumerBasic
+void HealthMonitorConsumerBasic::consumeHangEvent(uint64_t taskId,
+ const EventHangMetadata* metadata,
+ int64_t otherHungTasks) {
+ ALOGE("Logging hang event. Number of tasks already hung: %lld",
+ (long long)otherHungTasks);
+ logEventHangMetadata(metadata);
+}
+
+void HealthMonitorConsumerBasic::consumeUnHangEvent(uint64_t taskId,
+ const EventHangMetadata* metadata,
+ int64_t hungMs) {
+ ALOGE("Logging unhang event. Hang time: %lld ms", (long long)hungMs);
+ logEventHangMetadata(metadata);
+}
+
+} // namespace guest
+} // namespace base
+} // namespace android
diff --git a/android-emu/android/base/AndroidHealthMonitorConsumerBasic.h b/android-emu/android/base/AndroidHealthMonitorConsumerBasic.h
new file mode 100644
index 0000000..9f3dc03
--- /dev/null
+++ b/android-emu/android/base/AndroidHealthMonitorConsumerBasic.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 The Android Open Source Project
+// Copyright (C) 2022 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.
+#pragma once
+
+#include "AndroidHealthMonitorConsumer.h"
+
+namespace android {
+namespace base {
+namespace guest {
+class HealthMonitorConsumerBasic: public HealthMonitorConsumer {
+public:
+ void consumeHangEvent(uint64_t taskId, const EventHangMetadata* metadata,
+ int64_t otherHungTasks) override;
+ void consumeUnHangEvent(uint64_t taskId, const EventHangMetadata* metadata,
+ int64_t hungMs) override;
+
+};
+} // namespace guest
+} // namespace base
+} // namespace android
diff --git a/android-emu/android/base/Metrics.cpp b/android-emu/android/base/Metrics.cpp
deleted file mode 100644
index 46eaab4..0000000
--- a/android-emu/android/base/Metrics.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright (C) 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.
-
-#include "base/Metrics.h"
-
-#include <memory>
-#include <sstream>
-#include <variant>
-
-#include "host-common/logging.h"
-
-namespace android {
-namespace base {
-
-// These correspond to events defined in
-// go/gpg-event-codes
-constexpr int64_t kEmulatorGraphicsFreeze = 10009;
-constexpr int64_t kEmulatorGraphicsUnfreeze = 10010;
-constexpr int64_t kEmulatorGfxstreamVkAbortReason = 10011;
-constexpr int64_t kEmulatorGraphicsHangRenderThread = 10024;
-constexpr int64_t kEmulatorGraphicsUnHangRenderThread = 10025;
-constexpr int64_t kEmulatorGraphicsHangSyncThread = 10026;
-constexpr int64_t kEmulatorGraphicsUnHangSyncThread = 10027;
-constexpr int64_t kEmulatorGraphicsBadPacketLength = 10031;
-constexpr int64_t kEmulatorGraphicsDuplicateSequenceNum = 10032;
-
-void (*MetricsLogger::add_instant_event_callback)(int64_t event_code) = nullptr;
-void (*MetricsLogger::add_instant_event_with_descriptor_callback)(int64_t event_code,
- int64_t descriptor) = nullptr;
-void (*MetricsLogger::add_instant_event_with_metric_callback)(int64_t event_code,
- int64_t metric_value) = nullptr;
-void (*MetricsLogger::set_crash_annotation_callback)(const char* key, const char* value) = nullptr;
-
-void logEventHangMetadata(const EventHangMetadata* metadata) {
- ERR("Metadata:");
- ERR("\t file: %s", metadata->file);
- ERR("\t function: %s", metadata->function);
- ERR("\t line: %d", metadata->line);
- ERR("\t msg: %s", metadata->msg);
- ERR("\t thread: %d (0x%08x)", metadata->threadId, metadata->threadId);
- if (metadata->data) {
- ERR("\t Additional information:");
- for (auto& [key, value] : *metadata->data) {
- ERR("\t \t %s: %s", key.c_str(), value.c_str());
- }
- }
-}
-
-struct MetricTypeVisitor {
- void operator()(const std::monostate /*_*/) const { ERR("MetricEventType not initialized"); }
-
- void operator()(const MetricEventFreeze freezeEvent) const {
- if (MetricsLogger::add_instant_event_callback) {
- MetricsLogger::add_instant_event_callback(kEmulatorGraphicsFreeze);
- }
- }
-
- void operator()(const MetricEventUnFreeze unfreezeEvent) const {
- if (MetricsLogger::add_instant_event_with_metric_callback) {
- MetricsLogger::add_instant_event_with_metric_callback(kEmulatorGraphicsUnfreeze,
- unfreezeEvent.frozen_ms);
- }
- }
-
- void operator()(const MetricEventHang hangEvent) const {
- // Logging a hang event will trigger a crash report upload. If crash reporting is enabled,
- // the set_annotation_callback will be populated.
- if (MetricsLogger::set_crash_annotation_callback) {
- MetricsLogger::set_crash_annotation_callback("gfxstream_hang_file",
- hangEvent.metadata->file);
- MetricsLogger::set_crash_annotation_callback("gfxstream_hang_function",
- hangEvent.metadata->function);
- MetricsLogger::set_crash_annotation_callback(
- "gfxstream_hang_line", std::to_string(hangEvent.metadata->line).c_str());
- MetricsLogger::set_crash_annotation_callback("gfxstream_hang_msg",
- hangEvent.metadata->msg);
- std::stringstream threadDesc;
- threadDesc << hangEvent.metadata->threadId << " (0x" << std::hex
- << hangEvent.metadata->threadId << ")";
- std::string threadStr = threadDesc.str();
- MetricsLogger::set_crash_annotation_callback("gfxstream_hang_thread",
- threadStr.c_str());
-
- if (hangEvent.metadata->data) {
- for (auto& [key, value] : *hangEvent.metadata->data) {
- MetricsLogger::set_crash_annotation_callback(key.c_str(), value.c_str());
- }
- }
- }
-
- ERR("Logging hang event. Number of tasks already hung: %d", hangEvent.otherHungTasks);
- logEventHangMetadata(hangEvent.metadata);
- if (MetricsLogger::add_instant_event_with_metric_callback) {
- switch (hangEvent.metadata->hangType) {
- case EventHangMetadata::HangType::kRenderThread: {
- MetricsLogger::add_instant_event_with_metric_callback(
- kEmulatorGraphicsHangRenderThread, hangEvent.otherHungTasks);
- break;
- }
- case EventHangMetadata::HangType::kSyncThread: {
- MetricsLogger::add_instant_event_with_metric_callback(
- kEmulatorGraphicsHangSyncThread, hangEvent.otherHungTasks);
- break;
- }
- case EventHangMetadata::HangType::kOther: {
- // We don't collect metrics for this type of hang.
- break;
- }
- }
- }
-
- // We have to unset all annotations since this is not necessarily a fatal crash
- // and we need to ensure we don't pollute future crash reports.
- if (MetricsLogger::set_crash_annotation_callback) {
- MetricsLogger::set_crash_annotation_callback("gfxstream_hang_file", "");
- MetricsLogger::set_crash_annotation_callback("gfxstream_hang_function", "");
- MetricsLogger::set_crash_annotation_callback("gfxstream_hang_line", "");
- MetricsLogger::set_crash_annotation_callback("gfxstream_hang_msg", "");
- MetricsLogger::set_crash_annotation_callback("gfxstream_hang_thread", "");
- if (hangEvent.metadata->data) {
- for (auto& [key, value] : *hangEvent.metadata->data) {
- MetricsLogger::set_crash_annotation_callback(key.c_str(), "");
- }
- }
- }
- }
-
- void operator()(const MetricEventUnHang unHangEvent) const {
- ERR("Logging unhang event. Hang time: %d ms", unHangEvent.hung_ms);
- logEventHangMetadata(unHangEvent.metadata);
- if (MetricsLogger::add_instant_event_with_metric_callback) {
- switch (unHangEvent.metadata->hangType) {
- case EventHangMetadata::HangType::kRenderThread: {
- MetricsLogger::add_instant_event_with_metric_callback(
- kEmulatorGraphicsUnHangRenderThread, unHangEvent.hung_ms);
- break;
- }
- case EventHangMetadata::HangType::kSyncThread: {
- MetricsLogger::add_instant_event_with_metric_callback(
- kEmulatorGraphicsUnHangSyncThread, unHangEvent.hung_ms);
- break;
- }
- case EventHangMetadata::HangType::kOther: {
- // We don't collect metrics for this type of hang.
- break;
- }
- }
- }
- }
-
- void operator()(const GfxstreamVkAbort abort) const {
- // Ensure clearcut logs are uploaded before aborting.
- if (MetricsLogger::add_instant_event_with_descriptor_callback) {
- MetricsLogger::add_instant_event_with_descriptor_callback(
- kEmulatorGfxstreamVkAbortReason, abort.abort_reason);
- }
-
- if (MetricsLogger::set_crash_annotation_callback) {
- MetricsLogger::set_crash_annotation_callback("gfxstream_abort_file", abort.file);
- MetricsLogger::set_crash_annotation_callback("gfxstream_abort_function",
- abort.function);
- MetricsLogger::set_crash_annotation_callback("gfxstream_abort_line",
- std::to_string(abort.line).c_str());
- MetricsLogger::set_crash_annotation_callback(
- "gfxstream_abort_code", std::to_string(abort.abort_reason).c_str());
- MetricsLogger::set_crash_annotation_callback("gfxstream_abort_msg", abort.msg);
- }
- }
-
- void operator()(const MetricEventBadPacketLength BadPacketLengthEvent) const {
- if (MetricsLogger::add_instant_event_with_metric_callback) {
- MetricsLogger::add_instant_event_with_metric_callback(kEmulatorGraphicsBadPacketLength,
- BadPacketLengthEvent.len);
- }
- }
-
- void operator()(const MetricEventDuplicateSequenceNum DuplicateSequenceNumEvent) const {
- if (MetricsLogger::add_instant_event_with_descriptor_callback) {
- MetricsLogger::add_instant_event_with_descriptor_callback(
- kEmulatorGraphicsDuplicateSequenceNum, DuplicateSequenceNumEvent.opcode);
- }
- }
-};
-
-// MetricsLoggerImpl
-class MetricsLoggerImpl : public MetricsLogger {
- void logMetricEvent(MetricEventType eventType) override {
- std::visit(MetricTypeVisitor(), eventType);
- }
-};
-
-std::unique_ptr<MetricsLogger> CreateMetricsLogger() {
- return std::make_unique<MetricsLoggerImpl>();
-}
-
-} // namespace base
-} // namespace android
\ No newline at end of file
diff --git a/android-emu/android/base/Metrics.h b/android-emu/android/base/Metrics.h
deleted file mode 100644
index cb712e0..0000000
--- a/android-emu/android/base/Metrics.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-// Copyright (C) 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.
-#pragma once
-
-#include <inttypes.h>
-
-#include <memory>
-#include <string>
-#include <thread>
-#include <unordered_map>
-#include <variant>
-
-#include "base/threads/Thread.h"
-
-// Library to log metrics.
-namespace android {
-namespace base {
-
-// Struct for hanging events
-struct EventHangMetadata {
- const char* file;
- const char* function;
- const char* msg;
- const int line;
- const unsigned long threadId;
- // Field for adding custom key value annotations
- using HangAnnotations = std::unordered_map<std::string, std::string>;
- // Field for adding custom key value annotations
- std::unique_ptr<HangAnnotations> data;
-
- // TODO: willho@ replace this enum with a generic string field embedded in the
- // proto and replace the individual event codes with a general hang event
- // Requires a new callback to be passed from the vm to gfxstream_backend_init
- enum class HangType { kRenderThread, kSyncThread, kOther };
- HangType hangType;
-
- EventHangMetadata(const char* file, const char* function, const char* msg, int line,
- HangType hangType, std::unique_ptr<HangAnnotations> data)
- : file(file),
- function(function),
- msg(msg),
- line(line),
- data(std::move(data)),
- hangType(hangType),
- threadId(getCurrentThreadId()) {}
-
- EventHangMetadata()
- : EventHangMetadata(nullptr, nullptr, nullptr, 0, HangType::kRenderThread, nullptr) {}
-
- void mergeAnnotations(std::unique_ptr<HangAnnotations> annotations) {
- if (!data) {
- data = std::make_unique<HangAnnotations>();
- }
- data->merge(*annotations);
- }
-};
-
-// Events that can be logged.
-struct MetricEventBadPacketLength {
- int64_t len;
-};
-struct MetricEventDuplicateSequenceNum {
- int64_t opcode;
-};
-struct MetricEventFreeze {};
-struct MetricEventUnFreeze { int64_t frozen_ms; };
-struct MetricEventHang {
- uint64_t taskId; /* From HealthMonitor */
- EventHangMetadata* metadata;
- int64_t otherHungTasks;
-};
-struct MetricEventUnHang {
- uint64_t taskId; /* From HealthMonitor */
- EventHangMetadata* metadata;
- int64_t hung_ms;
-};
-struct GfxstreamVkAbort {
- const char* file;
- const char* function;
- const char* msg;
- int line;
- int64_t abort_reason;
-};
-
-using MetricEventType =
- std::variant<std::monostate, MetricEventBadPacketLength, MetricEventDuplicateSequenceNum,
- MetricEventFreeze, MetricEventUnFreeze, MetricEventHang, MetricEventUnHang,
- GfxstreamVkAbort>;
-
-class MetricsLogger {
- public:
- // Log a MetricEventType.
- virtual void logMetricEvent(MetricEventType eventType) = 0;
- // Virtual destructor.
- virtual ~MetricsLogger() = default;
-
- // Callbacks to log events
- static void (*add_instant_event_callback)(int64_t event_code);
- static void (*add_instant_event_with_descriptor_callback)(int64_t event_code,
- int64_t descriptor);
- static void (*add_instant_event_with_metric_callback)(int64_t event_code, int64_t metric_value);
- // Crashpad will copy the strings, so these need only persist for the function call
- static void (*set_crash_annotation_callback)(const char* key, const char* value);
-};
-
-std::unique_ptr<MetricsLogger> CreateMetricsLogger();
-
-} // namespace base
-} // namespace android
\ No newline at end of file
diff --git a/android-emu/android/base/meson.build b/android-emu/android/base/meson.build
index 882b28e..3b2817f 100644
--- a/android-emu/android/base/meson.build
+++ b/android-emu/android/base/meson.build
@@ -6,6 +6,8 @@
'AndroidSubAllocator.cpp',
'AndroidSubAllocator.h',
'Pool.cpp',
+ 'AndroidHealthMonitor.cpp',
+ 'AndroidHealthMonitorConsumerBasic.cpp',
'Tracing.cpp',
'ring_buffer.c',
'files/MemStream.cpp',
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index 6bb6adb..1129a47 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -16,6 +16,8 @@
#include "HostConnection.h"
#include "android/base/threads/AndroidThread.h"
+#include "android/base/AndroidHealthMonitor.h"
+#include "android/base/AndroidHealthMonitorConsumerBasic.h"
#include "cutils/properties.h"
#include "renderControl_types.h"
@@ -31,6 +33,9 @@
#define DPRINT(...)
#endif
+using android::base::guest::HealthMonitor;
+using android::base::guest::HealthMonitorConsumerBasic;
+
#ifdef GOLDFISH_NO_GL
struct gl_client_context_t {
int placeholder;
@@ -114,6 +119,12 @@
#define STREAM_BUFFER_SIZE (4*1024*1024)
#define STREAM_PORT_NUM 22468
+HealthMonitor<>& getGlobalHealthMonitor() {
+ static HealthMonitorConsumerBasic sHealthMonitorConsumerBasic;
+ static HealthMonitor sHealthMonitor(sHealthMonitorConsumerBasic);
+ return sHealthMonitor;
+}
+
static HostConnectionType getConnectionTypeFromProperty() {
#ifdef __Fuchsia__
return HOST_CONNECTION_ADDRESS_SPACE;
@@ -443,6 +454,11 @@
// Use "new" to access a non-public constructor.
auto con = std::unique_ptr<HostConnection>(new HostConnection);
+
+ // Initialize HealthMonitor
+ // Rather than inject as a construct arg, we keep it as a static variable in the .cpp
+ // to avoid setting up dependencies in other repos (external/qemu)
+ auto& healthMonitor = getGlobalHealthMonitor();
switch (connType) {
case HOST_CONNECTION_ADDRESS_SPACE: {
auto stream = createAddressSpaceStream(STREAM_BUFFER_SIZE);