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 com.android.server.audio; 18 19 import android.annotation.IntDef; 20 import android.util.Log; 21 22 import java.io.PrintWriter; 23 import java.lang.annotation.Retention; 24 import java.lang.annotation.RetentionPolicy; 25 import java.text.SimpleDateFormat; 26 import java.util.Date; 27 import java.util.LinkedList; 28 29 public class AudioEventLogger { 30 31 // ring buffer of events to log. 32 private final LinkedList<Event> mEvents; 33 34 private final String mTitle; 35 36 // the maximum number of events to keep in log 37 private final int mMemSize; 38 39 public static abstract class Event { 40 // formatter for timestamps 41 private final static SimpleDateFormat sFormat = new SimpleDateFormat("MM-dd HH:mm:ss:SSS"); 42 43 private final long mTimestamp; 44 Event()45 Event() { 46 mTimestamp = System.currentTimeMillis(); 47 } 48 toString()49 public String toString() { 50 return (new StringBuilder(sFormat.format(new Date(mTimestamp)))) 51 .append(" ").append(eventToString()).toString(); 52 } 53 54 /** 55 * Causes the string message for the event to appear in the logcat. 56 * Here is an example of how to create a new event (a StringEvent), adding it to the logger 57 * (an instance of AudioEventLogger) while also making it show in the logcat: 58 * <pre> 59 * myLogger.log( 60 * (new StringEvent("something for logcat and logger")).printLog(MyClass.TAG) ); 61 * </pre> 62 * @param tag the tag for the android.util.Log.v 63 * @return the same instance of the event 64 */ printLog(String tag)65 public Event printLog(String tag) { 66 return printLog(ALOGI, tag); 67 } 68 69 /** @hide */ 70 @IntDef(flag = false, value = { 71 ALOGI, 72 ALOGE, 73 ALOGW, 74 ALOGV } 75 ) 76 @Retention(RetentionPolicy.SOURCE) 77 public @interface LogType {} 78 79 public static final int ALOGI = 0; 80 public static final int ALOGE = 1; 81 public static final int ALOGW = 2; 82 public static final int ALOGV = 3; 83 84 /** 85 * Same as {@link #printLog(String)} with a log type 86 * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV} 87 * @param tag 88 * @return 89 */ printLog(@ogType int type, String tag)90 public Event printLog(@LogType int type, String tag) { 91 switch (type) { 92 case ALOGI: 93 Log.i(tag, eventToString()); 94 break; 95 case ALOGE: 96 Log.e(tag, eventToString()); 97 break; 98 case ALOGW: 99 Log.w(tag, eventToString()); 100 break; 101 case ALOGV: 102 default: 103 Log.v(tag, eventToString()); 104 break; 105 } 106 return this; 107 } 108 109 /** 110 * Convert event to String. 111 * This method is only called when the logger history is about to the dumped, 112 * so this method is where expensive String conversions should be made, not when the Event 113 * subclass is created. 114 * Timestamp information will be automatically added, do not include it. 115 * @return a string representation of the event that occurred. 116 */ eventToString()117 abstract public String eventToString(); 118 } 119 120 public static class StringEvent extends Event { 121 private final String mMsg; 122 StringEvent(String msg)123 public StringEvent(String msg) { 124 mMsg = msg; 125 } 126 127 @Override eventToString()128 public String eventToString() { 129 return mMsg; 130 } 131 } 132 133 /** 134 * Constructor for logger. 135 * @param size the maximum number of events to keep in log 136 * @param title the string displayed before the recorded log 137 */ AudioEventLogger(int size, String title)138 public AudioEventLogger(int size, String title) { 139 mEvents = new LinkedList<Event>(); 140 mMemSize = size; 141 mTitle = title; 142 } 143 log(Event evt)144 public synchronized void log(Event evt) { 145 if (mEvents.size() >= mMemSize) { 146 mEvents.removeFirst(); 147 } 148 mEvents.add(evt); 149 } 150 151 /** 152 * Add a string-based event to the log, and print it to logcat as info. 153 * @param msg the message for the logs 154 * @param tag the logcat tag to use 155 */ loglogi(String msg, String tag)156 public synchronized void loglogi(String msg, String tag) { 157 final Event event = new StringEvent(msg); 158 log(event.printLog(tag)); 159 } 160 161 /** 162 * Same as {@link #loglogi(String, String)} but specifying the logcat type 163 * @param msg the message for the logs 164 * @param logType the type of logcat entry 165 * @param tag the logcat tag to use 166 */ loglog(String msg, @Event.LogType int logType, String tag)167 public synchronized void loglog(String msg, @Event.LogType int logType, String tag) { 168 final Event event = new StringEvent(msg); 169 log(event.printLog(logType, tag)); 170 } 171 dump(PrintWriter pw)172 public synchronized void dump(PrintWriter pw) { 173 pw.println("Audio event log: " + mTitle); 174 for (Event evt : mEvents) { 175 pw.println(evt.toString()); 176 } 177 } 178 } 179