Merge changes I82ac2392,Ie0dd7acd,I8018e48f

* changes:
  Updating Flashall to work off tasks
  Updated location of initialization
  Updating FlashTask to require img-name
diff --git a/debuggerd/crasher/arm/crashglue.S b/debuggerd/crasher/arm/crashglue.S
index 6f41b21..e4adf40 100644
--- a/debuggerd/crasher/arm/crashglue.S
+++ b/debuggerd/crasher/arm/crashglue.S
@@ -19,40 +19,6 @@
 	ldr r11, =0xa5a50011
 	ldr r12, =0xa5a50012
 
-
-	fconstd   d0, #0
-	fconstd   d1, #1
-	fconstd   d2, #2
-	fconstd   d3, #3
-	fconstd   d4, #4
-	fconstd   d5, #5
-	fconstd   d6, #6
-	fconstd   d7, #7
-	fconstd   d8, #8
-	fconstd   d9, #9
-	fconstd   d10, #10
-	fconstd   d11, #11
-	fconstd   d12, #12
-	fconstd   d13, #13
-	fconstd   d14, #14
-	fconstd   d15, #15
-	fconstd   d16, #16
-	fconstd   d17, #17
-	fconstd   d18, #18
-	fconstd   d19, #19
-	fconstd   d20, #20
-	fconstd   d21, #21
-	fconstd   d22, #22
-	fconstd   d23, #23
-	fconstd   d24, #24
-	fconstd   d25, #25
-	fconstd   d26, #26
-	fconstd   d27, #27
-	fconstd   d28, #28
-	fconstd   d29, #29
-	fconstd   d30, #30
-	fconstd   d31, #31
-
 	mov lr, #0
 	ldr lr, [lr]
 	b .
diff --git a/debuggerd/crasher/arm64/crashglue.S b/debuggerd/crasher/arm64/crashglue.S
index 014c98c..97c824e 100644
--- a/debuggerd/crasher/arm64/crashglue.S
+++ b/debuggerd/crasher/arm64/crashglue.S
@@ -37,39 +37,6 @@
 	ldr x28, =0xa5a50028
 	ldr x29, =0xa5a50029
 
-	fmov   d0, -1.0  // -1 is more convincing than 0.
-	fmov   d1, 1.0
-	fmov   d2, 2.0
-	fmov   d3, 3.0
-	fmov   d4, 4.0
-	fmov   d5, 5.0
-	fmov   d6, 6.0
-	fmov   d7, 7.0
-	fmov   d8, 8.0
-	fmov   d9, 9.0
-	fmov   d10, 10.0
-	fmov   d11, 11.0
-	fmov   d12, 12.0
-	fmov   d13, 13.0
-	fmov   d14, 14.0
-	fmov   d15, 15.0
-	fmov   d16, 16.0
-	fmov   d17, 17.0
-	fmov   d18, 18.0
-	fmov   d19, 19.0
-	fmov   d20, 20.0
-	fmov   d21, 21.0
-	fmov   d22, 22.0
-	fmov   d23, 23.0
-	fmov   d24, 24.0
-	fmov   d25, 25.0
-	fmov   d26, 26.0
-	fmov   d27, 27.0
-	fmov   d28, 28.0
-	fmov   d29, 29.0
-	fmov   d30, 30.0
-	fmov   d31, 31.0
-
 	mov x30, xzr
 	ldr x30, [x30]
 	b .
diff --git a/debuggerd/crasher/riscv64/crashglue.S b/debuggerd/crasher/riscv64/crashglue.S
index 47dd93b..5334887 100644
--- a/debuggerd/crasher/riscv64/crashglue.S
+++ b/debuggerd/crasher/riscv64/crashglue.S
@@ -1,8 +1,11 @@
-
-	.globl crash1
-	.globl crashnostack
-
+.globl crash1
 crash1:
+	.cfi_startproc
+	addi sp, sp, -16
+	.cfi_def_cfa_offset 16
+	sd ra, 8(sp)
+	.cfi_offset ra, -8
+
 	li	x0,0xdead0000+0
 	li	x1,0xdead0000+1
 	li	x2,0xdead0000+2
