1 /* 2 * Copyright (C) 2017 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 org.chromium.latency.walt; 18 19 import android.content.Context; 20 import android.os.Environment; 21 22 import java.io.File; 23 import java.io.FileOutputStream; 24 import java.io.IOException; 25 import java.io.OutputStreamWriter; 26 import java.text.DecimalFormat; 27 import java.util.ArrayList; 28 29 /** 30 * Used to log events for Android systrace 31 */ 32 class TraceLogger { 33 34 private static final Object LOCK = new Object(); 35 private static TraceLogger instance; 36 37 private ArrayList<TraceEvent> traceEvents; 38 getInstance()39 public static TraceLogger getInstance() { 40 synchronized (LOCK) { 41 if (instance == null) { 42 instance = new TraceLogger(); 43 } 44 return instance; 45 } 46 } 47 TraceLogger()48 private TraceLogger() { 49 traceEvents = new ArrayList<>(); 50 } 51 log(long startTimeMicros, long finishTimeMicros, String title, String description)52 public synchronized void log(long startTimeMicros, long finishTimeMicros, String title, String description) { 53 traceEvents.add(new TraceEvent(startTimeMicros, finishTimeMicros, title, description)); 54 } 55 getLogText()56 public String getLogText() { 57 DecimalFormat df = new DecimalFormat(".000000"); 58 StringBuilder sb = new StringBuilder(); 59 int pid = android.os.Process.myPid(); 60 for (TraceEvent e : traceEvents) { 61 sb.append(String.format( 62 "WALTThread-1234 (%d) [000] ...1 %s: tracing_mark_write: B|%d|%s|description=%s|WALT\n", 63 pid, df.format(e.startTimeMicros / 1e6), pid, e.title, e.description)); 64 sb.append(String.format( 65 "WALTThread-1234 (%d) [000] ...1 %s: tracing_mark_write: E|%d|%s||WALT\n", 66 pid, df.format(e.finishTimeMicros / 1e6), pid, e.title)); 67 } 68 return sb.toString(); 69 } 70 flush(Context context)71 void flush(Context context) { 72 SimpleLogger logger = SimpleLogger.getInstance(context); 73 if (!isExternalStorageWritable()) { 74 logger.log("ERROR: could not write systrace logs to file"); 75 return; 76 } 77 writeSystraceLogs(context); 78 traceEvents.clear(); 79 } 80 writeSystraceLogs(Context context)81 private void writeSystraceLogs(Context context) { 82 File file = new File(context.getExternalFilesDir(null), "trace.txt"); 83 SimpleLogger logger = SimpleLogger.getInstance(context); 84 try { 85 OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file, true)); 86 writer.write(getLogText()); 87 writer.close(); 88 logger.log(String.format("TraceLogger wrote %d events to %s", 89 traceEvents.size(), file.getAbsolutePath())); 90 } catch (IOException e) { 91 logger.log("ERROR: IOException writing to trace.txt"); 92 e.printStackTrace(); 93 } 94 } 95 isExternalStorageWritable()96 private boolean isExternalStorageWritable() { 97 String state = Environment.getExternalStorageState(); 98 return Environment.MEDIA_MOUNTED.equals(state); 99 } 100 101 private class TraceEvent { 102 long startTimeMicros; 103 long finishTimeMicros; 104 String title; 105 String description; TraceEvent(long startTimeMicros, long finishTimeMicros, String title, String description)106 TraceEvent(long startTimeMicros, long finishTimeMicros, String title, String description) { 107 this.startTimeMicros = startTimeMicros; 108 this.finishTimeMicros = finishTimeMicros; 109 this.title = title; 110 this.description = description; 111 } 112 } 113 } 114