Simplify EventLog interface -- remove supported for nested
sequences (which nobody used) and streamline the API, adding
documentation in preparation for inclusion in the SDK.

Gut and deprecate EventLogTags, which unfortunately was put
into the public SDK (an oversight).  Include the functionality
in EventLog proper, in a simpler and easier to use manner.

This change doesn't actually un-@hide anything, but it does
change it to @pending.
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 81dd96e..ce0b954 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -16,134 +16,43 @@
 
 package android.util;
 
-import com.google.android.collect.Lists;
-
+import java.io.BufferedReader;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
- * {@hide}
- * Dynamically defined (in terms of event types), space efficient (i.e. "tight") event logging
- * to help instrument code for large scale stability and performance monitoring.
+ * Access to the system diagnostic event record.  System diagnostic events are
+ * used to record certain system-level events (such as garbage collection,
+ * activity manager state, system watchdogs, and other low level activity),
+ * which may be automatically collected and analyzed during system development.
  *
- * Note that this class contains all static methods.  This is done for efficiency reasons.
+ * <p>This is <b>not</b> the main "logcat" debugging log ({@link android.util.Log})!
+ * These diagnostic events are for system integrators, not application authors.
  *
- * Events for the event log are self-describing binary data structures.  They start with a 20 byte
- * header (generated automatically) which contains all of the following in order:
+ * <p>Events use integer tag codes corresponding to /system/etc/event-log-tags.
+ * They carry a payload of one or more int, long, or String values.  The
+ * event-log-tags file defines the payload contents for each type code.
  *