@@ -33,13 +36,22 @@
 	li	x27,0xdead0000+27
 	li	x28,0xdead0000+28
 	# don't trash the stack otherwise the signal handler won't run
-	#li	$29,0xdead0000+29
+	#li	x29,0xdead0000+29
 	li	x30,0xdead0000+30
 	li	x31,0xdead0000+31
 
+	li sp, 0
+	ld t2, 0(zero)
 	j .
+	.cfi_endproc
 
 
+.globl crashnostack
 crashnostack:
-	li	sp, 0
+	.cfi_startproc
+	mv t1, sp
+	.cfi_def_cfa_register t1
+	li sp, 0
+	ld t2, 0(zero)
 	j .
+	.cfi_endproc
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 25b03af..198de37 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -51,7 +51,6 @@
   HEADER,
   THREAD,
   REGISTERS,
-  FP_REGISTERS,
   BACKTRACE,
   MAPS,
   MEMORY,
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 74a1423..d71fc6c 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -47,12 +47,7 @@
 using android::base::unique_fd;
 
 bool is_allowed_in_logcat(enum logtype ltype) {
-  if ((ltype == HEADER)
-   || (ltype == REGISTERS)
-   || (ltype == BACKTRACE)) {
-    return true;
-  }
-  return false;
+  return (ltype == HEADER) || (ltype == REGISTERS) || (ltype == BACKTRACE);
 }
 
 static bool should_write_to_kmsg() {
diff --git a/libstats/expresslog/Counter.cpp b/libstats/expresslog/Counter.cpp
index bee1303..9382041 100644
--- a/libstats/expresslog/Counter.cpp
+++ b/libstats/expresslog/Counter.cpp
@@ -28,5 +28,10 @@
     stats_write(EXPRESS_EVENT_REPORTED, metricIdHash, amount);
 }
 
+void Counter::logIncrementWithUid(const char* metricName, int32_t uid, int64_t amount) {
+    const int64_t metricIdHash = farmhash::Fingerprint64(metricName, strlen(metricName));
+    stats_write(EXPRESS_UID_EVENT_REPORTED, metricIdHash, amount, uid);
+}
+
 }  // namespace expresslog
 }  // namespace android
diff --git a/libstats/expresslog/include/Counter.h b/libstats/expresslog/include/Counter.h
index 57328f5..8d0ab6a 100644
--- a/libstats/expresslog/include/Counter.h
+++ b/libstats/expresslog/include/Counter.h
@@ -24,6 +24,8 @@
 class Counter final {
 public:
     static void logIncrement(const char* metricId, int64_t amount = 1);
+
+    static void logIncrementWithUid(const char* metricId, int32_t uid, int64_t amount = 1);
 };
 
 }  // namespace expresslog
