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