blob: e058df4c15568dc99062a4e75882b205987a37bd [file] [log] [blame]
/*
* Copyright (C) 2019 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.compatibility.common.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/** Contains helper functions and shared constants for crash parsing. */
public class CrashUtils {
public static final long MIN_CRASH_ADDR = 32768;
// Matches the end of a crash
public static final Pattern sEndofCrashPattern =
Pattern.compile(".*DEBUG\\s+:\\s+backtrace:.*");
public static final String DEVICE_PATH = "/data/local/tmp/CrashParserResults/";
public static final String LOCK_FILENAME = "lockFile.loc";
public static final String UPLOAD_REQUEST = "Please upload a result file to stagefright";
public static final Pattern sUploadRequestPattern =
Pattern.compile(".*" + UPLOAD_REQUEST + ".*");
public static final String NEW_TEST_ALERT = "New test starting with name: ";
public static final Pattern sNewTestPattern =
Pattern.compile(".*" + NEW_TEST_ALERT + "(\\w+)\\(.*\\).*");
public static final String SIGNAL = "signal",
NAME = "name",
PID = "pid",
TID = "tid",
FAULT_ADDRESS = "faultaddress";
// Matches the smallest blob that has the appropriate header and footer
private static final Pattern sCrashBlobPattern =
Pattern.compile("DEBUG\\s+:( [*]{3})+.*?DEBUG\\s+:\\s+backtrace:", Pattern.DOTALL);
// Matches process id and name line and captures them
private static final Pattern sPidtidNamePattern =
Pattern.compile("pid: (\\d+), tid: (\\d+), name: ([^\\s]+\\s+)*>>> (.*) <<<");
// Matches fault address and signal type line
private static final Pattern sFaultLinePattern =
Pattern.compile(
"\\w+ \\d+ \\((.*)\\), code -*\\d+ \\(.*\\), fault addr "
+ "(?:0x(\\p{XDigit}+)|-+)");
// Matches the abort message line if it contains CHECK_
private static Pattern sAbortMessageCheckPattern =
Pattern.compile("(?i)Abort message.*CHECK_.*");
/**
* Determines if the given input has a {@link com.android.compatibility.common.util.Crash} that
* should fail an sts test
*
* @param processNames list of applicable process names
* @param checkMinAddr if the minimum fault address should be respected
* @param crashes list of crashes to check
* @return if a crash is serious enough to fail an sts test
*/
public static boolean detectCrash(
String[] processNames, boolean checkMinAddr, JSONArray crashes) {
for (int i = 0; i < crashes.length(); i++) {
try {
JSONObject crash = crashes.getJSONObject(i);
if (!crash.getString(SIGNAL).toLowerCase().matches("sig(segv|bus)")) {
continue;
}
if (checkMinAddr && !crash.isNull(FAULT_ADDRESS)) {
if (crash.getLong(FAULT_ADDRESS) < MIN_CRASH_ADDR) {
continue;
}
}
boolean foundProcess = false;
String name = crash.getString(NAME);
for (String process : processNames) {
if (name.equals(process)) {
foundProcess = true;
break;
}
}
if (!foundProcess) {
continue;
}
return true; // crash detected
} catch (JSONException | NullPointerException e) {
}
}
return false;
}
/** Adds all crashes found in the input as JSONObjects to the given JSONArray */
public static JSONArray addAllCrashes(String input, JSONArray crashes) {
Matcher crashBlobFinder = sCrashBlobPattern.matcher(input);
while (crashBlobFinder.find()) {
String crashStr = crashBlobFinder.group(0);
int tid = 0, pid = 0;
Long faultAddress = null;
String name = null, signal = null;
Matcher pidtidNameMatcher = sPidtidNamePattern.matcher(crashStr);
if (pidtidNameMatcher.find()) {
try {
pid = Integer.parseInt(pidtidNameMatcher.group(1));
} catch (NumberFormatException e) {
}
try {
tid = Integer.parseInt(pidtidNameMatcher.group(2));
} catch (NumberFormatException e) {
}
name = pidtidNameMatcher.group(3).trim();
}
Matcher faultLineMatcher = sFaultLinePattern.matcher(crashStr);
if (faultLineMatcher.find()) {
signal = faultLineMatcher.group(1);
String faultAddrMatch = faultLineMatcher.group(2);
if (faultAddrMatch != null) {
try {
faultAddress = Long.parseLong(faultAddrMatch, 16);
} catch (NumberFormatException e) {
}
}
}
if (!sAbortMessageCheckPattern.matcher(crashStr).find()) {
try {
JSONObject crash = new JSONObject();
crash.put(PID, pid);
crash.put(TID, tid);
crash.put(NAME, name);
crash.put(FAULT_ADDRESS, faultAddress);
crash.put(SIGNAL, signal);
crashes.put(crash);
} catch (JSONException e) {
}
}
}
return crashes;
}
}