- * <ul>
- * <li> Payload length: 2 bytes - length of the non-header portion </li>
- * <li> Padding: 2 bytes - no meaning at this time </li>
- * <li> Timestamp:
- *   <ul>
- *   <li> Seconds: 4 bytes - seconds since Epoch </li>
- *   <li> Nanoseconds: 4 bytes - plus extra nanoseconds </li>
- *   </ul></li>
- * <li> Process ID: 4 bytes - matching {@link android.os.Process#myPid} </li>
- * <li> Thread ID: 4 bytes - matching {@link android.os.Process#myTid} </li>
- * </li>
- * </ul>
- *
- * The above is followed by a payload, comprised of the following:
- * <ul>
- * <li> Tag: 4 bytes - unique integer used to identify a particular event.  This number is also
- *                     used as a key to map to a string that can be displayed by log reading tools.
- * </li>
- * <li> Type: 1 byte - can be either {@link #INT}, {@link #LONG}, {@link #STRING},
- *                     or {@link #LIST}. </li>
- * <li> Event log value: the size and format of which is one of:
- *   <ul>
- *   <li> INT: 4 bytes </li>
- *   <li> LONG: 8 bytes </li>
- *   <li> STRING:
- *     <ul>
- *     <li> Size of STRING: 4 bytes </li>
- *     <li> The string:  n bytes as specified in the size fields above. </li>
- *     </ul></li>
- *   <li> {@link List LIST}:
- *     <ul>
- *     <li> Num items: 1 byte </li>
- *     <li> N value payloads, where N is the number of items specified above. </li>
- *     </ul></li>
- *   </ul>
- * </li>
- * <li> '\n': 1 byte - an automatically generated newline, used to help detect and recover from log
- *                     corruption and enable standard unix tools like grep, tail and wc to operate
- *                     on event logs. </li>
- * </ul>
- *
- * Note that all output is done in the endian-ness of the device (as determined
- * by {@link ByteOrder#nativeOrder()}).
+ * @pending
  */
-
 public class EventLog {
+    private static final String TAG = "EventLog";
 
-    // Value types
-    public static final byte INT    = 0;
-    public static final byte LONG   = 1;
-    public static final byte STRING = 2;
-    public static final byte LIST   = 3;
+    private static final String TAGS_FILE = "/system/etc/event-log-tags";
+    private static final String COMMENT_PATTERN = "^\\s*(#.*)?$";
+    private static final String TAG_PATTERN = "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$";
+    private static HashMap<String, Integer> sTagCodes = null;
+    private static HashMap<Integer, String> sTagNames = null;
 
-    /**
-     * An immutable tuple used to log a heterogeneous set of loggable items.
-     * The items can be Integer, Long, String, or {@link List}.
-     * The maximum number of items is 127
-     */
-    public static final class List {
-        private Object[] mItems;
-
-        /**
-         * Get a particular tuple item
-         * @param pos The position of the item in the tuple
-         */
-        public final Object getItem(int pos) {
-            return mItems[pos];
-        }
-
-        /**
-         * Get the number of items in the tuple.
-         */
-        public final byte getNumItems() {
-            return (byte) mItems.length;
-        }
-
-        /**
-         * Create a new tuple.
-         * @param items The items to create the tuple with, as varargs.
-         * @throws IllegalArgumentException if the arguments are too few (0),
-         *         too many, or aren't loggable types.
-         */
-        public List(Object... items) throws IllegalArgumentException {
-            if (items.length > Byte.MAX_VALUE) {
-                throw new IllegalArgumentException(
-                        "A List must have fewer than "
-                        + Byte.MAX_VALUE + " items in it.");
-            }
-            for (int i = 0; i < items.length; i++) {
-                final Object item = items[i];
-                if (item == null) {
-                    // Would be nice to be able to write null strings...
-                    items[i] = "";
-                } else if (!(item instanceof List ||
-                      item instanceof String ||
-                      item instanceof Integer ||
-                      item instanceof Long)) {
-                    throw new IllegalArgumentException(
-                            "Attempt to create a List with illegal item type.");
-                }
-            }
-            this.mItems = items;
-        }
-    }
-
-    /**
-     * A previously logged event read from the logs.
-     */
+    /** A previously logged event read from the logs. */
     public static final class Event {
         private final ByteBuffer mBuffer;
 
@@ -158,77 +67,83 @@
         private static final int TAG_OFFSET = 20;
         private static final int DATA_START = 24;
 
+        // Value types
+        private static final byte INT_TYPE    = 0;
+        private static final byte LONG_TYPE   = 1;
+        private static final byte STRING_TYPE = 2;
+        private static final byte LIST_TYPE   = 3;
+
         /** @param data containing event, read from the system */
-        public Event(byte[] data) {
+        /*package*/ Event(byte[] data) {
             mBuffer = ByteBuffer.wrap(data);
             mBuffer.order(ByteOrder.nativeOrder());
         }
 
+        /** @return the process ID which wrote the log entry */
         public int getProcessId() {
             return mBuffer.getInt(PROCESS_OFFSET);
         }
 
+        /** @return the thread ID which wrote the log entry */
         public int getThreadId() {
             return mBuffer.getInt(THREAD_OFFSET);
         }
 
+        /** @return the wall clock time when the entry was written */
         public long getTimeNanos() {
             return mBuffer.getInt(SECONDS_OFFSET) * 1000000000l
                     + mBuffer.getInt(NANOSECONDS_OFFSET);
         }
 
+        /** @return the type tag code of the entry */
         public int getTag() {
             return mBuffer.getInt(TAG_OFFSET);
         }
 
-        /** @return one of Integer, Long, String, or List. */
+        /** @return one of Integer, Long, String, null, or Object[] of same. */
         public synchronized Object getData() {
-            mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
-            mBuffer.position(DATA_START);  // Just after the tag.
-            return decodeObject();
-        }
-
-        public byte[] getRawData() {
-            return mBuffer.array();
+            try {
+                mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
+                mBuffer.position(DATA_START);  // Just after the tag.
+                return decodeObject();
+            } catch (IllegalArgumentException e) {
+                Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
+                return null;
+            } catch (BufferUnderflowException e) {
+                Log.wtf(TAG, "Truncated entry payload: tag=" + getTag(), e);
+                return null;
+            }
         }
 
         /** @return the loggable item at the current position in mBuffer. */
         private Object decodeObject() {
-            if (mBuffer.remaining() < 1) return null;
-            switch (mBuffer.get()) {
-            case INT:
-                if (mBuffer.remaining() < 4) return null;
+            byte type = mBuffer.get();
+            switch (type) {
+            case INT_TYPE:
                 return (Integer) mBuffer.getInt();
 
-            case LONG:
-                if (mBuffer.remaining() < 8) return null;
+            case LONG_TYPE:
                 return (Long) mBuffer.getLong();
 
-            case STRING:
+            case STRING_TYPE:
                 try {
-                    if (mBuffer.remaining() < 4) return null;
                     int length = mBuffer.getInt();
-                    if (length < 0 || mBuffer.remaining() < length) return null;
                     int start = mBuffer.position();
                     mBuffer.position(start + length);
                     return new String(mBuffer.array(), start, length, "UTF-8");
                 } catch (UnsupportedEncodingException e) {
-                    throw new RuntimeException(e);  // UTF-8 is guaranteed.
+                    Log.wtf(TAG, "UTF-8 is not supported", e);
+                    return null;
                 }
 
-            case LIST:
-                if (mBuffer.remaining() < 1) return null;
+            case LIST_TYPE:
                 int length = mBuffer.get();
-                if (length < 0) return null;
                 Object[] array = new Object[length];
-                for (int i = 0; i < length; ++i) {
-                    array[i] = decodeObject();
-                    if (array[i] == null) return null;
-                }
-                return new List(array);
+                for (int i = 0; i < length; ++i) array[i] = decodeObject();
+                return array;
 
             default:
-                return null;
+                throw new IllegalArgumentException("Unknown entry type: " + type);
             }
         }
     }
@@ -236,46 +151,36 @@
     // We assume that the native methods deal with any concurrency issues.
 
     /**
-     * Send an event log message.
-     * @param tag An event identifer
+     * Record an event log message.
+     * @param tag The event type tag code
      * @param value A value to log
      * @return The number of bytes written
      */
     public static native int writeEvent(int tag, int value);
 
     /**
-     * Send an event log message.
-     * @param tag An event identifer
+     * Record an event log message.
+     * @param tag The event type tag code
      * @param value A value to log
      * @return The number of bytes written
      */
     public static native int writeEvent(int tag, long value);
 
     /**
-     * Send an event log message.
-     * @param tag An event identifer
+     * Record an event log message.
+     * @param tag The event type tag code
      * @param str A value to log
      * @return The number of bytes written
      */
     public static native int writeEvent(int tag, String str);
 
     /**
-     * Send an event log message.
-     * @param tag An event identifer
-     * @param list A {@link List} to log
-     * @return The number of bytes written
-     */
-    public static native int writeEvent(int tag, List list);
-
-    /**
-     * Send an event log message.
-     * @param tag An event identifer
+     * Record an event log message.
+     * @param tag The event type tag code
      * @param list A list of values to log
      * @return The number of bytes written
      */
-    public static int writeEvent(int tag, Object... list) {
-        return writeEvent(tag, new List(list));
-    }
+    public static native int writeEvent(int tag, Object... list);
 
     /**
      * Read events from the log, filtered by type.
@@ -287,11 +192,65 @@
             throws IOException;
 
     /**
-     * Read events from a file.
-     * @param path to read from
-     * @param output container to add events into
-     * @throws IOException if something goes wrong reading events
+     * Get the name associated with an event type tag code.
+     * @param tag code to look up
+     * @return the name of the tag, or null if no tag has that number
      */
-    public static native void readEvents(String path, Collection<Event> output)
-            throws IOException;
+    public static String getTagName(int tag) {
+        readTagsFile();
+        return sTagNames.get(tag);
+    }
+
+    /**
+     * Get the event type tag code associated with an event name.
+     * @param name of event to look up
+     * @return the tag code, or -1 if no tag has that name
+     */
+    public static int getTagCode(String name) {
+        readTagsFile();
+        Integer code = sTagCodes.get(name);
+        return code != null ? code : -1;
+    }
+
+    /**
+     * Read TAGS_FILE, populating sTagCodes and sTagNames, if not already done.
+     */
+    private static synchronized void readTagsFile() {
+        if (sTagCodes != null && sTagNames != null) return;
+
+        sTagCodes = new HashMap<String, Integer>();
+        sTagNames = new HashMap<Integer, String>();
+
+        Pattern comment = Pattern.compile(COMMENT_PATTERN);
+        Pattern tag = Pattern.compile(TAG_PATTERN);
+        BufferedReader reader = null;
+        String line;
+
+        try {
+            reader = new BufferedReader(new FileReader(TAGS_FILE), 256);
+            while ((line = reader.readLine()) != null) {
+                if (comment.matcher(line).matches()) continue;
+
+                Matcher m = tag.matcher(line);
+                if (!m.matches()) {
+                    Log.wtf(TAG, "Bad entry in " + TAGS_FILE + ": " + line);
+                    continue;
+                }
+
+                try {
+                    int num = Integer.parseInt(m.group(1));
+                    String name = m.group(2);
+                    sTagCodes.put(name, num);
+                    sTagNames.put(num, name);
+                } catch (NumberFormatException e) {
+                    Log.wtf(TAG, "Error in " + TAGS_FILE + ": " + line, e);
+                }
+            }
+        } catch (IOException e) {
+            Log.wtf(TAG, "Error reading " + TAGS_FILE, e);
+            // Leave the maps existing but unpopulated
+        } finally {
+            try { if (reader != null) reader.close(); } catch (IOException e) {}
+        }
+    }
 }
diff --git a/core/java/android/util/EventLogTags.java b/core/java/android/util/EventLogTags.java
index be905e3..98868f7 100644
--- a/core/java/android/util/EventLogTags.java
+++ b/core/java/android/util/EventLogTags.java
@@ -25,16 +25,14 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-/** Parsed representation of /etc/event-log-tags. */
+/**
+ * to-bo-deprecated: This class is no longer functional.
+ * Use {@link android.util.EventLog} instead.
+ */
 public class EventLogTags {
-    private final static String TAG = "EventLogTags";
-
-    private final static String TAGS_FILE = "/etc/event-log-tags";
-
     public static class Description {
         public final int mTag;
         public final String mName;
-        // TODO: Parse parameter descriptions when anyone has a use for them.
 
         Description(int tag, String name) {
             mTag = tag;
@@ -42,49 +40,11 @@
         }
     }
 
-    private final static Pattern COMMENT_PATTERN = Pattern.compile(
-            "^\\s*(#.*)?$");
+    public EventLogTags() throws IOException {}
 
-    private final static Pattern TAG_PATTERN = Pattern.compile(
-            "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$");
+    public EventLogTags(BufferedReader input) throws IOException {}
 
-    private final HashMap<String, Description> mNameMap =
-            new HashMap<String, Description>();
+    public Description get(String name) { return null; }
 
-    private final HashMap<Integer, Description> mTagMap =
-            new HashMap<Integer, Description>();
-
-    public EventLogTags() throws IOException {
-        this(new BufferedReader(new FileReader(TAGS_FILE), 256));
-    }
-
-    public EventLogTags(BufferedReader input) throws IOException {
-        String line;
-        while ((line = input.readLine()) != null) {
-            Matcher m = COMMENT_PATTERN.matcher(line);
-            if (m.matches()) continue;
-
-            m = TAG_PATTERN.matcher(line);
-            if (m.matches()) {
-                try {
-                    int tag = Integer.parseInt(m.group(1));
-                    Description d = new Description(tag, m.group(2));
-                    mNameMap.put(d.mName, d);
-                    mTagMap.put(d.mTag, d);
-                } catch (NumberFormatException e) {
-                    Log.e(TAG, "Error in event log tags entry: " + line, e);
-                }
-            } else {
-                Log.e(TAG, "Can't parse event log tags entry: " + line);
-            }
-        }
-    }
-
-    public Description get(String name) {
-        return mNameMap.get(name);
-    }
-
-    public Description get(int tag) {
-        return mTagMap.get(tag);
-    }
+    public Description get(int tag) { return null; }
 }
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 34b7c89..78356cf 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -21,13 +21,6 @@
 #include "jni.h"
 #include "cutils/logger.h"
 
-#define END_DELIMITER '\n'
-#define INT_BUFFER_SIZE (sizeof(jbyte)+sizeof(jint)+sizeof(END_DELIMITER))
-#define LONG_BUFFER_SIZE (sizeof(jbyte)+sizeof(jlong)+sizeof(END_DELIMITER))
-#define INITAL_BUFFER_CAPACITY 256
-
-#define MAX(a,b) ((a>b)?a:b)
-
 namespace android {
 
 static jclass gCollectionClass;
@@ -47,107 +40,6 @@
 
 static jclass gStringClass;
 
-struct ByteBuf {
-    size_t len;
-    size_t capacity;
-    uint8_t* buf;
-
-    ByteBuf(size_t initSize) {
-        buf = (uint8_t*)malloc(initSize);
-        len = 0;
-        capacity = initSize;
-    }
-
-    ~ByteBuf() {
-        free(buf);
-    }
-
-    bool ensureExtraCapacity(size_t extra) {
-        size_t spaceNeeded = len + extra;
-        if (spaceNeeded > capacity) {
-            size_t newCapacity = MAX(spaceNeeded, 2 * capacity);
-            void* newBuf = realloc(buf, newCapacity);
-            if (newBuf == NULL) {
-                return false;
-            }
-            capacity = newCapacity;
-            buf = (uint8_t*)newBuf;
-            return true;
-        } else {
-            return true;
-        }
-    }
-
-    void putIntEvent(jint value) {
-        bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE);
-        buf[len++] = EVENT_TYPE_INT;
-        memcpy(buf+len, &value, sizeof(jint));
-        len += sizeof(jint);
-    }
-
-    void putByte(uint8_t value) {
-        bool succeeded = ensureExtraCapacity(sizeof(uint8_t));
-        buf[len++] = value;
-    }
-
-    void putLongEvent(jlong value) {
-        bool succeeded = ensureExtraCapacity(LONG_BUFFER_SIZE);
-        buf[len++] = EVENT_TYPE_LONG;
-        memcpy(buf+len, &value, sizeof(jlong));
-        len += sizeof(jlong);
-    }
-
-
-    void putStringEvent(JNIEnv* env, jstring value) {
-        const char* strValue = env->GetStringUTFChars(value, NULL);
-        uint32_t strLen = strlen(strValue); //env->GetStringUTFLength(value);
-        bool succeeded = ensureExtraCapacity(1 + sizeof(uint32_t) + strLen);
-        buf[len++] = EVENT_TYPE_STRING;
-        memcpy(buf+len, &strLen, sizeof(uint32_t));
-        len += sizeof(uint32_t);
-        memcpy(buf+len, strValue, strLen);
-        env->ReleaseStringUTFChars(value, strValue);
-        len += strLen;
-    }
-
-    void putList(JNIEnv* env, jobject list) {
-        jobjectArray items = (jobjectArray) env->GetObjectField(list, gListItemsID);
-        if (items == NULL) {
-            jniThrowException(env, "java/lang/NullPointerException", NULL);
-            return;
-        }
-
-        jsize numItems = env->GetArrayLength(items);
-        putByte(EVENT_TYPE_LIST);
-        putByte(numItems);
-        // We'd like to call GetPrimitveArrayCritical() but that might
-        // not be safe since we're going to be doing some I/O
-        for (int i = 0; i < numItems; i++) {
-            jobject item = env->GetObjectArrayElement(items, i);
-            if (env->IsInstanceOf(item, gIntegerClass)) {
-                jint intVal = env->GetIntField(item, gIntegerValueID);
-                putIntEvent(intVal);
-            } else if (env->IsInstanceOf(item, gLongClass)) {
-                jlong longVal = env->GetLongField(item, gLongValueID);
-                putLongEvent(longVal);
-            } else if (env->IsInstanceOf(item, gStringClass)) {
-                putStringEvent(env, (jstring)item);
-            } else if (env->IsInstanceOf(item, gListClass)) {
-                putList(env, item);
-            } else {
-                jniThrowException(
-                        env,
-                        "java/lang/IllegalArgumentException",
-                        "Attempt to log an illegal item type.");
-                return;
-            }
-            env->DeleteLocalRef(item);
-        }
-
-        env->DeleteLocalRef(items);
-    }
-};
-
 /*
  * In class android.util.EventLog:
  *  static native int writeEvent(int tag, int value)
@@ -170,41 +62,80 @@
 
 /*
  * In class android.util.EventLog:
- *  static native int writeEvent(long tag, List value)
- */
-static jint android_util_EventLog_writeEvent_List(JNIEnv* env, jobject clazz,
-                                                  jint tag, jobject value) {
-    if (value == NULL) {
-        jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
-        env->ThrowNew(clazz, "writeEvent needs a value.");
-        return -1;
-    }
-    ByteBuf byteBuf(INITAL_BUFFER_CAPACITY);
-    byteBuf.putList(env, value);
-    byteBuf.putByte((uint8_t)END_DELIMITER);
-    int numBytesPut = byteBuf.len;
-    int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut);
-    return bytesWritten;
-}
-
-/*
- * In class android.util.EventLog:
  *  static native int writeEvent(int tag, String value)
  */
 static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz,
                                                     jint tag, jstring value) {
+    uint8_t buf[LOGGER_ENTRY_MAX_PAYLOAD];
+
+    // Don't throw NPE -- I feel like it's sort of mean for a logging function
+    // to be all crashy if you pass in NULL -- but make the NULL value explicit.
+    const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL";
+    jint len = strlen(str);
+    const int max = sizeof(buf) - sizeof(len) - 2;  // Type byte, final newline
+    if (len > max) len = max;
+
+    buf[0] = EVENT_TYPE_STRING;
+    memcpy(&buf[1], &len, sizeof(len));
+    memcpy(&buf[1 + sizeof(len)], str, len);
+    buf[1 + sizeof(len) + len] = '\n';
+
+    if (value != NULL) env->ReleaseStringUTFChars(value, str);
+    return android_bWriteLog(tag, buf, 2 + sizeof(len) + len);
+}
+
+/*
+ * In class android.util.EventLog:
+ *  static native int writeEvent(long tag, Object... value)
+ */
+static jint android_util_EventLog_writeEvent_Array(JNIEnv* env, jobject clazz,
+                                                   jint tag, jobjectArray value) {
     if (value == NULL) {
-        jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
-        env->ThrowNew(clazz, "logEvent needs a value.");
-        return -1;
+        return android_util_EventLog_writeEvent_String(env, clazz, tag, NULL);
     }
 
-    ByteBuf byteBuf(INITAL_BUFFER_CAPACITY);
-    byteBuf.putStringEvent(env, value);
-    byteBuf.putByte((uint8_t)END_DELIMITER);
-    int numBytesPut = byteBuf.len;
-    int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut);
-    return bytesWritten;
+    uint8_t buf[LOGGER_ENTRY_MAX_PAYLOAD];
+    const size_t max = sizeof(buf) - 1;  // leave room for final newline
+    size_t pos = 2;  // Save room for type tag & array count
+
+    jsize copied = 0, num = env->GetArrayLength(value);
+    for (; copied < num && copied < 256; ++copied) {
+        jobject item = env->GetObjectArrayElement(value, copied);
+        if (item == NULL || env->IsInstanceOf(item, gStringClass)) {
+            if (pos + 1 + sizeof(jint) > max) break;
+            const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL";
+            jint len = strlen(str);
+            if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len);
+            buf[pos++] = EVENT_TYPE_STRING;
+            memcpy(&buf[pos], &len, sizeof(len));
+            memcpy(&buf[pos + sizeof(len)], str, len);
+            pos += sizeof(len) + len;
+            if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str);
+        } else if (env->IsInstanceOf(item, gIntegerClass)) {
+            jint intVal = env->GetIntField(item, gIntegerValueID);
+            if (pos + 1 + sizeof(intVal) > max) break;
+            buf[pos++] = EVENT_TYPE_INT;
+            memcpy(&buf[pos], &intVal, sizeof(intVal));
+            pos += sizeof(intVal);
+        } else if (env->IsInstanceOf(item, gLongClass)) {
+            jlong longVal = env->GetLongField(item, gLongValueID);
+            if (pos + 1 + sizeof(longVal) > max) break;
+            buf[pos++] = EVENT_TYPE_LONG;
+            memcpy(&buf[pos], &longVal, sizeof(longVal));
+            pos += sizeof(longVal);
+        } else {
+            jniThrowException(env,
+                    "java/lang/IllegalArgumentException",
+                    "Invalid payload item type");
+            return -1;
+        }
+        env->DeleteLocalRef(item);
+    }
+
+    buf[0] = EVENT_TYPE_LIST;
+    buf[1] = copied;
+    buf[pos++] = '\n';
+    return android_bWriteLog(tag, buf, pos);
 }
 
 /*
@@ -276,81 +207,6 @@
 }
 
 /*
- * In class android.util.EventLog:
- *  static native void readEvents(String path, Collection<Event> output)
- *
- *  Reads events from a file (See Checkin.Aggregation). Events are stored in
- *  native raw format (logger_entry + payload).
- */
-static void android_util_EventLog_readEventsFile(JNIEnv* env, jobject clazz, jstring path,
-            jobject out) {
-    if (path == NULL || out == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", NULL);
-        return;
-    }
-
-    const char *pathString = env->GetStringUTFChars(path, 0);
-    int fd = open(pathString, O_RDONLY | O_NONBLOCK);
-    env->ReleaseStringUTFChars(path, pathString);
-
-    if (fd < 0) {
-        jniThrowIOException(env, errno);
-        return;
-    }
-
-    uint8_t buf[LOGGER_ENTRY_MAX_LEN];
-    for (;;) {
-        // read log entry structure from file
-        int len = read(fd, buf, sizeof(logger_entry));
-        if (len == 0) {
-            break; // end of file
-        } else if (len < 0) {
-            jniThrowIOException(env, errno);
-        } else if ((size_t) len < sizeof(logger_entry)) {
-            jniThrowException(env, "java/io/IOException", "Event header too short");
-            break;
-        }
-
-        // read event payload
-        logger_entry* entry = (logger_entry*) buf;
-        if (entry->len > LOGGER_ENTRY_MAX_PAYLOAD) {
-            jniThrowException(env,
-                    "java/lang/IllegalArgumentException",
-                    "Too much data for event payload. Corrupt file?");
-            break;
-        }
-
-        len = read(fd, buf + sizeof(logger_entry), entry->len);
-        if (len == 0) {
-            break; // end of file
-        } else if (len < 0) {
-            jniThrowIOException(env, errno);
-        } else if ((size_t) len < entry->len) {
-            jniThrowException(env, "java/io/IOException", "Event payload too short");
-            break;
-        }
-
-        // create EventLog$Event and add it to the collection
-        int buffer_size = sizeof(logger_entry) + entry->len;
-        jbyteArray array = env->NewByteArray(buffer_size);
-        if (array == NULL) break;
-
-        jbyte *bytes = env->GetByteArrayElements(array, NULL);
-        memcpy(bytes, buf, buffer_size);
-        env->ReleaseByteArrayElements(array, bytes, 0);
-
-        jobject event = env->NewObject(gEventClass, gEventInitID, array);
-        if (event == NULL) break;
-
-        env->CallBooleanMethod(out, gCollectionAddID, event);
-        env->DeleteLocalRef(event);
-        env->DeleteLocalRef(array);
-    }
-
-    close(fd);
-}
-
-/*
  * JNI registration.
  */
 static JNINativeMethod gRegisterMethods[] = {
@@ -362,22 +218,17 @@
       (void*) android_util_EventLog_writeEvent_String
     },
     { "writeEvent",
-      "(ILandroid/util/EventLog$List;)I",
-      (void*) android_util_EventLog_writeEvent_List
+      "(I[Ljava/lang/Object;)I",
+      (void*) android_util_EventLog_writeEvent_Array
     },
     { "readEvents",
       "([ILjava/util/Collection;)V",
       (void*) android_util_EventLog_readEvents
     },
-    { "readEvents",
-      "(Ljava/lang/String;Ljava/util/Collection;)V",
-      (void*) android_util_EventLog_readEventsFile
-    }
 };
 
 static struct { const char *name; jclass *clazz; } gClasses[] = {
     { "android/util/EventLog$Event", &gEventClass },
-    { "android/util/EventLog$List", &gListClass },
     { "java/lang/Integer", &gIntegerClass },
     { "java/lang/Long", &gLongClass },
     { "java/lang/String", &gStringClass },
@@ -386,7 +237,6 @@
 
 static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
     { &gIntegerClass, "value", "I", &gIntegerValueID },
-    { &gListClass, "mItems", "[Ljava/lang/Object;", &gListItemsID },
     { &gLongClass, "value", "J", &gLongValueID },
 };
 
@@ -430,4 +280,3 @@
 }
 
 }; // namespace android
