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(&currentTime, 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);