1 /* 2 * Copyright (C) 2012 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 com.android.ide.eclipse.ddms.systrace; 18 19 import com.google.common.base.Charsets; 20 import com.google.common.io.Files; 21 22 import java.io.File; 23 import java.io.IOException; 24 import java.util.zip.DataFormatException; 25 import java.util.zip.Inflater; 26 27 /** {@link SystraceOutputParser} receives the output of atrace command run on the device, 28 * parses it and generates html based on the trace */ 29 public class SystraceOutputParser { 30 private static final String TRACE_START = "TRACE:\n"; //$NON-NLS-1$ 31 32 private final boolean mUncompress; 33 private final String mJs; 34 private final String mCss; 35 private final String mHtmlPrefix; 36 private final String mHtmlSuffix; 37 38 private byte[] mAtraceOutput; 39 private int mAtraceLength; 40 private int mSystraceIndex = -1; 41 42 /** 43 * Constructs a atrace output parser. 44 * @param compressedStream Is the input stream compressed using zlib? 45 * @param systraceJs systrace javascript content 46 * @param systraceCss systrace css content 47 */ SystraceOutputParser(boolean compressedStream, String systraceJs, String systraceCss, String htmlPrefix, String htmlSuffix)48 public SystraceOutputParser(boolean compressedStream, String systraceJs, String systraceCss, 49 String htmlPrefix, String htmlSuffix) { 50 mUncompress = compressedStream; 51 mJs = systraceJs; 52 mCss = systraceCss; 53 mHtmlPrefix = htmlPrefix; 54 mHtmlSuffix = htmlSuffix; 55 } 56 57 /** 58 * Parses the atrace output for systrace content. 59 * @param atraceOutput output bytes from atrace 60 */ parse(byte[] atraceOutput)61 public void parse(byte[] atraceOutput) { 62 mAtraceOutput = atraceOutput; 63 mAtraceLength = atraceOutput.length; 64 65 removeCrLf(); 66 67 // locate the trace start marker within the first hundred bytes 68 String header = new String(mAtraceOutput, 0, Math.min(100, mAtraceLength)); 69 mSystraceIndex = locateSystraceData(header); 70 71 if (mSystraceIndex < 0) { 72 throw new RuntimeException("Unable to find trace start marker 'TRACE:':\n" + header); 73 } 74 } 75 76 /** Replaces \r\n with \n in {@link #mAtraceOutput}. */ removeCrLf()77 private void removeCrLf() { 78 int dst = 0; 79 for (int src = 0; src < mAtraceLength - 1; src++, dst++) { 80 byte copy; 81 if (mAtraceOutput[src] == '\r' && mAtraceOutput[src + 1] == '\n') { 82 copy = '\n'; 83 src++; 84 } else { 85 copy = mAtraceOutput[src]; 86 } 87 mAtraceOutput[dst] = copy; 88 } 89 90 mAtraceLength = dst; 91 } 92 locateSystraceData(String header)93 private int locateSystraceData(String header) { 94 int index = header.indexOf(TRACE_START); 95 if (index < 0) { 96 return -1; 97 } else { 98 return index + TRACE_START.length(); 99 } 100 } 101 getSystraceHtml()102 public String getSystraceHtml() { 103 if (mSystraceIndex < 0) { 104 return ""; 105 } 106 107 String trace = ""; 108 if (mUncompress) { 109 Inflater decompressor = new Inflater(); 110 decompressor.setInput(mAtraceOutput, mSystraceIndex, mAtraceLength - mSystraceIndex); 111 112 byte[] buf = new byte[4096]; 113 int n; 114 StringBuilder sb = new StringBuilder(1000); 115 try { 116 while ((n = decompressor.inflate(buf)) > 0) { 117 sb.append(new String(buf, 0, n)); 118 } 119 } catch (DataFormatException e) { 120 throw new RuntimeException(e); 121 } 122 decompressor.end(); 123 124 trace = sb.toString(); 125 } else { 126 trace = new String(mAtraceOutput, mSystraceIndex, mAtraceLength - mSystraceIndex); 127 } 128 129 // each line should end with the characters \n\ followed by a newline 130 String html_out = trace.replaceAll("\n", "\\\\n\\\\\n"); 131 String header = String.format(mHtmlPrefix, mCss, mJs, ""); 132 String footer = mHtmlSuffix; 133 return header + html_out + footer; 134 } 135 getJs(File assetsFolder)136 public static String getJs(File assetsFolder) { 137 try { 138 return String.format("<script language=\"javascript\">%s</script>", 139 Files.toString(new File(assetsFolder, "script.js"), Charsets.UTF_8)); 140 } catch (IOException e) { 141 return ""; 142 } 143 } 144 getCss(File assetsFolder)145 public static String getCss(File assetsFolder) { 146 try { 147 return String.format("<style type=\"text/css\">%s</style>", 148 Files.toString(new File(assetsFolder, "style.css"), Charsets.UTF_8)); 149 } catch (IOException e) { 150 return ""; 151 } 152 } 153 getHtmlPrefix(File assetsFolder)154 public static String getHtmlPrefix(File assetsFolder) { 155 return getHtmlTemplate(assetsFolder, "prefix.html"); 156 } 157 getHtmlSuffix(File assetsFolder)158 public static String getHtmlSuffix(File assetsFolder) { 159 return getHtmlTemplate(assetsFolder, "suffix.html"); 160 } 161 getHtmlTemplate(File assetsFolder, String htmlFileName)162 private static String getHtmlTemplate(File assetsFolder, String htmlFileName) { 163 try { 164 return Files.toString(new File(assetsFolder, htmlFileName), Charsets.UTF_8); 165 } catch (IOException e) { 166 return ""; 167 } 168 } 169 } 170