-
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index ecd3380..979b8ba 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -822,11 +822,9 @@
                 mRetryMgr.resetRetryCount();
 
                 CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
-                int bsid = (loc != null) ? loc.getBaseStationId() : -1;
-
-                EventLog.List val = new EventLog.List(bsid,
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_SETUP_FAILED,
+                        loc != null ? loc.getBaseStationId() : -1,
                         TelephonyManager.getDefault().getNetworkType());
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_SETUP_FAILED, val);
             }
             trySetupData(Phone.REASON_CDMA_DATA_DETACHED);
         }
@@ -865,10 +863,9 @@
 
     private void writeEventLogCdmaDataDrop() {
         CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
-        int bsid = (loc != null) ? loc.getBaseStationId() : -1;
-        EventLog.List val = new EventLog.List(bsid,
+        EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_DROP,
+                loc != null ? loc.getBaseStationId() : -1,
                 TelephonyManager.getDefault().getNetworkType());
-        EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_DROP, val);
     }
 
     protected void onDataStateChanged(AsyncResult ar) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 8698b38..9289ad4 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -537,11 +537,9 @@
         } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
             DataConnectionTracker dcTracker = phone.mDataConnection;
             if (! dcTracker.isDataConnectionAsDesired()) {
-
-                EventLog.List val = new EventLog.List(
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF,
                         dcTracker.getStateInString(),
-                        (dcTracker.getAnyDataEnabled() ? 1 : 0) );
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val);
+                        dcTracker.getAnyDataEnabled() ? 1 : 0);
             }
             Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
             msg.arg1 = 1; // tearDown is true
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index 91c089e..f4b9931 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -868,13 +868,10 @@
                     causeCode == CallFailCause.QOS_NOT_AVAIL ||
                     causeCode == CallFailCause.BEARER_NOT_AVAIL ||
                     causeCode == CallFailCause.ERROR_UNSPECIFIED) {
-                    int cid = -1;
                     GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                    if (loc != null) cid = loc.getCid();
-
-                    EventLog.List val = new EventLog.List(causeCode, cid,
-                        TelephonyManager.getDefault().getNetworkType());
-                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CALL_DROP, val);
+                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CALL_DROP,
+                            causeCode, loc != null ? loc.getCid() : -1,
+                            TelephonyManager.getDefault().getNetworkType());
                 }
 
                 for (int i = 0, s =  droppedDuringPoll.size()
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 5c97925..13407a3 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -710,12 +710,10 @@
                 Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
 
                 // Add an event log when the network drops PDP
-                int cid = -1;
                 GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                if (loc != null) cid = loc.getCid();
-                EventLog.List val = new EventLog.List(cid,
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP,
+                        loc != null ? loc.getCid() : -1,
                         TelephonyManager.getDefault().getNetworkType());
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
 
                 cleanUpConnection(true, null);
                 return;
@@ -733,12 +731,10 @@
                                     + " Reconnecting");
 
                     // Log the network drop on the event log.