diff --git a/trusty/stats/aidl/Android.bp b/trusty/stats/aidl/Android.bp
new file mode 100644
index 0000000..078cc99
--- /dev/null
+++ b/trusty/stats/aidl/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.trusty.stats.nw.setter",
+    unstable: true,
+    vendor_available: true,
+    srcs: [
+        "android/trusty/stats/nw/setter/IStatsSetter.aidl",
+    ],
+    imports: ["android.frameworks.stats-V1"],
+    backend: {
+        cpp: {
+            enabled: true,
+        },
+        java: {
+            enabled: false,
+            platform_apis: false,
+        },
+        ndk: {
+            enabled: false,
+        },
+    },
+}
diff --git a/trusty/stats/aidl/android/trusty/stats/nw/setter/IStatsSetter.aidl b/trusty/stats/aidl/android/trusty/stats/nw/setter/IStatsSetter.aidl
new file mode 100644
index 0000000..f44f4a3
--- /dev/null
+++ b/trusty/stats/aidl/android/trusty/stats/nw/setter/IStatsSetter.aidl
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package android.trusty.stats.nw.setter;
+
+import android.frameworks.stats.IStats;
+
+interface IStatsSetter {
+    /**
+     * Set the IStats interface facet.
+     *
+     * @param istats The IStats facet provided by the caller for the remote
+     *        service to report IStats' VendorAtom.
+     */
+    void setInterface(in IStats istats);
+}
diff --git a/trusty/stats/test/Android.bp b/trusty/stats/test/Android.bp
new file mode 100644
index 0000000..6b2bce9
--- /dev/null
+++ b/trusty/stats/test/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2021 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "trusty_stats_test",
+    vendor: true,
+    srcs: [
+        "stats_test.cpp",
+    ],
+    static_libs: [
+        "libgmock",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libtrusty",
+        "libbinder",
+        "libbinder_trusty",
+        "libutils",
+
+        // AIDL interface deps versions, please refer to below link
+        // https://source.android.com/docs/core/architecture/aidl/stable-aidl#module-naming-rules
+        "android.frameworks.stats-V1-cpp",
+        "android.trusty.stats.nw.setter-cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    require_root: true,
+    proprietary: true,
+}
diff --git a/trusty/stats/test/README.md b/trusty/stats/test/README.md
new file mode 100644
index 0000000..45e6af8
--- /dev/null
+++ b/trusty/stats/test/README.md
@@ -0,0 +1,97 @@
+# Development Notes
+
+*    First get [repo_pull.py and gerrit.py](https://android.googlesource.com/platform/development/+/master/tools/repo_pull/) from aosp.
+
+*    Although this repo is not currently in Trusty’s manifest, it’s sufficient to copy these two python scripts to the root of the Trusty project and run them from there. Make sure to follow the [repo_pull installation](https://android.googlesource.com/platform/development/+/master/tools/repo_pull/#installation) steps if necessary.
+
+## Build
+
+Build Android:
+
+```sh
+source build/envsetup.sh
+lunch qemu_trusty_arm64-userdebug
+m
+```
+
+Build Trusty:
+
+```sh
+./trusty/vendor/google/aosp/scripts/build.py qemu-generic-arm64-test-debug --skip-tests 2>stderr.log
+```
+
+## Trusty PORT_TEST
+
+On QEmu:
+
+```sh
+./build-root/build-qemu-generic-arm64-test-debug/run --headless --boot-test "com.android.trusty.stats.test" --verbose
+```
+
+On device: (Build for your device's debug target on both Adroid and Trusty)
+
+```sh
+/vendor/bin/trusty-ut-ctrl -D /dev/trusty-ipc-dev0 "com.android.trusty.stats.test"
+```
+
+On device, in a loop:
+
+```sh
+cat << 'EOF' > metrics.sh
+#!/system/bin/sh
+TIMES=${1:-0}
+X=0
+while [ "$TIMES" -eq 0 -o "$TIMES" -gt "$X" ]
+do
+  echo "######################## stats.test $X " $(( X++ ));
+  /vendor/bin/trusty-ut-ctrl -D /dev/trusty-ipc-dev0 "com.android.trusty.stats.test"
+done
+EOF
+
+adb wait-for-device
+adb push metrics.sh /data/user/test/metrics.sh
+adb shell sh /data/user/test/metrics.sh
+```
+
+## Android Native Test
+
+On QEmu:
+
+```sh
+./build-root/build-qemu-generic-arm64-test-debug/run --headless --android $ANDROID_PROJECT_ROOT --shell-command "/data/nativetest64/vendor/trusty_stats_test/trusty_stats_test" --verbose
+```
+
+On device: (Build for your device's debug target on both Adroid and Trusty)
+
+```sh
+/data/nativetest64/vendor/trusty_stats_test/trusty_stats_test
+```
+
+On device, in a loop:
+
+```sh
+cat << 'EOF' > metrics-nw.sh
+#!/system/bin/sh
+TIMES=${1:-0}
+X=0
+while [ "$TIMES" -eq 0 -o "$TIMES" -gt "$X" ]
+do
+  echo "######################## stats.test $X " $(( X++ ));
+  /data/nativetest64/vendor/trusty_stats_test/trusty_stats_test
+done
+EOF
+
+adb wait-for-device
+adb push metrics.sh /data/user/test/metrics-nw.sh
+adb shell sh /data/user/test/metrics-nw.sh
+```
+
+## Trusty Backtrace analysis
+
+
+```
+$ export A2L=./prebuilts/clang/host/linux-x86/llvm-binutils-stable/llvm-addr2line
+$ export OD=./prebuilts/clang/host/linux-x86/llvm-binutils-stable/llvm-objdump
+$ $OD -d -C build-root/build-qemu-generic-arm64-test-debug/user_tasks/trusty/user/base/app/metrics/metrics.syms.elf > objdump.lst
+$ $A2L -e build-root/build-qemu-generic-arm64-test-debug/user_tasks/trusty/user/base/app/metrics/metrics.syms.elf 0xe5104
+```
diff --git a/trusty/stats/test/stats_test.cpp b/trusty/stats/test/stats_test.cpp
new file mode 100644
index 0000000..1edddeb
--- /dev/null
+++ b/trusty/stats/test/stats_test.cpp
@@ -0,0 +1,364 @@
+/*
+ * 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 <errno.h>
+#include <getopt.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <condition_variable>
+#include <cstddef>
+#include <mutex>
+#include <queue>
+
+#include <android-base/expected.h>
+#include <android-base/logging.h>
+#include <android/frameworks/stats/BnStats.h>
+#include <android/frameworks/stats/IStats.h>
+#include <android/trusty/stats/nw/setter/IStatsSetter.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTipcAndroid.h>
+#include <binder/RpcTrusty.h>
+#include <trusty/tipc.h>
+
+/** DOC:
+ * ./build-root/build-qemu-generic-arm64-test-debug/run \
+ *       --android $ANDROID_PROJECT_ROOT \
+ *       --headless --shell-command \
+ *       "/data/nativetest64/vendor/trusty_stats_test/trusty_stats_test"
+ *
+ * adb -s emulator-5554 shell \
+ *       /data/nativetest64/vendor/trusty_stats_test/trusty_stats_test
+ */
+using ::android::base::unique_fd;
+using ::android::binder::Status;
+using ::android::frameworks::stats::BnStats;
+using ::android::frameworks::stats::IStats;
+using ::android::frameworks::stats::VendorAtom;
+using ::android::frameworks::stats::VendorAtomValue;
+using ::android::trusty::stats::nw::setter::IStatsSetter;
+
+constexpr const char kTrustyDefaultDeviceName[] = "/dev/trusty-ipc-dev0";
+constexpr const char kTrustyStatsSetterTest[] =
+        "com.android.frameworks.stats.trusty.test.relayer.istats_setter";
+constexpr const char kTrustyStatsSetterMetrics[] =
+        "com.android.frameworks.stats.trusty.metrics.istats_setter";
+constexpr const char kTrustyStatsPortTest[] = "com.android.trusty.stats.test";
+constexpr const char kTrustyCrashPortTest[] = "com.android.trusty.crashtest";
+constexpr const char kTrustyCrasherUuid[] = "7ee4dddc-177a-420a-96ea-5d413d88228e:crasher";
+
+enum TrustyAtoms : int32_t {
+    TrustyAppCrashed = 100072,
+    TrustyError = 100145,
+    TrustyStorageError = 100146
+};
+
+enum TestMsgHeader : int32_t {
+    TEST_PASSED = 0,
+    TEST_FAILED = 1,
+    TEST_MESSAGE = 2,
+};
+
+namespace android {
+namespace trusty {
+namespace stats {
+
+class Stats : public BnStats {
+  public:
+    Stats() : BnStats() {}
+
+    Status reportVendorAtom(const VendorAtom& vendorAtom) override {
+        const char* atomIdStr = vendorAtomStr(vendorAtom.atomId);
+        ALOGD("Vendor atom reported of type: %s\n", atomIdStr);
+        std::lock_guard lock(mLock);
+        mQueueVendorAtom.push(vendorAtom);
+        mCondVar.notify_one();
+        return Status::ok();
+    }
+
+    status_t getVendorAtom(VendorAtom* pVendorAtom, int64_t waitForMs) {
+        std::unique_lock lock(mLock);
+        while (mQueueVendorAtom.empty()) {
+            auto rc = mCondVar.wait_for(lock, std::chrono::milliseconds(waitForMs));
+            if (rc == std::cv_status::timeout) {
+                return TIMED_OUT;
+            }
+        }
+        *pVendorAtom = mQueueVendorAtom.front();
+        mQueueVendorAtom.pop();
+        return NO_ERROR;
+    }
+
+  private:
+    const char* vendorAtomStr(int32_t atomId) {
+        switch (atomId) {
+            case TrustyAtoms::TrustyAppCrashed:
+                return "TrustyAtoms::TrustyAppCrashed";
+            case TrustyAtoms::TrustyError:
+                return "TrustyAtoms::TrustyError";
+            case TrustyAtoms::TrustyStorageError:
+                return "TrustyAtoms::TrustyStorageError";
+            default:
+                return "unknown TrustyAtoms type";
+        }
+    }
+    std::mutex mLock;
+    std::condition_variable mCondVar;
+    std::queue<VendorAtom> mQueueVendorAtom;
+};
+
+class TrustyStatsTestBase : public ::testing::Test {
+  protected:
+    TrustyStatsTestBase(std::string&& portNameStatsSetter, std::string&& portNamePortTest)
+        : mPortTestFd(-1),
+          mPortNameStatsSetter(std::move(portNameStatsSetter)),
+          mPortNamePortTest(std::move(portNamePortTest)) {}
+
+    void SetUp() override {
+        // Commenting out the server portion because we do not have any direct
+        // incoming call Calls from TA are currently being handled on the mSession's
+        // extra thread. android::sp<::android::RpcServer> server =
+        // ::android::RpcServer::make(::android::RpcTransportCtxFactoryRaw::make());
+
+        mStats = android::sp<Stats>::make();
+        // Increasing number of incoming threads on mSession to be able to receive
+        // callbacks
+        auto session_initializer = [](sp<RpcSession>& session) {
+            session->setMaxIncomingThreads(1);
+        };
+
+        ASSERT_FALSE(mSession);
+        mSession = RpcTrustyConnectWithSessionInitializer(
+                kTrustyDefaultDeviceName, mPortNameStatsSetter.c_str(), session_initializer);
+        ASSERT_TRUE(mSession);
+
+        auto root = mSession->getRootObject();
+        ASSERT_TRUE(root);
+        auto statsSetter = IStatsSetter::asInterface(root);
+        ASSERT_TRUE(statsSetter);
+        statsSetter->setInterface(mStats);
+    }
+    void TearDown() override {
+        // close connection to unitest app
+        if (mPortTestFd != -1) {
+            tipc_close(mPortTestFd);
+        }
+        mPortTestFd = -1;
+
+        if (mSession) {
+            // shutdownAndWait here races with sending out the DecStrong
+            // messages after reportVendorAtom returns, so we delay it a little
+            // bit to give the messages time to go out over the transport
+            usleep(50000);
+            ASSERT_TRUE(mSession->shutdownAndWait(true));
+        }
+        mSession.clear();
+        mStats.clear();
+    }
+    void StartPortTest() {
+        // connect to unitest app
+        mPortTestFd = tipc_connect(kTrustyDefaultDeviceName, mPortNamePortTest.c_str());
+        if (mPortTestFd < 0) {
+            ALOGE("Failed to connect to '%s' app: %s\n", kTrustyStatsPortTest,
+                  strerror(-mPortTestFd));
+        }
+        ASSERT_GT(mPortTestFd, 0);
+    }
+    void WaitPortTestDone() {
+        // wait for test to complete
+        char rxBuf[1024];
+        const char prolog[] = "Trusty PORT_TEST:";
+        strncpy(rxBuf, prolog, sizeof(prolog) - 1);
+        char* pRxBuf = rxBuf + sizeof(prolog) - 1;
+        size_t remainingBufSize = sizeof(rxBuf) - sizeof(prolog) - 1;
+
+        ASSERT_NE(mPortTestFd, -1);
+        for (;;) {
+            int rc = read(mPortTestFd, pRxBuf, remainingBufSize);
+            ASSERT_GT(rc, 0);
+            ASSERT_LT(rc, (int)remainingBufSize);
+            if (pRxBuf[0] == TEST_PASSED) {
+                break;
+            } else if (pRxBuf[0] == TEST_FAILED) {
+                break;
+            } else if (pRxBuf[0] == TEST_MESSAGE) {
+                pRxBuf[0] = ' ';
+                write(STDOUT_FILENO, rxBuf, rc + sizeof(prolog) - 1);
+            } else {
+                ALOGE("Bad message header: %d\n", rxBuf[0]);
+                break;
+            }
+        }
+        ASSERT_EQ(pRxBuf[0], TEST_PASSED);
+    }
+
+    android::sp<Stats> mStats;
+
+  private:
+    android::sp<RpcSession> mSession;
+    int mPortTestFd;
+    std::string mPortNameStatsSetter;
+    std::string mPortNamePortTest;
+};
+
+class TrustyStatsTest : public TrustyStatsTestBase {
+  protected:
+    TrustyStatsTest() : TrustyStatsTestBase(kTrustyStatsSetterTest, kTrustyStatsPortTest) {}
+};
+
+class TrustyMetricsCrashTest : public TrustyStatsTestBase {
+  protected:
+    TrustyMetricsCrashTest()
+        : TrustyStatsTestBase(kTrustyStatsSetterMetrics, kTrustyCrashPortTest) {}
+};
+
+TEST_F(TrustyStatsTest, CheckAtoms) {
+    int atomAppCrashedCnt = 0;
+    int atomStorageErrorCnt = 0;
+    int atomTrustyErrorCnt = 0;
+    uint64_t blockForMs = 500;
+    StartPortTest();
+    WaitPortTestDone();
+    for (;;) {
+        VendorAtom vendorAtom;
+        auto status = mStats->getVendorAtom(&vendorAtom, blockForMs);
+        ASSERT_THAT(status, ::testing::AnyOf(NO_ERROR, TIMED_OUT));
+        if (status == TIMED_OUT) {
+            // No more atoms
+            break;
+        }
+
+        ASSERT_THAT(vendorAtom.atomId,
+                    ::testing::AnyOf(::testing::Eq(TrustyAtoms::TrustyAppCrashed),
+                                     ::testing::Eq(TrustyAtoms::TrustyError),
+                                     ::testing::Eq(TrustyAtoms::TrustyStorageError)));
+        ASSERT_STREQ(String8(vendorAtom.reverseDomainName), "google.android.trusty");
+        switch (vendorAtom.atomId) {
+            case TrustyAtoms::TrustyAppCrashed:
+                ++atomAppCrashedCnt;
+                ASSERT_STREQ(String8(vendorAtom.values[0].get<VendorAtomValue::stringValue>()),
+                             "5247d19b-cf09-4272-a450-3ef20dbefc14");
+                break;
+            case TrustyAtoms::TrustyStorageError:
+                ++atomStorageErrorCnt;
+                ASSERT_EQ(vendorAtom.values[0].get<VendorAtomValue::intValue>(), 5);
+                ASSERT_STREQ(String8(vendorAtom.values[1].get<VendorAtomValue::stringValue>()),
+                             "5247d19b-cf09-4272-a450-3ef20dbefc14");
+                ASSERT_STREQ(String8(vendorAtom.values[2].get<VendorAtomValue::stringValue>()),
+                             "5247d19b-cf09-4272-a450-3ef20dbefc14");
+                ASSERT_EQ(vendorAtom.values[3].get<VendorAtomValue::intValue>(), 1);
+                ASSERT_EQ(vendorAtom.values[4].get<VendorAtomValue::intValue>(), 3);
+                ASSERT_EQ(vendorAtom.values[5].get<VendorAtomValue::longValue>(),
+                          0x4BCDEFABBAFEDCBALL);
+                ASSERT_EQ(vendorAtom.values[6].get<VendorAtomValue::intValue>(), 4);
+                ASSERT_EQ(vendorAtom.values[7].get<VendorAtomValue::longValue>(), 1023);
+                break;
+            case TrustyAtoms::TrustyError:
+                ++atomTrustyErrorCnt;
+                break;
+            default:
+                FAIL() << "Unknown vendor atom ID: " << vendorAtom.atomId;
+                break;
+        }
+    };
+    ASSERT_EQ(atomAppCrashedCnt, 1);
+    ASSERT_EQ(atomStorageErrorCnt, 1);
+    ASSERT_EQ(atomTrustyErrorCnt, 0);
+}
+
+TEST_F(TrustyMetricsCrashTest, CheckTrustyCrashAtoms) {
+    const std::vector<uint32_t> kExpectedCrashReasonsArm64{
+            0x00000001U,  // exit_failure (twice)
+            0x00000001U,
+            0x92000004U,  // read_null_ptr
+            0xf200002aU,  // brk_instruction
+            0x92000004U,  // read_bad_ptr
+            0x92000044U,  // crash_write_bad_ptr
+            0x9200004fU,  // crash_write_ro_ptr
+            0x8200000fU,  // crash_exec_rodata
+            0x8200000fU,  // crash_exec_data
+    };
+    const std::vector<uint32_t> kExpectedCrashReasonsArm32{
+            0x00000001U,  // exit_failure (twice)
+            0x00000001U,
+            0x20000007U,  // read_null_ptr
+            0x20000007U,  // read_bad_ptr
+            0x20000807U,  // crash_write_bad_ptr
+            0x2000080fU,  // crash_write_ro_ptr
+            0x3000000fU,  // crash_exec_rodata
+            0x3000000fU,  // crash_exec_data
+    };
+
+    int expectedAtomCnt = 7;
+    int atomAppCrashedCnt = 0;
+    int atomStorageErrorCnt = 0;
+    int atomTrustyErrorCnt = 0;
+    std::vector<uint32_t> atomCrashReasons;
+    uint64_t blockForMs = 500;
+    StartPortTest();
+    WaitPortTestDone();
+    for (;;) {
+        VendorAtom vendorAtom;
+        auto status = mStats->getVendorAtom(&vendorAtom, blockForMs);
+        ASSERT_THAT(status, ::testing::AnyOf(NO_ERROR, TIMED_OUT));
+        if (status == TIMED_OUT) {
+            // No more atoms
+            break;
+        }
+
+        ASSERT_THAT(vendorAtom.atomId,
+                    ::testing::AnyOf(::testing::Eq(TrustyAtoms::TrustyAppCrashed),
+                                     ::testing::Eq(TrustyAtoms::TrustyError),
+                                     ::testing::Eq(TrustyAtoms::TrustyStorageError)));
+        ASSERT_STREQ(String8(vendorAtom.reverseDomainName), "google.android.trusty");
+
+        switch (vendorAtom.atomId) {
+            case TrustyAtoms::TrustyAppCrashed:
+                ++atomAppCrashedCnt;
+                ASSERT_STREQ(String8(vendorAtom.values[0].get<VendorAtomValue::stringValue>()),
+                             kTrustyCrasherUuid);
+                atomCrashReasons.push_back(vendorAtom.values[1].get<VendorAtomValue::intValue>());
+                break;
+            case TrustyAtoms::TrustyStorageError:
+                ++atomStorageErrorCnt;
+                break;
+            case TrustyAtoms::TrustyError:
+                ++atomTrustyErrorCnt;
+                ASSERT_STREQ(String8(vendorAtom.values[1].get<VendorAtomValue::stringValue>()), "");
+                break;
+            default:
+                FAIL() << "Unknown vendor atom ID: " << vendorAtom.atomId;
+        }
+    }
+    ASSERT_GE(atomAppCrashedCnt, expectedAtomCnt - 1);
+    ASSERT_EQ(atomStorageErrorCnt, 0);
+    // There is one dropped event left over from Trusty boot,
+    // it may show up here
+    ASSERT_LE(atomTrustyErrorCnt, 1);
+    ASSERT_THAT(atomCrashReasons,
+                ::testing::AnyOf(kExpectedCrashReasonsArm64, kExpectedCrashReasonsArm32));
+};
+
+}  // namespace stats
+}  // namespace trusty
+}  // namespace android