auto import from //depot/cupcake/@135843
diff --git a/eventanalyzer/.classpath b/eventanalyzer/.classpath
new file mode 100644
index 0000000..b0326c8
--- /dev/null
+++ b/eventanalyzer/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/eventanalyzer/.project b/eventanalyzer/.project
new file mode 100644
index 0000000..2862978
--- /dev/null
+++ b/eventanalyzer/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>eventanalyzer</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/eventanalyzer/Android.mk b/eventanalyzer/Android.mk
new file mode 100644
index 0000000..18e730e
--- /dev/null
+++ b/eventanalyzer/Android.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2008 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.
+#
+EVENTANALUZER_LOCAL_DIR := $(call my-dir)
+include $(EVENTANALUZER_LOCAL_DIR)/etc/Android.mk
+include $(EVENTANALUZER_LOCAL_DIR)/src/Android.mk
diff --git a/eventanalyzer/etc/Android.mk b/eventanalyzer/etc/Android.mk
new file mode 100644
index 0000000..e7703b4
--- /dev/null
+++ b/eventanalyzer/etc/Android.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2008 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.
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_PREBUILT_EXECUTABLES := eventanalyzer
+include $(BUILD_HOST_PREBUILT)
+
diff --git a/eventanalyzer/etc/eventanalyzer b/eventanalyzer/etc/eventanalyzer
new file mode 100755
index 0000000..d6c7895
--- /dev/null
+++ b/eventanalyzer/etc/eventanalyzer
@@ -0,0 +1,73 @@
+#!/bin/sh
+# Copyright 2005-2007, 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+    newProg=`/bin/ls -ld "${prog}"`
+    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+    if expr "x${newProg}" : 'x/' >/dev/null; then
+        prog="${newProg}"
+    else
+        progdir=`dirname "${prog}"`
+        prog="${progdir}/${newProg}"
+    fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+jarfile=eventanalyzer.jar
+frameworkdir="$progdir"
+libdir="$progdir"
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+    frameworkdir=`dirname "$progdir"`/tools/lib
+    libdir=`dirname "$progdir"`/tools/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+    frameworkdir=`dirname "$progdir"`/framework
+    libdir=`dirname "$progdir"`/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+    echo `basename "$prog"`": can't find $jarfile"
+    exit 1
+fi
+
+
+# Check args.
+# Mac OS X needs an additional arg, or you get an "illegal thread" complaint.
+if [ `uname` = "Darwin" ]; then
+    os_opts="-XstartOnFirstThread"
+else
+    os_opts=
+fi
+
+if [ "$OSTYPE" = "cygwin" ] ; then
+    jarpath=`cygpath -w  "$frameworkdir/$jarfile"`
+    progdir=`cygpath -w  "$progdir"`
+else
+    jarpath="$frameworkdir/$jarfile"
+fi
+
+# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
+# might need more memory, e.g. -Xmx128M
+exec java -Xmx128M $os_opts -Djava.ext.dirs="$frameworkdir" -Djava.library.path="$libdir" -jar "$jarpath" "$@"
diff --git a/eventanalyzer/etc/manifest.txt b/eventanalyzer/etc/manifest.txt
new file mode 100644
index 0000000..6d99ea1
--- /dev/null
+++ b/eventanalyzer/etc/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.eventanalyzer.EventAnalyzer
diff --git a/eventanalyzer/src/Android.mk b/eventanalyzer/src/Android.mk
new file mode 100644
index 0000000..e65c61f
--- /dev/null
+++ b/eventanalyzer/src/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2008 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.
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAR_MANIFEST := ../etc/manifest.txt
+LOCAL_JAVA_LIBRARIES := \
+	ddmlib
+LOCAL_MODULE := eventanalyzer
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/eventanalyzer/src/com/android/eventanalyzer/EventAnalyzer.java b/eventanalyzer/src/com/android/eventanalyzer/EventAnalyzer.java
new file mode 100644
index 0000000..c520784
--- /dev/null
+++ b/eventanalyzer/src/com/android/eventanalyzer/EventAnalyzer.java
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2008 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 com.android.eventanalyzer;
+
+import com.android.ddmlib.AndroidDebugBridge;
+import com.android.ddmlib.Device;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.Log.ILogOutput;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.log.EventContainer;
+import com.android.ddmlib.log.EventLogParser;
+import com.android.ddmlib.log.InvalidTypeException;
+import com.android.ddmlib.log.LogReceiver;
+import com.android.ddmlib.log.LogReceiver.ILogListener;
+import com.android.ddmlib.log.LogReceiver.LogEntry;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * Connects to a device using ddmlib and analyze its event log. 
+ */
+public class EventAnalyzer implements ILogListener {
+    
+    private final static int TAG_ACTIVITY_LAUNCH_TIME = 30009;
+    private final static char DATA_SEPARATOR = ',';
+
+    private final static String CVS_EXT = ".csv";
+    private final static String TAG_FILE_EXT = ".tag"; //$NON-NLS-1$
+    
+    private EventLogParser mParser;
+    private TreeMap<String, ArrayList<Long>> mLaunchMap = new TreeMap<String, ArrayList<Long>>(); 
+    
+    String mInputTextFile = null;
+    String mInputBinaryFile = null;
+    String mInputDevice = null;
+    String mInputFolder = null;
+    String mAlternateTagFile = null;
+    String mOutputFile = null;
+
+    public static void main(String[] args) {
+        new EventAnalyzer().run(args);
+    }
+    
+    private void run(String[] args) {
+        if (args.length == 0) {
+            printUsageAndQuit();
+        }
+        
+        int index = 0;
+        do {
+            String argument = args[index++];
+
+            if ("-s".equals(argument)) {
+                checkInputValidity("-s");
+                
+                if (index == args.length) {
+                    printUsageAndQuit();
+                }
+                
+                mInputDevice = args[index++];
+            } else if ("-fb".equals(argument)) {
+                checkInputValidity("-fb");
+                
+                if (index == args.length) {
+                    printUsageAndQuit();
+                }
+                
+                mInputBinaryFile = args[index++];
+            } else if ("-ft".equals(argument)) {
+                checkInputValidity("-ft");
+                
+                if (index == args.length) {
+                    printUsageAndQuit();
+                }
+                
+                mInputTextFile = args[index++];
+            } else if ("-F".equals(argument)) {
+                checkInputValidity("-F");
+                
+                if (index == args.length) {
+                    printUsageAndQuit();
+                }
+                
+                mInputFolder = args[index++];
+            } else if ("-t".equals(argument)) {
+                if (index == args.length) {
+                    printUsageAndQuit();
+                }
+
+                mAlternateTagFile = args[index++];
+            } else {
+                // get the filepath and break.
+                mOutputFile = argument;
+
+                // should not be any other device.
+                if (index < args.length) {
+                    printAndExit("Too many arguments!", false /* terminate */);
+                }
+            }
+        } while (index < args.length);
+
+        if ((mInputTextFile == null && mInputBinaryFile == null && mInputFolder == null &&
+                mInputDevice == null)) {
+            printUsageAndQuit();
+        }
+
+        File outputParent = new File(mOutputFile).getParentFile();
+        if (outputParent == null || outputParent.isDirectory() == false) {
+            printAndExit(String.format("%1$s is not a valid ouput file", mOutputFile),
+                    false /* terminate */);
+        }
+
+        // redirect the log output to /dev/null
+        Log.setLogOutput(new ILogOutput() {
+            public void printAndPromptLog(LogLevel logLevel, String tag, String message) {
+                // pass
+            }
+
+            public void printLog(LogLevel logLevel, String tag, String message) {
+                // pass
+            }
+        });
+
+        try {
+            if (mInputBinaryFile != null) {
+                parseBinaryLogFile();
+            } else if (mInputTextFile != null) {
+                parseTextLogFile(mInputTextFile);
+            } else if (mInputFolder != null) {
+                parseFolder(mInputFolder);
+            } else if (mInputDevice != null) {
+                parseLogFromDevice();
+            }
+            
+            // analyze the data gathered by the parser methods
+            analyzeData();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * Parses a binary event log file located at {@link #mInputBinaryFile}.
+     * @throws IOException 
+     */
+    private void parseBinaryLogFile() throws IOException {
+        mParser = new EventLogParser();
+
+        String tagFile = mInputBinaryFile + TAG_FILE_EXT;
+        if (mParser.init(tagFile) == false) {
+            // if we have an alternate location
+            if (mAlternateTagFile != null) {
+                if (mParser.init(mAlternateTagFile) == false) {
+                    printAndExit("Failed to get event tags from " + mAlternateTagFile,
+                            false /* terminate*/);
+                }
+            } else {
+                printAndExit("Failed to get event tags from " + tagFile, false /* terminate*/);
+            }
+        }
+        
+        LogReceiver receiver = new LogReceiver(this);
+
+        byte[] buffer = new byte[256];
+        
+        FileInputStream fis = new FileInputStream(mInputBinaryFile);
+        
+        int count;
+        while ((count = fis.read(buffer)) != -1) {
+            receiver.parseNewData(buffer, 0, count);
+        }
+    }
+
+    /**
+     * Parse a text Log file.
+     * @param filePath the location of the file.
+     * @throws IOException
+     */
+    private void parseTextLogFile(String filePath) throws IOException {
+        mParser = new EventLogParser();
+
+        String tagFile = filePath + TAG_FILE_EXT;
+        if (mParser.init(tagFile) == false) {
+            // if we have an alternate location
+            if (mAlternateTagFile != null) {
+                if (mParser.init(mAlternateTagFile) == false) {
+                    printAndExit("Failed to get event tags from " + mAlternateTagFile,
+                            false /* terminate*/);
+                }
+            } else {
+                printAndExit("Failed to get event tags from " + tagFile, false /* terminate*/);
+            }
+        }
+
+        // read the lines from the file and process them.
+        BufferedReader reader = new BufferedReader(
+                new InputStreamReader(new FileInputStream(filePath)));
+
+        String line;
+        while ((line = reader.readLine()) != null) {
+            processEvent(mParser.parse(line));
+        }
+    }
+
+    private void parseLogFromDevice() throws IOException {
+        // init the lib
+        AndroidDebugBridge.init(false /* debugger support */);
+        
+        try {
+            AndroidDebugBridge bridge = AndroidDebugBridge.createBridge();
+            
+            // we can't just ask for the device list right away, as the internal thread getting
+            // them from ADB may not be done getting the first list.
+            // Since we don't really want getDevices() to be blocking, we wait here manually.
+            int count = 0;
+            while (bridge.hasInitialDeviceList() == false) {
+                try {
+                    Thread.sleep(100);
+                    count++;
+                } catch (InterruptedException e) {
+                    // pass
+                }
+                
+                // let's not wait > 10 sec.
+                if (count > 100) {
+                    printAndExit("Timeout getting device list!", true /* terminate*/);
+                }
+            }
+
+            // now get the devices
+            Device[] devices = bridge.getDevices();
+            
+            for (Device device : devices) {
+                if (device.getSerialNumber().equals(mInputDevice)) {
+                    grabLogFrom(device);
+                    return;
+                }
+            }
+            
+            System.err.println("Could not find " + mInputDevice);
+        } finally {
+            AndroidDebugBridge.terminate();
+        }
+    }
+    
+    /**
+     * Parses the log files located in the folder, and its sub-folders.
+     * @param folderPath the path to the folder.
+     */
+    private void parseFolder(String folderPath) {
+        File f = new File(folderPath);
+        if (f.isDirectory() == false) {
+            printAndExit(String.format("%1$s is not a valid folder", folderPath),
+                    false /* terminate */);
+        }
+        
+        String[] files = f.list(new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+                name = name.toLowerCase();
+                return name.endsWith(".tag") == false;
+            }
+        });
+        
+        for (String file : files) {
+            try {
+                f = new File(folderPath + File.separator + file);
+                if (f.isDirectory()) {
+                    parseFolder(f.getAbsolutePath());
+                } else {
+                    parseTextLogFile(f.getAbsolutePath());
+                }
+            } catch (IOException e) {
+                // ignore this file.
+            }
+        }
+    }
+
+    private void grabLogFrom(Device device) throws IOException {
+        mParser = new EventLogParser();
+        if (mParser.init(device) == false) {
+            printAndExit("Failed to get event-log-tags from " + device.getSerialNumber(),
+                    true /* terminate*/);
+        }
+        
+        LogReceiver receiver = new LogReceiver(this);
+
+        device.runEventLogService(receiver);
+    }
+    
+    /**
+     * Analyze the data and writes it to {@link #mOutputFile}
+     * @throws IOException
+     */
+    private void analyzeData() throws IOException {
+        BufferedWriter writer = null;
+        try {
+            // make sure the file name has the proper extension.
+            if (mOutputFile.toLowerCase().endsWith(CVS_EXT) == false) {
+                mOutputFile = mOutputFile + CVS_EXT;
+            }
+
+            writer = new BufferedWriter(new FileWriter(mOutputFile));
+            StringBuilder builder = new StringBuilder();
+            
+            // write the list of launch start. One column per activity.
+            Set<String> activities = mLaunchMap.keySet();
+            
+            // write the column headers.
+            for (String activity : activities) {
+                builder.append(activity).append(DATA_SEPARATOR);
+            }
+            writer.write(builder.append('\n').toString());
+            
+            // loop on the activities and write their values.
+            boolean moreValues = true;
+            int index = 0;
+            while (moreValues) {
+                moreValues = false;
+                builder.setLength(0);
+                
+                for (String activity : activities) {
+                    // get the activity list.
+                    ArrayList<Long> list = mLaunchMap.get(activity);
+                    if (index < list.size()) {
+                        moreValues = true;
+                        builder.append(list.get(index).longValue()).append(DATA_SEPARATOR);
+                    } else {
+                        builder.append(DATA_SEPARATOR);
+                    }
+                }
+                
+                // write the line.
+                if (moreValues) {
+                    writer.write(builder.append('\n').toString());
+                }
+                
+                index++;
+            }
+            
+            // write per-activity stats.
+            for (String activity : activities) {
+                builder.setLength(0);
+                builder.append(activity).append(DATA_SEPARATOR);
+    
+                // get the activity list.
+                ArrayList<Long> list = mLaunchMap.get(activity);
+                
+                // sort the list
+                Collections.sort(list);
+                
+                // write min/max
+                builder.append(list.get(0).longValue()).append(DATA_SEPARATOR);
+                builder.append(list.get(list.size()-1).longValue()).append(DATA_SEPARATOR);
+    
+                // write median value
+                builder.append(list.get(list.size()/2).longValue()).append(DATA_SEPARATOR);
+                
+                // compute and write average
+                long total = 0; // despite being encoded on a long, the values are low enough that
+                                // a Long should be enough to compute the total
+                for (Long value : list) {
+                    total += value.longValue();
+                }
+                builder.append(total / list.size()).append(DATA_SEPARATOR);
+                
+                // finally write the data.
+                writer.write(builder.append('\n').toString());
+            }
+        } finally {
+            writer.close();
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see com.android.ddmlib.log.LogReceiver.ILogListener#newData(byte[], int, int)
+     */
+    public void newData(byte[] data, int offset, int length) {
+        // we ignore raw data. New entries are processed in #newEntry(LogEntry)
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see com.android.ddmlib.log.LogReceiver.ILogListener#newEntry(com.android.ddmlib.log.LogReceiver.LogEntry)
+     */
+    public void newEntry(LogEntry entry) {
+        // parse and process the entry data.
+        processEvent(mParser.parse(entry));
+    }
+    
+    private void processEvent(EventContainer event) {
+        if (event != null && event.mTag == TAG_ACTIVITY_LAUNCH_TIME) {
+            // get the activity name
+            try {
+                String name = event.getValueAsString(0);
+
+                // get the launch time
+                Object value = event.getValue(1);
+                if (value instanceof Long) {
+                    addLaunchTime(name, (Long)value);
+                }
+
+            } catch (InvalidTypeException e) {
+                // Couldn't get the name as a string...
+                // Ignore this event.
+            }
+        }
+    }
+
+    private void addLaunchTime(String name, Long value) {
+        ArrayList<Long> list = mLaunchMap.get(name);
+        
+        if (list == null) {
+            list = new ArrayList<Long>();
+            mLaunchMap.put(name, list);
+        }
+        
+        list.add(value);
+    }
+
+    private void checkInputValidity(String option) {
+        if (mInputTextFile != null || mInputBinaryFile != null) {
+            printAndExit(String.format("ERROR: %1$s cannot be used with an input file.", option),
+                    false /* terminate */);
+        } else if (mInputFolder != null) {
+            printAndExit(String.format("ERROR: %1$s cannot be used with an input file.", option),
+                    false /* terminate */);
+        } else if (mInputDevice != null) {
+            printAndExit(String.format("ERROR: %1$s cannot be used with an input device serial number.",
+                    option), false /* terminate */);
+        }
+    }
+
+    private static void printUsageAndQuit() {
+        // 80 cols marker:  01234567890123456789012345678901234567890123456789012345678901234567890123456789
+        System.out.println("Usage:");
+        System.out.println("   eventanalyzer [-t <TAG_FILE>] <SOURCE> <OUTPUT>");
+        System.out.println("");
+        System.out.println("Possible sources:");
+        System.out.println("   -fb <file>    The path to a binary event log, gathered by dumpeventlog");
+        System.out.println("   -ft <file>    The path to a text event log, gathered by adb logcat -b events");
+        System.out.println("   -F <folder>   The path to a folder containing multiple text log files.");
+        System.out.println("   -s <serial>   The serial number of the Device to grab the event log from.");
+        System.out.println("Options:");
+        System.out.println("   -t <file>     The path to tag file to use in case the one associated with");
+        System.out.println("                 the source is missing");
+        
+        System.exit(1);
+    }
+    
+    
+    private static void printAndExit(String message, boolean terminate) {
+        System.out.println(message);
+        if (terminate) {
+            AndroidDebugBridge.terminate();
+        }
+        System.exit(1);
+    }
+}