-                    int cid = -1;
                     GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                    if (loc != null) cid = loc.getCid();
-                    EventLog.List val = new EventLog.List(cid,
+                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP,
+                            loc != null ? loc.getCid() : -1,
                             TelephonyManager.getDefault().getNetworkType());
-                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
 
                     cleanUpConnection(true, null);
                 }
@@ -1148,14 +1144,10 @@
             if(DBG) log("PDP setup failed " + cause);
                     // Log this failure to the Event Logs.
             if (cause.isEventLoggable()) {
-                int cid = -1;
                 GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                if (loc != null) cid = loc.getCid();
-
-                EventLog.List val = new EventLog.List(
-                        cause.ordinal(), cid,
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL,
+                        cause.ordinal(), loc != null ? loc.getCid() : -1,
                         TelephonyManager.getDefault().getNetworkType());
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val);
             }
 
             // No try for permanent failure
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index f82474c..3e5f53c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -482,12 +482,9 @@
                     // Can't register data sevice while voice service is ok
                     // i.e. CREG is ok while CGREG is not
                     // possible a network or baseband side error
-                    int cid = -1;
                     GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                    if (loc != null) cid = loc.getCid();
-
-                    EventLog.List val = new EventLog.List(ss.getOperatorNumeric(), cid);
-                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CGREG_FAIL, val);
+                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CGREG_FAIL,
+                            ss.getOperatorNumeric(), loc != null ? loc.getCid() : -1);
                     mReportedGprsNoReg = true;
                 }
                 mStartedGprsRegCheck = false;
