com.android.ddmlib.log.EventLogParser Maven / Gradle / Ivy
Show all versions of ddmlib Show documentation
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ddmlib.log;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.Log;
import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.log.EventContainer.EventValueType;
import com.android.ddmlib.log.EventValueDescription.ValueType;
import com.android.ddmlib.log.LogReceiver.LogEntry;
import com.android.ddmlib.utils.ArrayHelper;
import com.google.common.base.Charsets;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Parser for the "event" log.
*/
public final class EventLogParser {
/** Location of the tag map file on the device */
private static final String EVENT_TAG_MAP_FILE = "/system/etc/event-log-tags"; //$NON-NLS-1$
/**
* Event log entry types. These must match up with the declarations in
* java/android/android/util/EventLog.java.
*/
private static final int EVENT_TYPE_INT = 0;
private static final int EVENT_TYPE_LONG = 1;
private static final int EVENT_TYPE_STRING = 2;
private static final int EVENT_TYPE_LIST = 3;
private static final Pattern PATTERN_SIMPLE_TAG = Pattern.compile(
"^(\\d+)\\s+([A-Za-z0-9_]+)\\s*$"); //$NON-NLS-1$
private static final Pattern PATTERN_TAG_WITH_DESC = Pattern.compile(
"^(\\d+)\\s+([A-Za-z0-9_]+)\\s*(.*)\\s*$"); //$NON-NLS-1$
private static final Pattern PATTERN_DESCRIPTION = Pattern.compile(
"\\(([A-Za-z0-9_\\s]+)\\|(\\d+)(\\|\\d+){0,1}\\)"); //$NON-NLS-1$
private static final Pattern TEXT_LOG_LINE = Pattern.compile(
"(\\d\\d)-(\\d\\d)\\s(\\d\\d):(\\d\\d):(\\d\\d).(\\d{3})\\s+I/([a-zA-Z0-9_]+)\\s*\\(\\s*(\\d+)\\):\\s+(.*)"); //$NON-NLS-1$
private final TreeMap mTagMap = new TreeMap();
private final TreeMap mValueDescriptionMap =
new TreeMap();
public EventLogParser() {
}
/**
* Inits the parser for a specific Device.
*
* This methods reads the event-log-tags located on the device to find out
* what tags are being written to the event log and what their format is.
* @param device The device.
* @return true
if success, false
if failure or cancellation.
*/
public boolean init(IDevice device) {
// read the event tag map file on the device.
try {
device.executeShellCommand("cat " + EVENT_TAG_MAP_FILE, //$NON-NLS-1$
new MultiLineReceiver() {
@Override
public void processNewLines(String[] lines) {
for (String line : lines) {
processTagLine(line);
}
}
@Override
public boolean isCancelled() {
return false;
}
});
} catch (Exception e) {
// catch all possible exceptions and return false.
return false;
}
return true;
}
/**
* Inits the parser with the content of a tag file.
* @param tagFileContent the lines of a tag file.
* @return true
if success, false
if failure.
*/
public boolean init(String[] tagFileContent) {
for (String line : tagFileContent) {
processTagLine(line);
}
return true;
}
/**
* Inits the parser with a specified event-log-tags file.
* @param filePath
* @return true
if success, false
if failure.
*/
public boolean init(String filePath) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(filePath));
String line = null;
do {
line = reader.readLine();
if (line != null) {
processTagLine(line);
}
} while (line != null);
return true;
} catch (IOException e) {
return false;
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
// ignore
}
}
}
/**
* Processes a line from the event-log-tags file.
* @param line the line to process
*/
private void processTagLine(String line) {
// ignore empty lines and comment lines
if (!line.isEmpty() && line.charAt(0) != '#') {
Matcher m = PATTERN_TAG_WITH_DESC.matcher(line);
if (m.matches()) {
try {
int value = Integer.parseInt(m.group(1));
String name = m.group(2);
if (name != null && mTagMap.get(value) == null) {
mTagMap.put(value, name);
}
// special case for the GC tag. We ignore what is in the file,
// and take what the custom GcEventContainer class tells us.
// This is due to the event encoding several values on 2 longs.
// @see GcEventContainer
if (value == GcEventContainer.GC_EVENT_TAG) {
mValueDescriptionMap.put(value,
GcEventContainer.getValueDescriptions());
} else {
String description = m.group(3);
if (description != null && !description.isEmpty()) {
EventValueDescription[] desc =
processDescription(description);
if (desc != null) {
mValueDescriptionMap.put(value, desc);
}
}
}
} catch (NumberFormatException e) {
// failed to convert the number into a string. just ignore it.
}
} else {
m = PATTERN_SIMPLE_TAG.matcher(line);
if (m.matches()) {
int value = Integer.parseInt(m.group(1));
String name = m.group(2);
if (name != null && mTagMap.get(value) == null) {
mTagMap.put(value, name);
}
}
}
}
}
private EventValueDescription[] processDescription(String description) {
String[] descriptions = description.split("\\s*,\\s*"); //$NON-NLS-1$
ArrayList list = new ArrayList();
for (String desc : descriptions) {
Matcher m = PATTERN_DESCRIPTION.matcher(desc);
if (m.matches()) {
try {
String name = m.group(1);
String typeString = m.group(2);
int typeValue = Integer.parseInt(typeString);
EventValueType eventValueType = EventValueType.getEventValueType(typeValue);
if (eventValueType == null) {
// just ignore this description if the value is not recognized.
// TODO: log the error.
}
typeString = m.group(3);
if (typeString != null && !typeString.isEmpty()) {
//skip the |
typeString = typeString.substring(1);
typeValue = Integer.parseInt(typeString);
ValueType valueType = ValueType.getValueType(typeValue);
list.add(new EventValueDescription(name, eventValueType, valueType));
} else {
list.add(new EventValueDescription(name, eventValueType));
}
} catch (NumberFormatException nfe) {
// just ignore this description if one number is malformed.
// TODO: log the error.
} catch (InvalidValueTypeException e) {
// just ignore this description if data type and data unit don't match
// TODO: log the error.
}
} else {
Log.e("EventLogParser", //$NON-NLS-1$
String.format("Can't parse %1$s", description)); //$NON-NLS-1$
}
}
if (list.isEmpty()) {
return null;
}
return list.toArray(new EventValueDescription[list.size()]);
}
public EventContainer parse(LogEntry entry) {
if (entry.len < 4) {
return null;
}
int inOffset = 0;
int tagValue = ArrayHelper.swap32bitFromArray(entry.data, inOffset);
inOffset += 4;
String tag = mTagMap.get(tagValue);
if (tag == null) {
Log.e("EventLogParser", String.format("unknown tag number: %1$d", tagValue));
}
ArrayList