diff options
| author | android-build-team Robot <android-build-team-robot@google.com> | 2019-08-15 04:47:14 +0000 |
|---|---|---|
| committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-08-15 04:47:14 +0000 |
| commit | 94a7e58e30f64e95601e04f6caccb1822446cfa7 (patch) | |
| tree | 32c55b354bcf11934cc484d2f0848ee4fbd1d95b | |
| parent | 2e6635e0493f504122a8c059abd3669f41016f10 (diff) | |
| parent | a1c78ee85e6b6f4e2eabe5b9d28d674945890bc6 (diff) | |
| download | platform_test_suite_harness-android10-mainline-a-release.tar.gz platform_test_suite_harness-android10-mainline-a-release.tar.bz2 platform_test_suite_harness-android10-mainline-a-release.zip | |
Snap for 5803298 from a1c78ee85e6b6f4e2eabe5b9d28d674945890bc6 to qt-aml-releaseandroid-mainline-10.0.0_r2android10-mainline-a-release
Change-Id: I146c55ab69fbc3a713e88273513ab0ad5af0efc1
13 files changed, 481 insertions, 72 deletions
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java index 44939f3f..e62c2719 100644 --- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java +++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java @@ -27,6 +27,7 @@ import com.android.compatibility.common.util.IInvocationResult; import com.android.compatibility.common.util.IModuleResult; import com.android.compatibility.common.util.ITestResult; import com.android.compatibility.common.util.InvocationResult; +import com.android.compatibility.common.util.InvocationResult.RunHistory; import com.android.compatibility.common.util.MetricsStore; import com.android.compatibility.common.util.ReportLog; import com.android.compatibility.common.util.ResultHandler; @@ -64,6 +65,7 @@ import com.android.tradefed.util.proto.TfMetricProtoUtil; import com.google.common.annotations.VisibleForTesting; import com.google.common.xml.XmlEscapers; +import com.google.gson.Gson; import org.xmlpull.v1.XmlPullParserException; @@ -75,6 +77,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -97,6 +100,8 @@ public class ResultReporter implements ILogSaverListener, ITestInvocationListene private static final String CTS_PREFIX = "cts:"; private static final String BUILD_INFO = CTS_PREFIX + "build_"; private static final String LATEST_LINK_NAME = "latest"; + /** Used to get run history from the test result of last run. */ + private static final String RUN_HISTORY_KEY = "run_history"; public static final String BUILD_BRAND = "build_brand"; public static final String BUILD_DEVICE = "build_device"; @@ -533,6 +538,15 @@ public class ResultReporter implements ILogSaverListener, ITestInvocationListene } } + /** + * Returns whether a report creation should be skipped. + */ + protected boolean shouldSkipReportCreation() { + // This value is always false here for backwards compatibility. + // Extended classes have the option to override this. + return false; + } + private void finalizeResults() { if (mFingerprintFailure) { CLog.w("Failed the fingerprint check. Skip result reporting."); @@ -565,6 +579,25 @@ public class ResultReporter implements ILogSaverListener, ITestInvocationListene String moduleProgress = String.format("%d of %d", mResult.getModuleCompleteCount(), mResult.getModules().size()); + // Get run history from the test result of last run and add the run history of the current + // run to it. + // TODO(b/137973382): avoid casting by move the method to interface level. + Collection<RunHistory> runHistories = ((InvocationResult) mResult).getRunHistories(); + String runHistoryJSON = mResult.getInvocationInfo().get(RUN_HISTORY_KEY); + Gson gson = new Gson(); + if (runHistoryJSON != null) { + RunHistory[] runHistoryArray = gson.fromJson(runHistoryJSON, RunHistory[].class); + Collections.addAll(runHistories, runHistoryArray); + } + RunHistory newRun = new RunHistory(); + newRun.startTime = mResult.getStartTime(); + newRun.endTime = newRun.startTime + mElapsedTime; + runHistories.add(newRun); + mResult.addInvocationInfo(RUN_HISTORY_KEY, gson.toJson(runHistories)); + + if (shouldSkipReportCreation()) { + return; + } try { // Zip the full test results directory. diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopier.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopier.java index 87a667b4..d0c70436 100644 --- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopier.java +++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopier.java @@ -42,6 +42,9 @@ public class PreviousSessionFileCopier implements ITestInvocationListener { ChecksumReporter.NAME, ChecksumReporter.PREV_NAME, ResultHandler.FAILURE_REPORT_NAME, + CertificationSuiteResultReporter.FAILURE_REPORT_NAME, + CertificationSuiteResultReporter.SUMMARY_FILE, + CertificationChecksumHelper.NAME, "diffs"); private CompatibilityBuildHelper mBuildHelper; diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BuildFingerPrintPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BuildFingerPrintPreparer.java index a96b76a3..30e303b0 100644 --- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BuildFingerPrintPreparer.java +++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BuildFingerPrintPreparer.java @@ -54,17 +54,22 @@ public final class BuildFingerPrintPreparer extends BaseTargetPreparer { if (!compare.equals(currentBuildFingerprint)) { throw new TargetSetupError( String.format( - "Device build fingerprint must match %s. Found '%s' instead.", + "Device build fingerprint must match '%s'. Found '%s' instead.", compare, currentBuildFingerprint), device.getDeviceDescriptor()); } if (mExpectedVendorFingerprint != null) { String currentBuildVendorFingerprint = device.getProperty(mVendorFingerprintProperty); + // Replace by empty string if null to do a proper comparison. + if (currentBuildVendorFingerprint == null) { + currentBuildVendorFingerprint = ""; + } if (!mExpectedVendorFingerprint.equals(currentBuildVendorFingerprint)) { throw new TargetSetupError( String.format( - "Device vendor build fingerprint must match %s - found %s instead.", + "Device vendor build fingerprint must match '%s'. Found '%s' " + + "instead.", mExpectedVendorFingerprint, currentBuildVendorFingerprint), device.getDeviceDescriptor()); } diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java index 48709fc3..d59f0b6b 100644 --- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java +++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java @@ -386,7 +386,7 @@ public class BusinessLogicPreparer implements IAbiReceiver, IInvocationContextRe extendedDeviceInfo .add(String.format("%s:%s:%s", fileAndKey[0], fileAndKey[1], value)); } - }catch(JSONException | IOException e){ + }catch(JSONException | IOException | RuntimeException e){ CLog.e("Failed to read or parse Extended DeviceInfo JSON file: %s. Error: %s", ediFile.getAbsolutePath(), e); return new ArrayList<>(); diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java index a179978e..82c4d8fe 100644 --- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java +++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java @@ -549,4 +549,75 @@ public class ResultReporterTest extends TestCase { TestStatus.PASS, result1.getResultStatus()); } + + /** Ensure that the run history of the current run is added to previous run history. */ + public void testRetryWithRunHistory() throws Exception { + mReporter.invocationStarted(mContext); + + // Set up IInvocationResult with existing results from previous session + mReporter.testRunStarted(ID, 2); + IInvocationResult invocationResult = mReporter.getResult(); + IModuleResult moduleResult = invocationResult.getOrCreateModule(ID); + ICaseResult caseResult = moduleResult.getOrCreateResult(CLASS); + ITestResult testResult1 = caseResult.getOrCreateResult(METHOD_1); + testResult1.setResultStatus(TestStatus.PASS); + testResult1.setRetry(true); + ITestResult testResult2 = caseResult.getOrCreateResult(METHOD_2); + testResult2.setResultStatus(TestStatus.FAIL); + testResult2.setStackTrace(STACK_TRACE); + testResult2.setRetry(true); + // Set up IInvocationResult with the run history of previous runs. + invocationResult.addInvocationInfo( + "run_history", "[{\"startTime\":1,\"endTime\":2},{\"startTime\":3,\"endTime\":4}]"); + + // Flip results for the current session + TestDescription test1 = new TestDescription(CLASS, METHOD_1); + mReporter.testStarted(test1); + mReporter.testFailed(test1, STACK_TRACE); + mReporter.testEnded(test1, new HashMap<String, Metric>()); + TestDescription test2 = new TestDescription(CLASS, METHOD_2); + mReporter.testStarted(test2); + mReporter.testEnded(test2, new HashMap<String, Metric>()); + + mReporter.testRunEnded(10, new HashMap<String, Metric>()); + mReporter.invocationEnded(10); + + // Verification that results have been overwritten. + IInvocationResult result = mReporter.getResult(); + assertEquals("Expected 1 pass", 1, result.countResults(TestStatus.PASS)); + assertEquals("Expected 1 failure", 1, result.countResults(TestStatus.FAIL)); + List<IModuleResult> modules = result.getModules(); + assertEquals("Expected 1 module", 1, modules.size()); + IModuleResult module = modules.get(0); + List<ICaseResult> cases = module.getResults(); + assertEquals("Expected 1 test case", 1, cases.size()); + ICaseResult case1 = cases.get(0); + List<ITestResult> testResults = case1.getResults(); + assertEquals("Expected 2 tests", 2, testResults.size()); + + long startTime = mReporter.getResult().getStartTime(); + String expectedRunHistory = + String.format( + "[{\"startTime\":1,\"endTime\":2}," + + "{\"startTime\":3,\"endTime\":4},{\"startTime\":%d,\"endTime\":%d}]", + startTime, startTime + 10); + assertEquals(expectedRunHistory, invocationResult.getInvocationInfo().get("run_history")); + + // Test 1 details + ITestResult finalTestResult1 = case1.getResult(METHOD_1); + assertNotNull(String.format("Expected result for %s", TEST_1), finalTestResult1); + assertEquals( + String.format("Expected fail for %s", TEST_1), + TestStatus.FAIL, + finalTestResult1.getResultStatus()); + assertEquals(finalTestResult1.getStackTrace(), STACK_TRACE); + + // Test 2 details + ITestResult finalTestResult2 = case1.getResult(METHOD_2); + assertNotNull(String.format("Expected result for %s", TEST_2), finalTestResult2); + assertEquals( + String.format("Expected pass for %s", TEST_2), + TestStatus.PASS, + finalTestResult2.getResultStatus()); + } } diff --git a/common/util/src/com/android/compatibility/common/util/CrashUtils.java b/common/util/src/com/android/compatibility/common/util/CrashUtils.java index 08375ad3..430fafb9 100644 --- a/common/util/src/com/android/compatibility/common/util/CrashUtils.java +++ b/common/util/src/com/android/compatibility/common/util/CrashUtils.java @@ -16,8 +16,10 @@ package com.android.compatibility.common.util; +import java.io.File; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.math.BigInteger; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -25,7 +27,7 @@ import org.json.JSONObject; /** Contains helper functions and shared constants for crash parsing. */ public class CrashUtils { // used to only detect actual addresses instead of nullptr and other unlikely values - public static final long MIN_CRASH_ADDR = 0x8000; + public static final BigInteger MIN_CRASH_ADDR = new BigInteger("8000", 16); // Matches the end of a crash public static final Pattern sEndofCrashPattern = Pattern.compile("DEBUG\\s+?:\\s+?backtrace:"); @@ -37,11 +39,12 @@ public class CrashUtils { 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"; + public static final String SIGNAL = "signal"; + public static final String NAME = "name"; + public static final String PROCESS = "process"; + public static final String PID = "pid"; + public static final String TID = "tid"; + public static final String 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); @@ -58,47 +61,87 @@ public class CrashUtils { Pattern.compile("(?i)Abort message.*?CHECK_"); /** + * returns true if the signal is a segmentation fault or bus error. + */ + public static boolean isSecuritySignal(JSONObject crash) throws JSONException { + return crash.getString(SIGNAL).toLowerCase().matches("sig(segv|bus)"); + } + + /** + * returns the filename of the process. + * e.g. "/system/bin/mediaserver" returns "mediaserver" + */ + public static String getProcessFileName(JSONObject crash) throws JSONException { + return new File(crash.getString(PROCESS)).getName(); + } + + /** * 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 processPatterns list of patterns that match 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) { + public static boolean securityCrashDetected( + JSONArray crashes, boolean checkMinAddr, Pattern... processPatterns) { + return matchSecurityCrashes(crashes, checkMinAddr, processPatterns).length() > 0; + } + + public static BigInteger getBigInteger(JSONObject source, String name) throws JSONException { + if (source.isNull(name)) { + return null; + } + String intString = source.getString(name); + BigInteger value = null; + try { + value = new BigInteger(intString, 16); + } catch (NumberFormatException e) {} + return value; + } + + /** + * Determines which given inputs have a {@link com.android.compatibility.common.util.Crash} that + * should fail an sts test + * + * @param processPatterns list of patterns that match applicable process names + * @param checkMinAddr if the minimum fault address should be respected + * @param crashes list of crashes to check + * @return the list of crashes serious enough to fail an sts test + */ + public static JSONArray matchSecurityCrashes( + JSONArray crashes, boolean checkMinAddr, Pattern... processPatterns) { + JSONArray securityCrashes = new JSONArray(); for (int i = 0; i < crashes.length(); i++) { try { JSONObject crash = crashes.getJSONObject(i); - if (!crash.getString(SIGNAL).toLowerCase().matches("sig(segv|bus)")) { + if (!matchesAny(getProcessFileName(crash), processPatterns)) { 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 (!isSecuritySignal(crash)) { + continue; } - - if (!foundProcess) { + BigInteger faultAddress = getBigInteger(crash, FAULT_ADDRESS); + if (checkMinAddr && faultAddress != null + && faultAddress.compareTo(MIN_CRASH_ADDR) < 0) { continue; } + securityCrashes.put(crash); + } catch (JSONException | NullPointerException e) {} + } + return securityCrashes; + } - return true; // crash detected - } catch (JSONException | NullPointerException e) { + /** + * returns true if the input matches any of the patterns. + */ + private static boolean matchesAny(String input, Pattern... patterns) { + for (Pattern p : patterns) { + if (p.matcher(input).matches()) { + return true; } } - return false; } @@ -107,21 +150,23 @@ public class CrashUtils { 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; + int tid = 0; + int pid = 0; + BigInteger faultAddress = null; + String name = null; + String process = null; + String signal = null; Matcher pidtidNameMatcher = sPidtidNamePattern.matcher(crashStr); if (pidtidNameMatcher.find()) { try { pid = Integer.parseInt(pidtidNameMatcher.group(1)); - } catch (NumberFormatException e) { - } + } catch (NumberFormatException e) {} try { tid = Integer.parseInt(pidtidNameMatcher.group(2)); - } catch (NumberFormatException e) { - } + } catch (NumberFormatException e) {} name = pidtidNameMatcher.group(3).trim(); + process = pidtidNameMatcher.group(4).trim(); } Matcher faultLineMatcher = sFaultLinePattern.matcher(crashStr); @@ -130,9 +175,8 @@ public class CrashUtils { String faultAddrMatch = faultLineMatcher.group(2); if (faultAddrMatch != null) { try { - faultAddress = Long.parseLong(faultAddrMatch, 16); - } catch (NumberFormatException e) { - } + faultAddress = new BigInteger(faultAddrMatch, 16); + } catch (NumberFormatException e) {} } } if (!sAbortMessageCheckPattern.matcher(crashStr).find()) { @@ -141,12 +185,12 @@ public class CrashUtils { crash.put(PID, pid); crash.put(TID, tid); crash.put(NAME, name); - crash.put(FAULT_ADDRESS, faultAddress); + crash.put(PROCESS, process); + crash.put(FAULT_ADDRESS, + faultAddress == null ? null : faultAddress.toString(16)); crash.put(SIGNAL, signal); crashes.put(crash); - } catch (JSONException e) { - - } + } catch (JSONException e) {} } } return crashes; diff --git a/common/util/src/com/android/compatibility/common/util/InvocationResult.java b/common/util/src/com/android/compatibility/common/util/InvocationResult.java index 45780a99..969e188f 100644 --- a/common/util/src/com/android/compatibility/common/util/InvocationResult.java +++ b/common/util/src/com/android/compatibility/common/util/InvocationResult.java @@ -17,6 +17,7 @@ package com.android.compatibility.common.util; import java.io.File; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -30,6 +31,13 @@ import java.util.Set; */ public class InvocationResult implements IInvocationResult { + /** Helper object for JSON conversion. */ + public static final class RunHistory { + public long startTime; + public long endTime; + } + + private Collection<RunHistory> mRunHistories = new ArrayList<>(); private long mTimestamp; private Map<String, IModuleResult> mModuleResults = new LinkedHashMap<>(); private Map<String, String> mInvocationInfo = new HashMap<>(); @@ -40,6 +48,11 @@ public class InvocationResult implements IInvocationResult { private RetryChecksumStatus mRetryChecksumStatus = RetryChecksumStatus.NotRetry; private File mRetryDirectory = null; + /** @return a collection of the run history of previous runs. */ + public Collection<RunHistory> getRunHistories() { + return mRunHistories; + } + /** * {@inheritDoc} */ diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java index 1be36242..53f73d3a 100644 --- a/common/util/src/com/android/compatibility/common/util/ResultHandler.java +++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java @@ -37,6 +37,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; @@ -104,6 +105,9 @@ public class ResultHandler { private static final String RESULT_ATTR = "result"; private static final String RESULT_TAG = "Result"; private static final String RUNTIME_ATTR = "runtime"; + private static final String RUN_HISTORY_ATTR = "run_history"; + private static final String RUN_HISTORY_TAG = "RunHistory"; + private static final String RUN_TAG = "Run"; private static final String SCREENSHOT_TAG = "Screenshot"; private static final String SKIPPED_ATTR = "skipped"; private static final String STACK_TAG = "StackTrace"; @@ -198,6 +202,10 @@ public class ResultHandler { invocation.addInvocationInfo(BUILD_ID, parser.getAttributeValue(NS, BUILD_ID)); invocation.addInvocationInfo(BUILD_PRODUCT, parser.getAttributeValue(NS, BUILD_PRODUCT)); + String runHistoryValue = parser.getAttributeValue(NS, RUN_HISTORY_ATTR); + if (runHistoryValue != null) { + invocation.addInvocationInfo(RUN_HISTORY_ATTR, runHistoryValue); + } // The build fingerprint needs to reflect the true fingerprint of the device under test, // ignoring potential overrides made by test suites (namely STS) for APFE build @@ -212,7 +220,19 @@ public class ResultHandler { // --skip-device-info flag parser.nextTag(); parser.require(XmlPullParser.END_TAG, NS, BUILD_TAG); + + // Parse RunHistory tag. parser.nextTag(); + boolean hasRunHistoryTag = true; + try { + parser.require(parser.START_TAG, NS, RUN_HISTORY_TAG); + } catch (XmlPullParserException e) { + hasRunHistoryTag = false; + } + if (hasRunHistoryTag) { + parseRunHistory(parser); + } + parser.require(XmlPullParser.START_TAG, NS, SUMMARY_TAG); parser.nextTag(); parser.require(XmlPullParser.END_TAG, NS, SUMMARY_TAG); @@ -308,6 +328,18 @@ public class ResultHandler { } } + /** Parse and replay all run history information. */ + private static void parseRunHistory(XmlPullParser parser) + throws IOException, XmlPullParserException { + while (parser.nextTag() == XmlPullParser.START_TAG) { + parser.require(XmlPullParser.START_TAG, NS, RUN_TAG); + parser.nextTag(); + parser.require(XmlPullParser.END_TAG, NS, RUN_TAG); + } + parser.require(XmlPullParser.END_TAG, NS, RUN_HISTORY_TAG); + parser.nextTag(); + } + /** * @param result * @param resultDir @@ -392,6 +424,21 @@ public class ResultHandler { } serializer.endTag(NS, BUILD_TAG); + // Run history - this contains a list of start and end times of previous runs. More + // information may be added in the future. + Collection<InvocationResult.RunHistory> runHistories = + ((InvocationResult) result).getRunHistories(); + if (!runHistories.isEmpty()) { + serializer.startTag(NS, RUN_HISTORY_TAG); + for (InvocationResult.RunHistory runHistory : runHistories) { + serializer.startTag(NS, RUN_TAG); + serializer.attribute(NS, START_TIME_ATTR, String.valueOf(runHistory.startTime)); + serializer.attribute(NS, END_TIME_ATTR, String.valueOf(runHistory.endTime)); + serializer.endTag(NS, RUN_TAG); + } + serializer.endTag(NS, RUN_HISTORY_TAG); + } + // Summary serializer.startTag(NS, SUMMARY_TAG); serializer.attribute(NS, PASS_ATTR, Integer.toString(passed)); diff --git a/common/util/src/com/android/compatibility/common/util/ResultUnit.java b/common/util/src/com/android/compatibility/common/util/ResultUnit.java index 31aecbbe..131ba8f1 100644 --- a/common/util/src/com/android/compatibility/common/util/ResultUnit.java +++ b/common/util/src/com/android/compatibility/common/util/ResultUnit.java @@ -39,7 +39,9 @@ public enum ResultUnit { /** unit for benchmarking with generic score. */ SCORE, /** radian */ - RADIAN; + RADIAN, + /** Audio or Video frames count, dropped, repeated, etc... */ + FRAMES; /** * @return a string to be used in the report. diff --git a/common/util/tests/assets/logcat.txt b/common/util/tests/assets/logcat.txt index ad778c76..b9d10d05 100644 --- a/common/util/tests/assets/logcat.txt +++ b/common/util/tests/assets/logcat.txt @@ -271,4 +271,66 @@ 11-25 19:47:35.597 940 940 F DEBUG : #24 pc 0003fa3b /system/lib/libc.so (_ZL15__pthread_startPv+30) 11-25 19:47:35.597 940 940 F DEBUG : #25 pc 0001a085 /system/lib/libc.so (__start_thread+6) 11-25 19:47:35.837 940 940 F DEBUG : -11-25 19:47:35.837 940 940 F DEBUG : Tombstone written to: /data/tombstones/tombstone_01
\ No newline at end of file +11-25 19:47:35.837 940 940 F DEBUG : Tombstone written to: /data/tombstones/tombstone_01 +--------- beginning of crash +09-03 17:48:05.627 11071 11189 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0xe9380000 in tid 11189 (synthetic_thread) +09-03 17:48:05.707 359 359 W : debuggerd: handling request: pid=11071 uid=1041 gid=1005 tid=11189 +09-03 17:48:05.796 7072 7072 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** +09-03 17:48:05.796 7072 7072 F DEBUG : Build fingerprint: 'google/angler/angler:7.1.1/N4F26T/3687331:userdebug/dev-keys' +09-03 17:48:05.796 7072 7072 F DEBUG : Revision: '0' +09-03 17:48:05.796 7072 7072 F DEBUG : ABI: 'arm' +09-03 17:48:05.796 7072 7072 F DEBUG : pid: 11071, tid: 11189, name: synthetic_thread >>> synthetic_process_0 <<< +09-03 17:48:05.797 7072 7072 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xe9380000 +09-03 17:48:05.797 7072 7072 F DEBUG : r0 e9e7a240 r1 e9380000 r2 00000170 r3 00000000 +09-03 17:48:05.797 7072 7072 F DEBUG : r4 00000002 r5 00000000 r6 ec1e1f25 r7 eb6f8000 +09-03 17:48:05.797 7072 7072 F DEBUG : r8 00000000 r9 eb105204 sl 00000000 fp 000003c0 +09-03 17:48:05.797 7072 7072 F DEBUG : ip ebd3df18 sp eaf80688 lr ec1e1f41 pc ebd38dd6 cpsr 20000030 +09-03 17:48:05.805 7072 7072 F DEBUG : +09-03 17:48:05.805 7072 7072 F DEBUG : backtrace: +09-03 17:48:05.806 7072 7072 F DEBUG : #00 pc 00002dd6 /system/lib/libaudioutils.so (memcpy_to_float_from_i16+5) +09-03 17:48:05.806 7072 7072 F DEBUG : #01 pc 00040f3d /system/lib/libaudioflinger.so +09-03 17:48:05.806 7072 7072 F DEBUG : #02 pc 00040799 /system/lib/libaudioflinger.so +09-03 17:48:05.806 7072 7072 F DEBUG : #03 pc 00011178 /system/lib/libaudioflinger.so +09-03 17:48:05.806 7072 7072 F DEBUG : #04 pc 0003180b /system/lib/libaudioflinger.so +09-03 17:48:05.806 7072 7072 F DEBUG : #05 pc 0002fe57 /system/lib/libaudioflinger.so +09-03 17:48:05.806 7072 7072 F DEBUG : #06 pc 0000e345 /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+140) +09-03 17:48:05.806 7072 7072 F DEBUG : #07 pc 000470b3 /system/lib/libc.so (_ZL15__pthread_startPv+22) +09-03 17:48:05.806 7072 7072 F DEBUG : #08 pc 00019e3d /system/lib/libc.so (__start_thread+6) +09-03 17:48:05.967 11272 11568 W NativeCrashListener: Couldn't find ProcessRecord for pid 11071 +09-03 17:48:05.969 359 359 W : debuggerd: resuming target 11071 +09-03 17:48:05.981 11272 11307 I BootReceiver: Copying /data/tombstones/tombstone_01 to DropBox (SYSTEM_TOMBSTONE) +09-03 17:48:06.067 394 394 I ServiceManager: service 'media.sound_trigger_hw' died +06-15 19:57:33.607 12736 12761 D PermissionCache: checking android.permission.MODIFY_AUDIO_SETTINGS for uid=10197 => granted (698 us) +--------- beginning of crash +06-15 19:57:33.607 12736 12761 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 12761 (synthetic_thread) +06-15 19:57:33.608 379 379 W : debuggerd: handling request: pid=12736 uid=1041 gid=1005 tid=12761 +06-15 19:57:33.670 26192 26192 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** +06-15 19:57:33.670 26192 26192 F DEBUG : Build fingerprint: 'google/bullhead/bullhead:7.1.2/N2G48C/4104010:userdebug/dev-keys' +06-15 19:57:33.670 26192 26192 F DEBUG : Revision: 'rev_1.0' +06-15 19:57:33.670 26192 26192 F DEBUG : ABI: 'arm' +06-15 19:57:33.670 26192 26192 F DEBUG : pid: 12736, tid: 12761, name: synthetic_thread >>> synthetic_process_1 <<< +06-15 19:57:33.670 26192 26192 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 +06-15 19:57:33.670 26192 26192 F DEBUG : r0 00000000 r1 00000000 r2 0000005f r3 00000000 +06-15 19:57:33.670 26192 26192 F DEBUG : r4 ffffffff r5 00000000 r6 f14f9000 r7 00000001 +06-15 19:57:33.670 26192 26192 F DEBUG : r8 00000004 r9 f3353114 sl f3313900 fp 00000000 +06-15 19:57:33.670 26192 26192 F DEBUG : ip f3bd4d88 sp f127d9c8 lr f3b9cbc5 pc f3b65af4 cpsr 60000030 +06-15 19:57:33.676 26192 26192 F DEBUG : +06-15 19:57:33.676 26192 26192 F DEBUG : backtrace: +06-15 19:57:33.677 26192 26192 F DEBUG : #00 pc 00018af4 /system/lib/libc.so (strlen+71) +06-15 19:57:33.677 26192 26192 F DEBUG : #01 pc 0004fbc1 /system/lib/libc.so (__strlen_chk+4) +06-15 19:57:33.677 26192 26192 F DEBUG : #02 pc 0000c599 /system/lib/libutils.so (_ZN7android7String8C2EPKc+12) +06-15 19:57:33.677 26192 26192 F DEBUG : #03 pc 0002fdbf /system/lib/libaudiopolicymanagerdefault.so (_ZNK7android18HwModuleCollection19getDeviceDescriptorEjPKcS2_b+458) +06-15 19:57:33.677 26192 26192 F DEBUG : #04 pc 0001de47 /system/lib/libaudiopolicymanagerdefault.so (_ZN7android18AudioPolicyManager27setDeviceConnectionStateIntEj24audio_policy_dev_state_tPKcS3_+178) +06-15 19:57:33.677 26192 26192 F DEBUG : #05 pc 0000a009 /system/lib/libaudiopolicyservice.so +06-15 19:57:33.677 26192 26192 F DEBUG : #06 pc 000a01a5 /system/lib/libmedia.so (_ZN7android20BnAudioPolicyService10onTransactEjRKNS_6ParcelEPS1_j+1256) +06-15 19:57:33.677 26192 26192 F DEBUG : #07 pc 000359c3 /system/lib/libbinder.so (_ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j+70) +06-15 19:57:33.677 26192 26192 F DEBUG : #08 pc 0003d1bb /system/lib/libbinder.so (_ZN7android14IPCThreadState14executeCommandEi+702) +06-15 19:57:33.677 26192 26192 F DEBUG : #09 pc 0003ce07 /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+114) +06-15 19:57:33.677 26192 26192 F DEBUG : #10 pc 0003d31b /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+46) +06-15 19:57:33.678 26192 26192 F DEBUG : #11 pc 0004f8c5 /system/lib/libbinder.so +06-15 19:57:33.678 26192 26192 F DEBUG : #12 pc 0000e345 /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+140) +06-15 19:57:33.678 26192 26192 F DEBUG : #13 pc 000470b3 /system/lib/libc.so (_ZL15__pthread_startPv+22) +06-15 19:57:33.678 26192 26192 F DEBUG : #14 pc 00019e3d /system/lib/libc.so (__start_thread+6) +06-15 19:57:33.839 934 2991 W NativeCrashListener: Couldn't find ProcessRecord for pid 12736 +06-15 19:57:33.846 934 952 I BootReceiver: Copying /data/tombstones/tombstone_01 to DropBox (SYSTEM_TOMBSTONE) + diff --git a/common/util/tests/src/com/android/compatibility/common/util/CrashUtilsTest.java b/common/util/tests/src/com/android/compatibility/common/util/CrashUtilsTest.java index 94f472e6..2138b7b3 100644 --- a/common/util/tests/src/com/android/compatibility/common/util/CrashUtilsTest.java +++ b/common/util/tests/src/com/android/compatibility/common/util/CrashUtilsTest.java @@ -27,6 +27,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.util.regex.Pattern; /** Unit tests for {@link CrashUtils}. */ @RunWith(JUnit4.class) @@ -52,67 +53,89 @@ public class CrashUtilsTest { @Test public void testGetAllCrashes() throws Exception { JSONArray expectedResults = new JSONArray(); - expectedResults.put(createCrashJson(11071, 11189, "AudioOut_D", 3912761344L, "SIGSEGV")); - expectedResults.put(createCrashJson(12736, 12761, "Binder:12736_2", 0L, "SIGSEGV")); - expectedResults.put(createCrashJson(26201, 26227, "Binder:26201_3", 0L, "SIGSEGV")); - expectedResults.put(createCrashJson(26246, 26282, "Binder:26246_5", 0L, "SIGSEGV")); - expectedResults.put(createCrashJson(245, 245, "installd", null, "SIGABRT")); - expectedResults.put(createCrashJson(6371, 8072, "media.codec", 3976200192L, "SIGSEGV")); - expectedResults.put(createCrashJson(8373, 8414, "loo", null, "SIGABRT")); + expectedResults.put(createCrashJson( + 11071, 11189, "AudioOut_D", "/system/bin/audioserver", "e9380000", "SIGSEGV")); + expectedResults.put(createCrashJson( + 12736, 12761, "Binder:12736_2", "/system/bin/audioserver", "0", "SIGSEGV")); + expectedResults.put(createCrashJson( + 26201, 26227, "Binder:26201_3", "/system/bin/audioserver", "0", "SIGSEGV")); + expectedResults.put(createCrashJson( + 26246, 26282, "Binder:26246_5", "/system/bin/audioserver", "0", "SIGSEGV")); + expectedResults.put(createCrashJson( + 245, 245, "installd", "/system/bin/installd", null, "SIGABRT")); + expectedResults.put(createCrashJson( + 6371, 8072, "media.codec", "omx@1.0-service", "ed000000", "SIGSEGV")); + expectedResults.put(createCrashJson( + 8373, 8414, "loo", "com.android.bluetooth", null, "SIGABRT")); + expectedResults.put(createCrashJson( + 11071, 11189, "synthetic_thread", "synthetic_process_0", "e9380000", "SIGSEGV")); + expectedResults.put(createCrashJson( + 12736, 12761, "synthetic_thread", "synthetic_process_1", "0", "SIGSEGV")); Assert.assertEquals(mCrashes.toString(), expectedResults.toString()); } public JSONObject createCrashJson( - int pid, int tid, String name, Long faultaddress, String signal) { + int pid, int tid, String name, String process, String faultaddress, String signal) { JSONObject json = new JSONObject(); try { json.put(CrashUtils.PID, pid); json.put(CrashUtils.TID, tid); json.put(CrashUtils.NAME, name); + json.put(CrashUtils.PROCESS, process); json.put(CrashUtils.FAULT_ADDRESS, faultaddress); json.put(CrashUtils.SIGNAL, signal); - } catch (JSONException e) { - - } + } catch (JSONException e) {} return json; } @Test public void testValidCrash() throws Exception { - Assert.assertTrue(CrashUtils.detectCrash(new String[] {"AudioOut_D"}, true, mCrashes)); + Assert.assertTrue(CrashUtils.securityCrashDetected(mCrashes, true, + Pattern.compile("synthetic_process_0"))); } @Test public void testMissingName() throws Exception { - Assert.assertFalse(CrashUtils.detectCrash(new String[] {""}, true, mCrashes)); + Assert.assertFalse(CrashUtils.securityCrashDetected(mCrashes, true, + Pattern.compile(""))); } @Test public void testSIGABRT() throws Exception { - Assert.assertFalse(CrashUtils.detectCrash(new String[] {"installd"}, true, mCrashes)); + Assert.assertFalse(CrashUtils.securityCrashDetected(mCrashes, true, + Pattern.compile("installd"))); } @Test public void testFaultAddressBelowMin() throws Exception { - Assert.assertFalse(CrashUtils.detectCrash(new String[] {"Binder:12736_2"}, true, mCrashes)); + Assert.assertFalse(CrashUtils.securityCrashDetected(mCrashes, true, + Pattern.compile("synthetic_process_1"))); } @Test public void testIgnoreMinAddressCheck() throws Exception { - Assert.assertTrue(CrashUtils.detectCrash(new String[] {"Binder:12736_2"}, false, mCrashes)); + Assert.assertTrue(CrashUtils.securityCrashDetected(mCrashes, false, + Pattern.compile("synthetic_process_1"))); + } + + @Test + public void testBadAbortMessage() throws Exception { + Assert.assertFalse(CrashUtils.securityCrashDetected(mCrashes, true, + Pattern.compile("generic"))); } @Test public void testGoodAndBadCrashes() throws Exception { - Assert.assertTrue( - CrashUtils.detectCrash(new String[] {"AudioOut_D", "generic"}, true, mCrashes)); + Assert.assertTrue(CrashUtils.securityCrashDetected(mCrashes, true, + Pattern.compile("synthetic_process_0"), Pattern.compile("generic"))); } @Test public void testNullFaultAddress() throws Exception { JSONArray crashes = new JSONArray(); - crashes.put(createCrashJson(8373, 8414, "loo", null, "SIGSEGV")); - Assert.assertTrue(CrashUtils.detectCrash(new String[] {"loo"}, true, crashes)); + crashes.put(createCrashJson(8373, 8414, "loo", "com.android.bluetooth", null, "SIGSEGV")); + Assert.assertTrue(CrashUtils.securityCrashDetected(crashes, true, + Pattern.compile("com\\.android\\.bluetooth"))); } } diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java index 50a00f07..11ca7222 100644 --- a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java +++ b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java @@ -18,18 +18,29 @@ package com.android.compatibility.common.util; import com.android.tradefed.util.FileUtil; import com.android.tradefed.util.AbiUtils; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + import junit.framework.TestCase; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.io.StringReader; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + /** * Unit tests for {@link ResultHandler} */ @@ -59,10 +70,14 @@ public class ResultHandlerTest extends TestCase { private static final String BUILD_FINGERPRINT_UNALTERED = "build_fingerprint_unaltered"; private static final String BUILD_ID = "build_id"; private static final String BUILD_PRODUCT = "build_product"; + private static final String RUN_HISTORY = "run_history"; private static final String EXAMPLE_BUILD_ID = "XYZ"; private static final String EXAMPLE_BUILD_PRODUCT = "wolverine"; private static final String EXAMPLE_BUILD_FINGERPRINT = "example_build_fingerprint"; private static final String EXAMPLE_BUILD_FINGERPRINT_UNALTERED = "example_build_fingerprint_unaltered"; + private static final String EXAMPLE_RUN_HISTORY = + "[{\"startTime\":10000000000000,\"endTime\":10000000000001}," + + "{\"startTime\":10000000000002,\"endTime\":10000000000003}]"; private static final String DEVICE_A = "device123"; private static final String DEVICE_B = "device456"; @@ -176,6 +191,18 @@ public class ResultHandlerTest extends TestCase { result.addInvocationInfo(BUILD_FINGERPRINT, EXAMPLE_BUILD_FINGERPRINT); result.addInvocationInfo(BUILD_ID, EXAMPLE_BUILD_ID); result.addInvocationInfo(BUILD_PRODUCT, EXAMPLE_BUILD_PRODUCT); + result.addInvocationInfo(RUN_HISTORY, EXAMPLE_RUN_HISTORY); + Collection<InvocationResult.RunHistory> runHistories = + ((InvocationResult) result).getRunHistories(); + InvocationResult.RunHistory runHistory1 = new InvocationResult.RunHistory(); + runHistory1.startTime = 10000000000000L; + runHistory1.endTime = 10000000000001L; + runHistories.add(runHistory1); + InvocationResult.RunHistory runHistory2 = new InvocationResult.RunHistory(); + runHistory2.startTime = 10000000000002L; + runHistory2.endTime = 10000000000003L; + runHistories.add(runHistory2); + // Module A: test1 passes, test2 not executed IModuleResult moduleA = result.getOrCreateModule(ID_A); moduleA.setDone(false); @@ -208,12 +235,31 @@ public class ResultHandlerTest extends TestCase { moduleBTest5.skipped(); // Serialize to file - ResultHandler.writeResults(SUITE_NAME, SUITE_VERSION, SUITE_PLAN, SUITE_BUILD, - result, resultDir, START_MS, END_MS, REFERENCE_URL, LOG_URL, - COMMAND_LINE_ARGS); + File res = + ResultHandler.writeResults( + SUITE_NAME, + SUITE_VERSION, + SUITE_PLAN, + SUITE_BUILD, + result, + resultDir, + START_MS, + END_MS, + REFERENCE_URL, + LOG_URL, + COMMAND_LINE_ARGS); + String content = FileUtil.readStringFromFile(res); + assertXmlContainsAttribute(content, "Result/Build", "run_history", EXAMPLE_RUN_HISTORY); + assertXmlContainsNode(content, "Result/RunHistory"); + assertXmlContainsAttribute(content, "Result/RunHistory/Run", "start", "10000000000000"); + assertXmlContainsAttribute(content, "Result/RunHistory/Run", "end", "10000000000001"); + assertXmlContainsAttribute(content, "Result/RunHistory/Run", "start", "10000000000002"); + assertXmlContainsAttribute(content, "Result/RunHistory/Run", "end", "10000000000003"); // Parse the results and assert correctness - checkResult(ResultHandler.getResultFromDir(resultDir), false); + result = ResultHandler.getResultFromDir(resultDir); + checkResult(result, false); + checkRunHistory(result); } public void testParsing() throws Exception { @@ -350,6 +396,11 @@ public class ResultHandlerTest extends TestCase { checkResult(result, EXAMPLE_BUILD_FINGERPRINT, newTestFormat); } + static void checkRunHistory(IInvocationResult result) { + Map<String, String> buildInfo = result.getInvocationInfo(); + assertEquals("Incorrect run history", EXAMPLE_RUN_HISTORY, buildInfo.get(RUN_HISTORY)); + } + static void checkResult( IInvocationResult result, String expectedBuildFingerprint, boolean newTestFormat) throws Exception { @@ -450,4 +501,55 @@ public class ResultHandlerTest extends TestCase { assertNull("Unexpected stack trace", moduleBTest5.getStackTrace()); assertNull("Unexpected report", moduleBTest5.getReportLog()); } + + /** Return all XML nodes that match the given xPathExpression. */ + private NodeList getXmlNodes(String xml, String xPathExpression) + throws XPathExpressionException { + + InputSource inputSource = new InputSource(new StringReader(xml)); + XPath xpath = XPathFactory.newInstance().newXPath(); + return (NodeList) xpath.evaluate(xPathExpression, inputSource, XPathConstants.NODESET); + } + + /** Assert that the XML contains a node matching the given xPathExpression. */ + private NodeList assertXmlContainsNode(String xml, String xPathExpression) + throws XPathExpressionException { + NodeList nodes = getXmlNodes(xml, xPathExpression); + assertNotNull( + String.format("XML '%s' returned null for xpath '%s'.", xml, xPathExpression), + nodes); + assertTrue( + String.format( + "XML '%s' should have returned at least 1 node for xpath '%s', " + + "but returned %s nodes instead.", + xml, xPathExpression, nodes.getLength()), + nodes.getLength() >= 1); + return nodes; + } + + /** + * Assert that the XML contains a node matching the given xPathExpression and that the node has + * a given value. + */ + private void assertXmlContainsAttribute( + String xml, String xPathExpression, String attributeName, String attributeValue) + throws XPathExpressionException { + NodeList nodes = assertXmlContainsNode(xml, xPathExpression); + boolean found = false; + + for (int i = 0; i < nodes.getLength(); i++) { + Element element = (Element) nodes.item(i); + String value = element.getAttribute(attributeName); + if (attributeValue.equals(value)) { + found = true; + break; + } + } + + assertTrue( + String.format( + "xPath '%s' should contain attribute '%s' but does not. XML: '%s'", + xPathExpression, attributeName, xml), + found); + } } diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml index 40b195b7..5530f1b2 100755 --- a/tools/cts-tradefed/res/config/cts-known-failures.xml +++ b/tools/cts-tradefed/res/config/cts-known-failures.xml @@ -139,6 +139,10 @@ <!-- b/62481870 --> <option name="compatibility:exclude-filter" value="CtsNativeMediaAAudioTestCases android.nativemedia.aaudio.AAudioOutputStreamCallbackTest#testPlayback" /> + <!-- b/134654621 --> + <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.AppConfigurationTests#testTaskCloseRestoreFreeOrientation" /> + <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.AppConfigurationTests#testAppOrientationRequestConfigClears" /> + <!-- b/62976713 --> <option name="compatibility:exclude-filter" value="arm64-v8a CtsMediaBitstreamsTestCases" /> <option name="compatibility:exclude-filter" value="x86_64 CtsMediaBitstreamsTestCases" /> |
