MetricsReader.java revision f33926abed907faf31093544303ea51723738214
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 */ 16package android.metrics; 17 18import android.annotation.SystemApi; 19import android.util.EventLog; 20import android.util.EventLog.Event; 21import android.util.Log; 22 23import com.android.internal.logging.MetricsLogger; 24 25import java.io.IOException; 26import java.util.ArrayList; 27import java.util.LinkedList; 28import java.util.Queue; 29 30/** 31 * Read platform logs. 32 * @hide 33 */ 34@SystemApi 35public class MetricsReader { 36 private Queue<LogMaker> mEventQueue = new LinkedList<>(); 37 private long mLastEventMs; 38 private long mCheckpointMs; 39 private int[] LOGTAGS = { MetricsLogger.LOGTAG }; 40 41 /** 42 * Read the available logs into a new session. 43 * 44 * The session will contain events starting from the oldest available 45 * log on the system up to the most recent at the time of this call. 46 * 47 * A call to {@link #checkpoint()} will cause the session to contain 48 * only events that occured after that call. 49 * 50 * This call will not return until the system buffer overflows the 51 * specified timestamp. If the specified timestamp is 0, then the 52 * call will return immediately since any logs 1970 have already been 53 * overwritten (n.b. if the underlying system has the capability to 54 * store many decades of system logs, this call may fail in 55 * interesting ways.) 56 * 57 * @param horizonMs block until this timestamp is overwritten, 0 for non-blocking read. 58 */ 59 public void read(long horizonMs) { 60 ArrayList<Event> nativeEvents = new ArrayList<>(); 61 try { 62 EventLog.readEventsOnWrapping(LOGTAGS, horizonMs, nativeEvents); 63 } catch (IOException e) { 64 e.printStackTrace(); 65 } 66 mEventQueue.clear(); 67 for (EventLog.Event event : nativeEvents) { 68 final long eventTimestampMs = event.getTimeNanos() / 1000000; 69 if (eventTimestampMs > mCheckpointMs) { 70 Object data = event.getData(); 71 Object[] objects; 72 if (data instanceof Object[]) { 73 objects = (Object[]) data; 74 } else { 75 // wrap scalar objects 76 objects = new Object[1]; 77 objects[0] = data; 78 } 79 mEventQueue.add(new LogMaker(objects) 80 .setTimestamp(eventTimestampMs)); 81 mLastEventMs = eventTimestampMs; 82 } 83 } 84 } 85 86 /** Cause this session to only contain events that occur after this call. */ 87 public void checkpoint() { 88 // read the log to find the most recent event. 89 read(0L); 90 // any queued event is now too old, so drop them. 91 mEventQueue.clear(); 92 mCheckpointMs = mLastEventMs; 93 } 94 95 /** 96 * Rewind the session to the beginning of time and read all available logs. 97 * 98 * A prior call to {@link #checkpoint()} will cause the reader to ignore 99 * any event with a timestamp before the time of that call. 100 * 101 * The underlying log buffer is live: between calls to {@link #reset()}, older 102 * events may be lost from the beginning of the session, and new events may 103 * appear at the end. 104 */ 105 public void reset() { 106 read(0l); 107 } 108 109 /* Does the current log session have another entry? */ 110 public boolean hasNext() { 111 return !mEventQueue.isEmpty(); 112 } 113 114 /* Return the next entry in the current log session. */ 115 public LogMaker next() { 116 return mEventQueue.poll(); 117 } 118 119} 120