19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.util;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnorimport java.io.BufferedReader;
2062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnorimport java.io.FileReader;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
2362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnorimport java.nio.BufferUnderflowException;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.nio.ByteBuffer;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.nio.ByteOrder;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Collection;
2762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnorimport java.util.HashMap;
2862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnorimport java.util.regex.Matcher;
2962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnorimport java.util.regex.Pattern;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
3262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor * Access to the system diagnostic event record.  System diagnostic events are
3362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor * used to record certain system-level events (such as garbage collection,
3462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor * activity manager state, system watchdogs, and other low level activity),
3562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor * which may be automatically collected and analyzed during system development.
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
3762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor * <p>This is <b>not</b> the main "logcat" debugging log ({@link android.util.Log})!
3862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor * These diagnostic events are for system integrators, not application authors.
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
4062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor * <p>Events use integer tag codes corresponding to /system/etc/event-log-tags.
4162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor * They carry a payload of one or more int, long, or String values.  The
4262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor * event-log-tags file defines the payload contents for each type code.
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class EventLog {
45a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson    /** @hide */ public EventLog() {}
46a0f8bc51aff98c2e23e73069e447f63397471a0aJesse Wilson
4762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    private static final String TAG = "EventLog";
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    private static final String TAGS_FILE = "/system/etc/event-log-tags";
5062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    private static final String COMMENT_PATTERN = "^\\s*(#.*)?$";
5162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    private static final String TAG_PATTERN = "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$";
5262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    private static HashMap<String, Integer> sTagCodes = null;
5362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    private static HashMap<Integer, String> sTagNames = null;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    /** A previously logged event read from the logs. */
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final class Event {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final ByteBuffer mBuffer;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
59747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn        // Layout of event log entry received from Android logger.
60747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn        //  see system/core/include/log/logger.h
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int LENGTH_OFFSET = 0;
62747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn        private static final int HEADER_SIZE_OFFSET = 2;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int PROCESS_OFFSET = 4;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int THREAD_OFFSET = 8;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int SECONDS_OFFSET = 12;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int NANOSECONDS_OFFSET = 16;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
68747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn        // Layout for event log v1 format, v2 and v3 use HEADER_SIZE_OFFSET
69747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn        private static final int V1_PAYLOAD_START = 20;
70747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn        private static final int DATA_OFFSET = 4;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        // Value types
7362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        private static final byte INT_TYPE    = 0;
7462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        private static final byte LONG_TYPE   = 1;
7562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        private static final byte STRING_TYPE = 2;
7662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        private static final byte LIST_TYPE   = 3;
7762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** @param data containing event, read from the system */
7962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        /*package*/ Event(byte[] data) {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBuffer = ByteBuffer.wrap(data);
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBuffer.order(ByteOrder.nativeOrder());
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        /** @return the process ID which wrote the log entry */
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getProcessId() {
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mBuffer.getInt(PROCESS_OFFSET);
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        /** @return the thread ID which wrote the log entry */
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getThreadId() {
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mBuffer.getInt(THREAD_OFFSET);
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        /** @return the wall clock time when the entry was written */
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public long getTimeNanos() {
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mBuffer.getInt(SECONDS_OFFSET) * 1000000000l
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + mBuffer.getInt(NANOSECONDS_OFFSET);
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        /** @return the type tag code of the entry */
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getTag() {
102747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn            int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
103747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn            if (offset == 0) {
104747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn                offset = V1_PAYLOAD_START;
105747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn            }
106747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn            return mBuffer.getInt(offset);
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        /** @return one of Integer, Long, String, null, or Object[] of same. */
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized Object getData() {
11162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            try {
112747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn                int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
113747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn                if (offset == 0) {
114747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn                    offset = V1_PAYLOAD_START;
115747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn                }
116747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn                mBuffer.limit(offset + mBuffer.getShort(LENGTH_OFFSET));
117747802f8aa4d373885161724d9c2c61dcd4f8010Mark Salyzyn                mBuffer.position(offset + DATA_OFFSET); // Just after the tag.
11862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                return decodeObject();
11962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            } catch (IllegalArgumentException e) {
12062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
12162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                return null;
12262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            } catch (BufferUnderflowException e) {
12362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                Log.wtf(TAG, "Truncated entry payload: tag=" + getTag(), e);
12462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                return null;
12562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            }
12630636876c079cdce5f856aa2269e2d2f769e8363Jim Miller        }
12730636876c079cdce5f856aa2269e2d2f769e8363Jim Miller
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** @return the loggable item at the current position in mBuffer. */
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Object decodeObject() {
13062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            byte type = mBuffer.get();
13162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            switch (type) {
13262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            case INT_TYPE:
13330636876c079cdce5f856aa2269e2d2f769e8363Jim Miller                return (Integer) mBuffer.getInt();
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            case LONG_TYPE:
13630636876c079cdce5f856aa2269e2d2f769e8363Jim Miller                return (Long) mBuffer.getLong();
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            case STRING_TYPE:
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int length = mBuffer.getInt();
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int start = mBuffer.position();
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mBuffer.position(start + length);
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return new String(mBuffer.array(), start, length, "UTF-8");
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (UnsupportedEncodingException e) {
14562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                    Log.wtf(TAG, "UTF-8 is not supported", e);
14662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                    return null;
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            case LIST_TYPE:
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int length = mBuffer.get();
1516916089e838662b41d902cd9a0d2560b04633ef9Dan Egnor                if (length < 0) length += 256;  // treat as signed byte
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object[] array = new Object[length];
15362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                for (int i = 0; i < length; ++i) array[i] = decodeObject();
15462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                return array;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
15762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                throw new IllegalArgumentException("Unknown entry type: " + type);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // We assume that the native methods deal with any concurrency issues.
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
16562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * Record an event log message.
16662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * @param tag The event type tag code
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param value A value to log
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of bytes written
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static native int writeEvent(int tag, int value);
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
17362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * Record an event log message.
17462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * @param tag The event type tag code
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param value A value to log
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of bytes written
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static native int writeEvent(int tag, long value);
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * Record an event log message.
18262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * @param tag The event type tag code
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param str A value to log
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of bytes written
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static native int writeEvent(int tag, String str);
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * Record an event log message.
19062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * @param tag The event type tag code
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param list A list of values to log
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of bytes written
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    public static native int writeEvent(int tag, Object... list);
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Read events from the log, filtered by type.
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param tags to search for
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param output container to add events into
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws IOException if something goes wrong reading events
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static native void readEvents(int[] tags, Collection<Event> output)
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException;
20495ff2401a9c6f0252aeedfa27ba0a9a5f0d7f55eJim Miller
20595ff2401a9c6f0252aeedfa27ba0a9a5f0d7f55eJim Miller    /**
20662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * Get the name associated with an event type tag code.
20762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * @param tag code to look up
20862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * @return the name of the tag, or null if no tag has that number
20995ff2401a9c6f0252aeedfa27ba0a9a5f0d7f55eJim Miller     */
21062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    public static String getTagName(int tag) {
21162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        readTagsFile();
21262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        return sTagNames.get(tag);
21362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    }
21462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor
21562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    /**
21662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * Get the event type tag code associated with an event name.
21762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * @param name of event to look up
21862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * @return the tag code, or -1 if no tag has that name
21962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     */
22062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    public static int getTagCode(String name) {
22162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        readTagsFile();
22262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        Integer code = sTagCodes.get(name);
22362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        return code != null ? code : -1;
22462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    }
22562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor
22662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    /**
22762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     * Read TAGS_FILE, populating sTagCodes and sTagNames, if not already done.
22862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor     */
22962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    private static synchronized void readTagsFile() {
23062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        if (sTagCodes != null && sTagNames != null) return;
23162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor
23262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        sTagCodes = new HashMap<String, Integer>();
23362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        sTagNames = new HashMap<Integer, String>();
23462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor
23562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        Pattern comment = Pattern.compile(COMMENT_PATTERN);
23662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        Pattern tag = Pattern.compile(TAG_PATTERN);
23762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        BufferedReader reader = null;
23862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        String line;
23962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor
24062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        try {
24162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            reader = new BufferedReader(new FileReader(TAGS_FILE), 256);
24262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            while ((line = reader.readLine()) != null) {
24362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                if (comment.matcher(line).matches()) continue;
24462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor
24562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                Matcher m = tag.matcher(line);
24662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                if (!m.matches()) {
24762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                    Log.wtf(TAG, "Bad entry in " + TAGS_FILE + ": " + line);
24862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                    continue;
24962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                }
25062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor
25162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                try {
25262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                    int num = Integer.parseInt(m.group(1));
25362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                    String name = m.group(2);
25462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                    sTagCodes.put(name, num);
25562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                    sTagNames.put(num, name);
25662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                } catch (NumberFormatException e) {
25762136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                    Log.wtf(TAG, "Error in " + TAGS_FILE + ": " + line, e);
25862136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor                }
25962136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            }
26062136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        } catch (IOException e) {
26162136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            Log.wtf(TAG, "Error reading " + TAGS_FILE, e);
26262136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            // Leave the maps existing but unpopulated
26362136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        } finally {
26462136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor            try { if (reader != null) reader.close(); } catch (IOException e) {}
26562136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor        }
26662136d3e1c1262fc31a1f77f6d6acbd75e5ea81dDan Egnor    }
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
268