@@ -518,11 +515,8 @@
         } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
             DataConnectionTracker dcTracker = phone.mDataConnection;
             if (! dcTracker.isDataConnectionAsDesired()) {
-
-                EventLog.List val = new EventLog.List(
-                        dcTracker.getStateInString(),
-                        (dcTracker.getAnyDataEnabled() ? 1 : 0) );
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val);
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF,
+                        dcTracker.getStateInString(), dcTracker.getAnyDataEnabled() ? 1 : 0);
             }
             Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
             msg.arg1 = 1; // tearDown is true
diff --git a/tests/framework-tests/src/android/util/EventLogFunctionalTest.java b/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
index 8263083..8afe35f 100644
--- a/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
+++ b/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
@@ -59,31 +59,21 @@
      }
 
     public void testLogOfListWithOneInt() throws Exception {
-        final EventLog.List list = new EventLog.List(1234);
-        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, new Object[] {1234});
         Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + 1 + 4 + 1, numBytes);
     }
 
     public void testLogOfListWithMultipleInts() throws Exception {
-       final EventLog.List list = new EventLog.List(1234, 2345, 3456);
-        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, new Object[] {1234, 2345, 3456});
         Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + 1 + 4 + 1 + 4 + 1 + 4 + 1, numBytes);
     }
 
