Merge "Basic binary event-log helpers"
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 71b235a..f2051dd 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -18,6 +18,8 @@
     DisplayHardware/HWComposer.cpp \
     DisplayHardware/PowerHAL.cpp \
     DisplayHardware/VirtualDisplaySurface.cpp \
+    EventLog/EventLogTags.logtags \
+    EventLog/EventLog.cpp
 
 LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp
new file mode 100644
index 0000000..815242b
--- /dev/null
+++ b/services/surfaceflinger/EventLog/EventLog.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2013 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 <stdio.h>
+#include <stdlib.h>
+#include <cutils/log.h>
+#include <utils/String8.h>
+
+#include "EventLog.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(EventLog)
+
+
+EventLog::EventLog() {
+}
+
+void EventLog::doLogJank(const String8& window, int32_t value) {
+    EventLog::TagBuffer buffer(LOGTAG_SF_JANK);
+    buffer.startList(2);
+    buffer.writeString8(window);
+    buffer.writeInt32(value);
+    buffer.endList();
+    buffer.log();
+}
+
+void EventLog::logJank(const String8& window, int32_t value) {
+    EventLog::getInstance().doLogJank(window, value);
+}
+
+// ---------------------------------------------------------------------------
+
+EventLog::TagBuffer::TagBuffer(int32_t tag)
+    : mPos(0), mTag(tag), mOverflow(false) {
+}
+
+void EventLog::TagBuffer::log() {
+    if (mOverflow) {
+        ALOGW("couldn't log to binary event log: overflow.");
+    } else if (android_bWriteLog(mTag, mStorage, mPos) < 0) {
+        ALOGE("couldn't log to EventLog: %s", strerror(errno));
+    }
+    // purge the buffer
+    mPos = 0;
+    mOverflow = false;
+}
+
+void EventLog::TagBuffer::startList(int8_t count) {
+    if (mOverflow) return;
+    const size_t needed = 1 + sizeof(count);
+    if (mPos + needed > STORAGE_MAX_SIZE) {
+        mOverflow = true;
+        return;
+    }
+    mStorage[mPos + 0] = EVENT_TYPE_LIST;
+    mStorage[mPos + 1] = count;
+    mPos += needed;
+}
+
+void EventLog::TagBuffer::endList() {
+    if (mOverflow) return;
+    const size_t needed = 1;
+    if (mPos + needed > STORAGE_MAX_SIZE) {
+        mOverflow = true;
+        return;
+    }
+    mStorage[mPos + 0] = '\n';
+    mPos += needed;
+}
+
+void EventLog::TagBuffer::writeInt32(int32_t value) {
+    if (mOverflow) return;
+    const size_t needed = 1 + sizeof(value);
+    if (mPos + needed > STORAGE_MAX_SIZE) {
+        mOverflow = true;
+        return;
+    }
+    mStorage[mPos + 0] = EVENT_TYPE_INT;
+    memcpy(&mStorage[mPos + 1], &value, sizeof(value));
+    mPos += needed;
+}
+
+void EventLog::TagBuffer::writeInt64(int64_t value) {
+    if (mOverflow) return;
+    const size_t needed = 1 + sizeof(value);
+    if (mPos + needed > STORAGE_MAX_SIZE) {
+        mOverflow = true;
+        return;
+    }
+    mStorage[mPos + 0] = EVENT_TYPE_LONG;
+    memcpy(&mStorage[mPos + 1], &value, sizeof(value));
+    mPos += needed;
+}
+
+void EventLog::TagBuffer::writeString8(const String8& value) {
+    if (mOverflow) return;
+    const int32_t stringLen = value.length();
+    const size_t needed = 1 + sizeof(int32_t) + stringLen;
+    if (mPos + needed > STORAGE_MAX_SIZE) {
+        mOverflow = true;
+        return;
+    }
+    mStorage[mPos + 0] = EVENT_TYPE_STRING;
+    memcpy(&mStorage[mPos + 1], &stringLen, sizeof(int32_t));
+    memcpy(&mStorage[mPos + 5], value.string(), stringLen);
+    mPos += needed;
+}
+
+// ---------------------------------------------------------------------------
+}// namespace android
+
+// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h
new file mode 100644
index 0000000..2f1cd9b
--- /dev/null
+++ b/services/surfaceflinger/EventLog/EventLog.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2013 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 <stdint.h>
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+
+#ifndef ANDROID_SF_EVENTLOG_H
+#define ANDROID_SF_EVENTLOG_H
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class String8;
+
+class EventLog : public Singleton<EventLog> {
+
+public:
+    static void logJank(const String8& window, int32_t value);
+
+protected:
+    EventLog();
+
+private:
+    /*
+     * EventLogBuffer is a helper class to construct an in-memory event log
+     * tag. In this version the buffer is not dynamic, so write operation can
+     * fail if there is not enough space in the temporary buffer.
+     * Once constructed, the buffer can be logger by calling the log()
+     * method.
+     */
+
+    class TagBuffer {
+        enum { STORAGE_MAX_SIZE = 128 };
+        int32_t mPos;
+        int32_t mTag;
+        bool mOverflow;
+        char mStorage[STORAGE_MAX_SIZE];
+    public:
+        TagBuffer(int32_t tag);
+
+        // starts list of items
+        void startList(int8_t count);
+        // terminates the list
+        void endList();
+        // write a 32-bit integer
+        void writeInt32(int32_t value);
+        // write a 64-bit integer
+        void writeInt64(int64_t value);
+        // write a C string
+        void writeString8(const String8& value);
+
+        // outputs the the buffer to the log
+        void log();
+    };
+
+    friend class Singleton<EventLog>;
+    EventLog(const EventLog&);
+    EventLog& operator =(const EventLog&);
+
+    enum { LOGTAG_SF_JANK = 60100 };
+    void doLogJank(const String8& window, int32_t value);
+};
+
+// ---------------------------------------------------------------------------
+}// namespace android
+// ---------------------------------------------------------------------------
+
+#endif /* ANDROID_SF_EVENTLOG_H */
diff --git a/services/surfaceflinger/EventLog/EventLogTags.logtags b/services/surfaceflinger/EventLog/EventLogTags.logtags
new file mode 100644
index 0000000..c83692f
--- /dev/null
+++ b/services/surfaceflinger/EventLog/EventLogTags.logtags
@@ -0,0 +1,38 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace.  Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+#    (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+
+# surfaceflinger
+60100 sf_jank (window|3),(value|1)
+
+# NOTE - the range 1000000-2000000 is reserved for partners and others who
+# want to define their own log tags without conflicting with the core platform.