1011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi/* 2011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * Copyright (C) 2017 The Android Open Source Project 3011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * 4011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License"); 5011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * you may not use this file except in compliance with the License. 6011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * You may obtain a copy of the License at 7011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * 8011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * http://www.apache.org/licenses/LICENSE-2.0 9011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * 10011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * Unless required by applicable law or agreed to in writing, software 11011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS, 12011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * See the License for the specific language governing permissions and 14011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * limitations under the License. 15011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi */ 16011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 17011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivipackage com.android.server.audio; 18011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 1974a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Triviimport android.util.Log; 2074a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi 21011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Triviimport java.io.PrintWriter; 22011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Triviimport java.text.SimpleDateFormat; 23011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Triviimport java.util.Date; 24011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Triviimport java.util.LinkedList; 25011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 26011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivipublic class AudioEventLogger { 27011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 28011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi // ring buffer of events to log. 29011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi private final LinkedList<Event> mEvents; 30011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 31011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi private final String mTitle; 32011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 33011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi // the maximum number of events to keep in log 34011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi private final int mMemSize; 35011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 36011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi public static abstract class Event { 37011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi // formatter for timestamps 38011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi private final static SimpleDateFormat sFormat = new SimpleDateFormat("MM-dd HH:mm:ss:SSS"); 39011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 40011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi private final long mTimestamp; 41011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 42011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi Event() { 43011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi mTimestamp = System.currentTimeMillis(); 44011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 45011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 46011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi public String toString() { 47011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi return (new StringBuilder(sFormat.format(new Date(mTimestamp)))) 48011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi .append(" ").append(eventToString()).toString(); 49011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 50011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 51011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi /** 520b67b9fad6733492ffab238a5ba12b98a696ef0cJean-Michel Trivi * Causes the string message for the event to appear in the logcat. 5374a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi * Here is an example of how to create a new event (a StringEvent), adding it to the logger 540b67b9fad6733492ffab238a5ba12b98a696ef0cJean-Michel Trivi * (an instance of AudioEventLogger) while also making it show in the logcat: 5574a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi * <pre> 5674a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi * myLogger.log( 5774a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi * (new StringEvent("something for logcat and logger")).printLog(MyClass.TAG) ); 5874a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi * </pre> 5974a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi * @param tag the tag for the android.util.Log.v 6074a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi * @return the same instance of the event 6174a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi */ 6274a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi public Event printLog(String tag) { 630b67b9fad6733492ffab238a5ba12b98a696ef0cJean-Michel Trivi Log.i(tag, eventToString()); 6474a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi return this; 6574a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi } 6674a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi 6774a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi /** 68011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * Convert event to String. 69011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * This method is only called when the logger history is about to the dumped, 70011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * so this method is where expensive String conversions should be made, not when the Event 71011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * subclass is created. 72011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * Timestamp information will be automatically added, do not include it. 73011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * @return a string representation of the event that occurred. 74011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi */ 75011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi abstract public String eventToString(); 76011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 77011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 78011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi public static class StringEvent extends Event { 79011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi private final String mMsg; 80011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 81011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi public StringEvent(String msg) { 82011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi mMsg = msg; 83011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 84011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 85011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi @Override 86011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi public String eventToString() { 87011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi return mMsg; 88011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 89011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 90011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 91011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi /** 92011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * Constructor for logger. 93011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * @param size the maximum number of events to keep in log 94011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi * @param title the string displayed before the recorded log 95011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi */ 96011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi public AudioEventLogger(int size, String title) { 97011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi mEvents = new LinkedList<Event>(); 98011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi mMemSize = size; 99011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi mTitle = title; 100011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 101011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 102011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi public synchronized void log(Event evt) { 103011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi if (mEvents.size() >= mMemSize) { 104011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi mEvents.removeFirst(); 105011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 106011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi mEvents.add(evt); 107011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 108011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi 109011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi public synchronized void dump(PrintWriter pw) { 110011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi pw.println("Audio event log: " + mTitle); 111011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi for (Event evt : mEvents) { 112011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi pw.println(evt.toString()); 113011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 114011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi } 115011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi} 116