Add instant trace methods

Bug: 207049735
Test: atest TraceDevTest
Change-Id: If2826a9bb1fb99d75ff3c9c03c16c2f5f1ec5d1b
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index 24c6ae6..97e93f8 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -208,6 +208,39 @@
 }
 
 /**
+ * Trace an instantaneous context. name is used to identify the context.
+ *
+ * An "instant" is an event with no defined duration. Visually is displayed like a single marker
+ * in the timeline (rather than a span, in the case of begin/end events).
+ *
+ * By default, instant events are added into a dedicated track that has the same name of the event.
+ * Use atrace_instant_for_track to put different instant events into the same timeline track/row.
+ */
+#define ATRACE_INSTANT(name) atrace_instant(ATRACE_TAG, name)
+static inline void atrace_instant(uint64_t tag, const char* name) {
+    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
+        void atrace_instant_body(const char*);
+        atrace_instant_body(name);
+    }
+}
+
+/**
+ * Trace an instantaneous context. name is used to identify the context.
+ * trackName is the name of the row where the event should be recorded.
+ *
+ * An "instant" is an event with no defined duration. Visually is displayed like a single marker
+ * in the timeline (rather than a span, in the case of begin/end events).
+ */
+#define ATRACE_INSTANT_FOR_TRACK(trackName, name) \
+    atrace_instant_for_track(ATRACE_TAG, trackName, name)
+static inline void atrace_instant_for_track(uint64_t tag, const char* trackName, const char* name) {
+    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
+        void atrace_instant_for_track_body(const char*, const char*);
+        atrace_instant_for_track_body(trackName, name);
+    }
+}
+
+/**
  * Traces an integer counter value.  name is used to identify the counter.
  * This can be used to track how a value changes over time.
  */
diff --git a/libcutils/trace-container.cpp b/libcutils/trace-container.cpp
index f7eed48..ef7c72d 100644
--- a/libcutils/trace-container.cpp
+++ b/libcutils/trace-container.cpp
@@ -217,6 +217,28 @@
     WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
 }
 
+void atrace_instant_body(const char* name) {
+    if (CC_LIKELY(atrace_use_container_sock)) {
+        WRITE_MSG_IN_CONTAINER("I", "|", "%s", name, "");
+        return;
+    }
+
+    if (atrace_marker_fd < 0) return;
+
+    WRITE_MSG("I|%d|", "%s", name, "");
+}
+
+void atrace_instant_for_track_body(const char* trackName, const char* name) {
+    if (CC_LIKELY(atrace_use_container_sock)) {
+        WRITE_MSG_IN_CONTAINER("N", "|", "|%s", trackName, name);
+        return;
+    }
+
+    if (atrace_marker_fd < 0) return;
+
+    WRITE_MSG("N|%d|", "|%s", name, trackName);
+}
+
 void atrace_int_body(const char* name, int32_t value)
 {
     if (CC_LIKELY(atrace_use_container_sock)) {
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 1ab63dc..25c86f4 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -89,6 +89,14 @@
     WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
 }
 
+void atrace_instant_body(const char* name) {
+    WRITE_MSG("I|%d|", "%s", name, "");
+}
+
+void atrace_instant_for_track_body(const char* trackName, const char* name) {
+    WRITE_MSG("N|%d|", "|%s", trackName, name);
+}
+
 void atrace_int_body(const char* name, int32_t value)
 {
     WRITE_MSG("C|%d|", "|%" PRId32, name, value);
diff --git a/libcutils/trace-dev_test.cpp b/libcutils/trace-dev_test.cpp
index 832b36a..ff6d202 100644
--- a/libcutils/trace-dev_test.cpp
+++ b/libcutils/trace-dev_test.cpp
@@ -195,6 +195,106 @@
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 }
 
+TEST_F(TraceDevTest, atrace_instant_body_normal) {
+    atrace_instant_body("fake_name");
+
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+    std::string actual;
+    ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+    std::string expected = android::base::StringPrintf("I|%d|fake_name", getpid());
+    ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_instant_body_exact) {
+    std::string expected = android::base::StringPrintf("I|%d|", getpid());
+    std::string name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1);
+    atrace_instant_body(name.c_str());
+
+    ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+    std::string actual;
+    ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+    expected += name;
+    ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+    // Add a single character and verify we get the exact same value as before.
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+    name += '*';
+    atrace_instant_body(name.c_str());
+    EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+    ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+    ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_instant_body_truncated) {
+    std::string expected = android::base::StringPrintf("I|%d|", getpid());
+    std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+    atrace_instant_body(name.c_str());
+
+    ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+    std::string actual;
+    ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+    int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 1;
+    expected += android::base::StringPrintf("%.*s", expected_len, name.c_str());
+    ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_instant_for_track_body_normal) {
+    atrace_instant_for_track_body("fake_track", "fake_name");
+
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+    std::string actual;
+    ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+    std::string expected = android::base::StringPrintf("N|%d|fake_track|fake_name", getpid());
+    ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_instant_for_track_body_exact) {
+    const int nameSize = 5;
+    std::string expected = android::base::StringPrintf("N|%d|", getpid());
+    std::string trackName = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - nameSize);
+    atrace_instant_for_track_body(trackName.c_str(), "name");
+
+    ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+    std::string actual;
+    ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+    expected += trackName + "|name";
+    ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+    // Add a single character and verify we get the exact same value as before.
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+    trackName += '*';
+    atrace_instant_for_track_body(trackName.c_str(), "name");
+    EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+    ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+    ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_instant_for_track_body_truncated) {
+    const int nameSize = 5;
+    std::string expected = android::base::StringPrintf("N|%d|", getpid());
+    std::string trackName = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+    atrace_instant_for_track_body(trackName.c_str(), "name");
+
+    ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+    ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+    std::string actual;
+    ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+    int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 1 - nameSize;
+    expected += android::base::StringPrintf("%.*s|name", expected_len, trackName.c_str());
+    ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
 TEST_F(TraceDevTest, atrace_int_body_normal) {
   atrace_int_body("fake_name", 12345);
 
diff --git a/libcutils/trace-host.cpp b/libcutils/trace-host.cpp
index 9781ad3..b01a0ec 100644
--- a/libcutils/trace-host.cpp
+++ b/libcutils/trace-host.cpp
@@ -28,6 +28,9 @@
 void atrace_end_body() { }
 void atrace_async_begin_body(const char* /*name*/, int32_t /*cookie*/) {}
 void atrace_async_end_body(const char* /*name*/, int32_t /*cookie*/) {}
+void atrace_instant_body(const char* /*name*/) {}
+void atrace_instant_for_track_body(const char* /*trackName*/,
+                                   const char* /*name*/) {}
 void atrace_int_body(const char* /*name*/, int32_t /*value*/) {}
 void atrace_int64_body(const char* /*name*/, int64_t /*value*/) {}
 void atrace_init() {}