FileDocCategorySizeDatePackage
EventAnalyzer.javaAPI DocAndroid 1.5 API17419Wed May 06 22:41:10 BST 2009com.android.eventanalyzer

EventAnalyzer

public class EventAnalyzer extends Object implements com.android.ddmlib.log.LogReceiver.ILogListener
Connects to a device using ddmlib and analyze its event log.

Fields Summary
private static final int
TAG_ACTIVITY_LAUNCH_TIME
private static final char
DATA_SEPARATOR
private static final String
CVS_EXT
private static final String
TAG_FILE_EXT
private com.android.ddmlib.log.EventLogParser
mParser
private TreeMap
mLaunchMap
String
mInputTextFile
String
mInputBinaryFile
String
mInputDevice
String
mInputFolder
String
mAlternateTagFile
String
mOutputFile
Constructors Summary
Methods Summary
private voidaddLaunchTime(java.lang.String name, java.lang.Long value)

        ArrayList<Long> list = mLaunchMap.get(name);
        
        if (list == null) {
            list = new ArrayList<Long>();
            mLaunchMap.put(name, list);
        }
        
        list.add(value);
    
private voidanalyzeData()
Analyze the data and writes it to {@link #mOutputFile}

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();
        }
    
private voidcheckInputValidity(java.lang.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 voidgrabLogFrom(com.android.ddmlib.Device device)

        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);
    
public static voidmain(java.lang.String[] args)


         
        new EventAnalyzer().run(args);
    
public voidnewData(byte[] data, int offset, int length)

        // we ignore raw data. New entries are processed in #newEntry(LogEntry)
    
public voidnewEntry(com.android.ddmlib.log.LogReceiver.LogEntry entry)

        // parse and process the entry data.
        processEvent(mParser.parse(entry));
    
private voidparseBinaryLogFile()
Parses a binary event log file located at {@link #mInputBinaryFile}.

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);
        }
    
private voidparseFolder(java.lang.String folderPath)
Parses the log files located in the folder, and its sub-folders.

param
folderPath the path to the folder.

        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 voidparseLogFromDevice()

        // 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();
        }
    
private voidparseTextLogFile(java.lang.String filePath)
Parse a text Log file.

param
filePath the location of the file.
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 static voidprintAndExit(java.lang.String message, boolean terminate)

        System.out.println(message);
        if (terminate) {
            AndroidDebugBridge.terminate();
        }
        System.exit(1);
    
private static voidprintUsageAndQuit()

        // 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 voidprocessEvent(com.android.ddmlib.log.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 voidrun(java.lang.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();
        }