• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 android.util;
18 
19 import java.io.BufferedReader;
20 import java.io.FileReader;
21 import java.io.IOException;
22 import java.io.UnsupportedEncodingException;
23 import java.nio.BufferUnderflowException;
24 import java.nio.ByteBuffer;
25 import java.nio.ByteOrder;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 
31 /**
32  * Access to the system diagnostic event record.  System diagnostic events are
33  * used to record certain system-level events (such as garbage collection,
34  * activity manager state, system watchdogs, and other low level activity),
35  * which may be automatically collected and analyzed during system development.
36  *
37  * <p>This is <b>not</b> the main "logcat" debugging log ({@link android.util.Log})!
38  * These diagnostic events are for system integrators, not application authors.
39  *
40  * <p>Events use integer tag codes corresponding to /system/etc/event-log-tags.
41  * They carry a payload of one or more int, long, or String values.  The
42  * event-log-tags file defines the payload contents for each type code.
43  */
44 public class EventLog {
45     private static final String TAG = "EventLog";
46 
47     private static final String TAGS_FILE = "/system/etc/event-log-tags";
48     private static final String COMMENT_PATTERN = "^\\s*(#.*)?$";
49     private static final String TAG_PATTERN = "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$";
50     private static HashMap<String, Integer> sTagCodes = null;
51     private static HashMap<Integer, String> sTagNames = null;
52 
53     /** A previously logged event read from the logs. */
54     public static final class Event {
55         private final ByteBuffer mBuffer;
56 
57         // Layout of event log entry received from kernel.
58         private static final int LENGTH_OFFSET = 0;
59         private static final int PROCESS_OFFSET = 4;
60         private static final int THREAD_OFFSET = 8;
61         private static final int SECONDS_OFFSET = 12;
62         private static final int NANOSECONDS_OFFSET = 16;
63 
64         private static final int PAYLOAD_START = 20;
65         private static final int TAG_OFFSET = 20;
66         private static final int DATA_START = 24;
67 
68         // Value types
69         private static final byte INT_TYPE    = 0;
70         private static final byte LONG_TYPE   = 1;
71         private static final byte STRING_TYPE = 2;
72         private static final byte LIST_TYPE   = 3;
73 
74         /** @param data containing event, read from the system */
Event(byte[] data)75         /*package*/ Event(byte[] data) {
76             mBuffer = ByteBuffer.wrap(data);
77             mBuffer.order(ByteOrder.nativeOrder());
78         }
79 
80         /** @return the process ID which wrote the log entry */
getProcessId()81         public int getProcessId() {
82             return mBuffer.getInt(PROCESS_OFFSET);
83         }
84 
85         /** @return the thread ID which wrote the log entry */
getThreadId()86         public int getThreadId() {
87             return mBuffer.getInt(THREAD_OFFSET);
88         }
89 
90         /** @return the wall clock time when the entry was written */
getTimeNanos()91         public long getTimeNanos() {
92             return mBuffer.getInt(SECONDS_OFFSET) * 1000000000l
93                     + mBuffer.getInt(NANOSECONDS_OFFSET);
94         }
95 
96         /** @return the type tag code of the entry */
getTag()97         public int getTag() {
98             return mBuffer.getInt(TAG_OFFSET);
99         }
100 
101         /** @return one of Integer, Long, String, null, or Object[] of same. */
getData()102         public synchronized Object getData() {
103             try {
104                 mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
105                 mBuffer.position(DATA_START);  // Just after the tag.
106                 return decodeObject();
107             } catch (IllegalArgumentException e) {
108                 Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
109                 return null;
110             } catch (BufferUnderflowException e) {
111                 Log.wtf(TAG, "Truncated entry payload: tag=" + getTag(), e);
112                 return null;
113             }
114         }
115 
116         /** @return the loggable item at the current position in mBuffer. */
decodeObject()117         private Object decodeObject() {
118             byte type = mBuffer.get();
119             switch (type) {
120             case INT_TYPE:
121                 return (Integer) mBuffer.getInt();
122 
123             case LONG_TYPE:
124                 return (Long) mBuffer.getLong();
125 
126             case STRING_TYPE:
127                 try {
128                     int length = mBuffer.getInt();
129                     int start = mBuffer.position();
130                     mBuffer.position(start + length);
131                     return new String(mBuffer.array(), start, length, "UTF-8");
132                 } catch (UnsupportedEncodingException e) {
133                     Log.wtf(TAG, "UTF-8 is not supported", e);
134                     return null;
135                 }
136 
137             case LIST_TYPE:
138                 int length = mBuffer.get();
139                 if (length < 0) length += 256;  // treat as signed byte
140                 Object[] array = new Object[length];
141                 for (int i = 0; i < length; ++i) array[i] = decodeObject();
142                 return array;
143 
144             default:
145                 throw new IllegalArgumentException("Unknown entry type: " + type);
146             }
147         }
148     }
149 
150     // We assume that the native methods deal with any concurrency issues.
151 
152     /**
153      * Record an event log message.
154      * @param tag The event type tag code
155      * @param value A value to log
156      * @return The number of bytes written
157      */
writeEvent(int tag, int value)158     public static native int writeEvent(int tag, int value);
159 
160     /**
161      * Record an event log message.
162      * @param tag The event type tag code
163      * @param value A value to log
164      * @return The number of bytes written
165      */
writeEvent(int tag, long value)166     public static native int writeEvent(int tag, long value);
167 
168     /**
169      * Record an event log message.
170      * @param tag The event type tag code
171      * @param str A value to log
172      * @return The number of bytes written
173      */
writeEvent(int tag, String str)174     public static native int writeEvent(int tag, String str);
175 
176     /**
177      * Record an event log message.
178      * @param tag The event type tag code
179      * @param list A list of values to log
180      * @return The number of bytes written
181      */
writeEvent(int tag, Object... list)182     public static native int writeEvent(int tag, Object... list);
183 
184     /**
185      * Read events from the log, filtered by type.
186      * @param tags to search for
187      * @param output container to add events into
188      * @throws IOException if something goes wrong reading events
189      */
readEvents(int[] tags, Collection<Event> output)190     public static native void readEvents(int[] tags, Collection<Event> output)
191             throws IOException;
192 
193     /**
194      * Get the name associated with an event type tag code.
195      * @param tag code to look up
196      * @return the name of the tag, or null if no tag has that number
197      */
getTagName(int tag)198     public static String getTagName(int tag) {
199         readTagsFile();
200         return sTagNames.get(tag);
201     }
202 
203     /**
204      * Get the event type tag code associated with an event name.
205      * @param name of event to look up
206      * @return the tag code, or -1 if no tag has that name
207      */
getTagCode(String name)208     public static int getTagCode(String name) {
209         readTagsFile();
210         Integer code = sTagCodes.get(name);
211         return code != null ? code : -1;
212     }
213 
214     /**
215      * Read TAGS_FILE, populating sTagCodes and sTagNames, if not already done.
216      */
readTagsFile()217     private static synchronized void readTagsFile() {
218         if (sTagCodes != null && sTagNames != null) return;
219 
220         sTagCodes = new HashMap<String, Integer>();
221         sTagNames = new HashMap<Integer, String>();
222 
223         Pattern comment = Pattern.compile(COMMENT_PATTERN);
224         Pattern tag = Pattern.compile(TAG_PATTERN);
225         BufferedReader reader = null;
226         String line;
227 
228         try {
229             reader = new BufferedReader(new FileReader(TAGS_FILE), 256);
230             while ((line = reader.readLine()) != null) {
231                 if (comment.matcher(line).matches()) continue;
232 
233                 Matcher m = tag.matcher(line);
234                 if (!m.matches()) {
235                     Log.wtf(TAG, "Bad entry in " + TAGS_FILE + ": " + line);
236                     continue;
237                 }
238 
239                 try {
240                     int num = Integer.parseInt(m.group(1));
241                     String name = m.group(2);
242                     sTagCodes.put(name, num);
243                     sTagNames.put(num, name);
244                 } catch (NumberFormatException e) {
245                     Log.wtf(TAG, "Error in " + TAGS_FILE + ": " + line, e);
246                 }
247             }
248         } catch (IOException e) {
249             Log.wtf(TAG, "Error reading " + TAGS_FILE, e);
250             // Leave the maps existing but unpopulated
251         } finally {
252             try { if (reader != null) reader.close(); } catch (IOException e) {}
253         }
254     }
255 }
256