-    public void testLogOfListWithEmbeddedList() throws Exception {
-        final EventLog.List list = new EventLog.List(
-                new EventLog.List(1234, 2345, 3456));
-        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
-        Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 2 + 1 + 1 + 4 + 1 + 4 + 1 + 4 + 1, numBytes);
-    }
-
     public void testEventLargerThanInitialBufferCapacity() throws Exception {
         final Integer[] array = new Integer[127];
         for (int i = 0; i < array.length; i++) {
             array[i] = i;
         }
-        final EventLog.List list = new EventLog.List((Object[]) array);
-        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, (Object[]) array);
         Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + (5 * array.length) + 1, numBytes);
     }
 
@@ -117,8 +107,7 @@
     // This test is obsolete. See http://b/issue?id=1262082
     public void disableTestReadCompoundEntry() throws Exception {
         long when = System.currentTimeMillis();
-        EventLog.writeEvent(2719,
-                new EventLog.List(1l, new EventLog.List("2", "three", "4"), 5));
+        EventLog.writeEvent(2719, 1l, "2", 3);
         Log.i(TAG, "Wrote compound event at T=" + when);
 
         ArrayList<EventLog.Event> list = new ArrayList<EventLog.Event>();
@@ -129,18 +118,11 @@
             long eventTime = event.getTimeNanos() / 1000000;
             Log.i(TAG, "  Found event T=" + eventTime);
             if (eventTime > when - 100 && eventTime < when + 1000) {
-                EventLog.List data = (EventLog.List) event.getData();
-                assertEquals(data.getNumItems(), 3);
-
-                EventLog.List nested = (EventLog.List) data.getItem(1);
-                assertEquals(nested.getNumItems(), 3);
-
-                assertEquals(data.getItem(0), 1l);
-                assertEquals(nested.getItem(0), "2");
-                assertEquals(nested.getItem(1), "three");
-                assertEquals(nested.getItem(2), "4");
-                assertEquals(data.getItem(2), 5);
-
+                Object[] data = (Object[]) event.getData();
+                assertEquals(data.length, 3);
+                assertEquals(data[0], 1l);
+                assertEquals(data[1], "2");
+                assertEquals(data[2], 3);
                 assertFalse(found);
                 found = true;
             }
diff --git a/tests/framework-tests/src/android/util/EventLogTest.java b/tests/framework-tests/src/android/util/EventLogTest.java
index 4a5d888..2a9e9cd 100644
--- a/tests/framework-tests/src/android/util/EventLogTest.java
+++ b/tests/framework-tests/src/android/util/EventLogTest.java
@@ -33,13 +33,13 @@
 
     public void testIllegalListTypesThrowException() throws Exception {
         try {
-            EventLog.writeEvent(TEST_TAG, new EventLog.List(new Object()));
+            EventLog.writeEvent(TEST_TAG, new Object[]{new Object()});
             fail("Can't create List with any old Object");
         } catch (IllegalArgumentException e) {
             // expected
         }
         try {
-            EventLog.writeEvent(TEST_TAG, new EventLog.List((byte) 1));
+            EventLog.writeEvent(TEST_TAG, new Object[]{(byte) 1});
             fail("Can't create List with any old byte");
         } catch (IllegalArgumentException e) {
             // expected