Home | History | Annotate | Download | only in profiler
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package dalvik.system.profiler;
     18 
     19 import java.io.BufferedInputStream;
     20 import java.io.Closeable;
     21 import java.io.DataInputStream;
     22 import java.io.EOFException;
     23 import java.io.File;
     24 import java.io.FileInputStream;
     25 import java.io.IOException;
     26 import java.io.InputStream;
     27 
     28 /**
     29  * Run on device with:
     30  * adb shell dalvikvm 'dalvik.system.profiler.HprofBinaryToAscii'
     31  *
     32  * Run on host with:
     33  * java -classpath out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar
     34  */
     35 public final class HprofBinaryToAscii {
     36 
     37     /**
     38      * Main entry point for HprofBinaryToAscii command line tool
     39      */
     40     public static void main(String[] args) {
     41         System.exit(convert(args) ? 0 : 1);
     42     }
     43 
     44     /**
     45      * Reads single file from arguments and attempts to read it as
     46      * either a binary hprof file or a version with a text header.
     47      */
     48     private static boolean convert(String[] args) {
     49 
     50         if (args.length != 1) {
     51             usage("binary hprof file argument expected");
     52             return false;
     53         }
     54         File file = new File(args[0]);
     55         if (!file.exists()) {
     56             usage("file " + file + " does not exist");
     57             return false;
     58         }
     59 
     60         if (startsWithMagic(file)) {
     61             HprofData hprofData;
     62             try {
     63                 hprofData = readHprof(file);
     64             } catch (IOException e) {
     65                 System.out.println("Problem reading binary hprof data from "
     66                                    + file + ": " + e.getMessage());
     67                 return false;
     68             }
     69             return write(hprofData);
     70         }
     71 
     72         HprofData hprofData;
     73         try {
     74             hprofData = readSnapshot(file);
     75         } catch (IOException e) {
     76             System.out.println("Problem reading snapshot containing binary hprof data from "
     77                                + file + ": " + e.getMessage());
     78             return false;
     79         }
     80         return write(hprofData);
     81     }
     82 
     83     /**
     84      * Probe the start of file to see if it starts with a plausible
     85      * binary hprof magic value. If so, it is returned. On any other
     86      * case including unexpected errors, false is returned.
     87      */
     88     private static boolean startsWithMagic(File file) {
     89         DataInputStream inputStream = null;
     90         try {
     91             inputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
     92             return BinaryHprof.readMagic(inputStream) != null;
     93         } catch (IOException e) {
     94             return false;
     95         } finally {
     96             closeQuietly(inputStream);
     97         }
     98     }
     99 
    100     /**
    101      * Read and return an HprofData from a vanilla binary hprof file.
    102      */
    103     private static HprofData readHprof(File file) throws IOException {
    104         InputStream inputStream = null;
    105         try {
    106             inputStream = new BufferedInputStream(new FileInputStream(file));
    107             return read(inputStream);
    108         } finally {
    109             closeQuietly(inputStream);
    110         }
    111     }
    112 
    113     /**
    114      * Read a file looking for text header terminated by two newlines,
    115      * then proceed to read binary hprof data.
    116      */
    117     private static HprofData readSnapshot(File file) throws IOException {
    118         InputStream inputStream = null;
    119         try {
    120             inputStream = new BufferedInputStream(new FileInputStream(file));
    121             int ch;
    122             while ((ch = inputStream.read()) != -1) {
    123                 if (ch == '\n' && inputStream.read() == '\n') {
    124                     return read(inputStream);
    125                 }
    126             }
    127             throw new EOFException("Could not find expected header");
    128         } finally {
    129             closeQuietly(inputStream);
    130         }
    131     }
    132 
    133     /**
    134      * Read binary hprof data from the provided input stream and
    135      * return the HprofData object.
    136      */
    137     private static HprofData read(InputStream inputStream) throws IOException {
    138         BinaryHprofReader reader = new BinaryHprofReader(inputStream);
    139         reader.setStrict(false);
    140         reader.read();
    141         return reader.getHprofData();
    142     }
    143 
    144     /**
    145      * From IoUtils.closeQuietly but replicated for open source
    146      * version.
    147      */
    148     private static void closeQuietly(Closeable c) {
    149         if (c != null) {
    150             try {
    151                 c.close();
    152             } catch (IOException ignored) {
    153             }
    154         }
    155     }
    156 
    157     /**
    158      * Write text verion of hprof data to standard output. Returns
    159      * false on error.
    160      */
    161     private static boolean write(HprofData hprofData) {
    162         try {
    163             AsciiHprofWriter.write(hprofData, System.out);
    164         } catch (IOException e) {
    165             System.out.println("Problem writing ASCII hprof data: " + e.getMessage());
    166             return false;
    167         }
    168         return true;
    169     }
    170 
    171     /**
    172      * Prints usage error but does not exit.
    173      */
    174     private static void usage(String error) {
    175         System.out.print("ERROR: ");
    176         System.out.println(error);
    177         System.out.println();
    178         System.out.println("usage: HprofBinaryToAscii <binary-hprof-file>");
    179         System.out.println();
    180         System.out.println("Reads a binary hprof file and print it in ASCII format");
    181     }
    182 }
    183