Android Security CTS/STS hostside Oom Catcher fixes.
There's a NullPointerException due to ThreadLocal variables that got
missed, meaning every branch on or above oc-dev improperly failed tests
when oom was detected.
* Move the ThreadLocal uses to the delegating thread.
* Change the behavior of setting a test to "high-memory"
* Clean up and log device memory caching
* Fix a problem where hard reset was detected when Oom detected.
- only was a problem when an exception occurred
Bug: 127834624
Bug: 127837702
Bug: 111403569
Test: run "oom(){ oom $1$1;};oom oom" during a test and ensure oom catcher
catches oom cleanly without hard reset detected.
Test: reboot deviced during a test and ensure hard reset is detected.
Change-Id: I87bca9e0ab5563a2b8b9bf90cfb68ff41e9ab8cf
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/HostsideOomCatcher.java b/hostsidetests/securitybulletin/src/android/security/cts/HostsideOomCatcher.java
index cd39c56..86f930b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/HostsideOomCatcher.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/HostsideOomCatcher.java
@@ -79,14 +79,23 @@
* Utility to get the device memory total by reading /proc/meminfo and returning MemTotal
*/
private static long getMemTotal(ITestDevice device) throws DeviceNotAvailableException {
- String memInfo = device.executeShellCommand("cat /proc/meminfo");
- Pattern pattern = Pattern.compile("MemTotal:\\s*(.*?)\\s*[kK][bB]");
- Matcher matcher = pattern.matcher(memInfo);
- if (matcher.find()) {
- return Long.parseLong(matcher.group(1));
- } else {
- throw new RuntimeException("Could not get device memory total");
+ // cache device TotalMem to avoid an adb shell for every test.
+ String serial = device.getSerialNumber();
+ Long totalMemory = totalMemories.get(serial);
+ if (totalMemory == null) {
+ String memInfo = device.executeShellCommand("cat /proc/meminfo");
+ Pattern pattern = Pattern.compile("MemTotal:\\s*(.*?)\\s*[kK][bB]");
+ Matcher matcher = pattern.matcher(memInfo);
+ if (matcher.find()) {
+ totalMemory = Long.parseLong(matcher.group(1));
+ } else {
+ throw new RuntimeException("Could not get device memory total.");
+ }
+ Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+ "Device " + serial + " has " + totalMemory + "KB total memory.");
+ totalMemories.put(serial, totalMemory);
}
+ return totalMemory;
}
/**
@@ -94,24 +103,14 @@
* Match this call to SecurityTestCase.setup().
*/
public synchronized void start() throws Exception {
- // cache device TotalMem to avoid and adb shell for every test.
- Long totalMemory = totalMemories.get(getDevice().getSerialNumber());
- if (totalMemory == null) {
- totalMemory = getMemTotal(getDevice());
- totalMemories.put(getDevice().getSerialNumber(), totalMemory);
- }
+ long totalMemory = getMemTotal(getDevice());
isLowMemoryDevice = totalMemory < LOW_MEMORY_DEVICE_THRESHOLD_KB;
// reset test oom behavior
- // Low memory devices should skip (pass) tests when OOMing and log so that the
- // high-memory-test flag can be added. Normal devices should fail tests that OOM so that
- // they'll be ran again with --retry. If the test OOMs because previous tests used the
- // memory, it will likely pass on a second try.
- if (isLowMemoryDevice) {
- oomBehavior = OomBehavior.PASS_AND_LOG;
- } else {
- oomBehavior = OomBehavior.FAIL_AND_LOG;
- }
+ // Devices should fail tests that OOM so that they'll be ran again with --retry.
+ // If the test OOMs because previous tests used the memory, it will likely pass
+ // on a second try.
+ oomBehavior = OomBehavior.FAIL_AND_LOG;
oomDetected = false;
// Cache OOM detection in separate persistent threads for each device.
@@ -207,12 +206,11 @@
Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
"lowmemorykiller detected; rebooting device.");
synchronized (HostsideOomCatcher.this) { // synchronized for oomDetected
- oomDetected = true;
+ oomDetected = true; // set HostSideOomCatcher var
}
try {
device.nonBlockingReboot();
device.waitForDeviceOnline(60 * 2 * 1000); // 2 minutes
- context.updateKernelStartTime();
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index eea1380..ea6d66c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -96,26 +96,29 @@
oomCatcher.stop(getDevice().getSerialNumber());
getDevice().waitForDeviceAvailable(120 * 1000);
- String uptime = getDevice().executeShellCommand("cat /proc/uptime");
- assertTrue("Phone has had a hard reset",
- (System.currentTimeMillis()/1000 -
- Integer.parseInt(uptime.substring(0, uptime.indexOf('.')))
- - kernelStartTime < 2));
- //TODO(badash@): add ability to catch runtime restart
- getDevice().disableAdbRoot();
if (oomCatcher.isOomDetected()) {
+ // we don't need to check kernel start time if we intentionally rebooted because oom
+ updateKernelStartTime();
switch (oomCatcher.getOomBehavior()) {
case FAIL_AND_LOG:
fail("The device ran out of memory.");
- return;
+ break;
case PASS_AND_LOG:
Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG, "Skipping test.");
- return;
+ break;
case FAIL_NO_LOG:
fail();
- return;
+ break;
}
+ } else {
+ String uptime = getDevice().executeShellCommand("cat /proc/uptime");
+ assertTrue("Phone has had a hard reset",
+ (System.currentTimeMillis()/1000 -
+ Integer.parseInt(uptime.substring(0, uptime.indexOf('.')))
+ - kernelStartTime < 2));
+ //TODO(badash@): add ability to catch runtime restart
+ getDevice().disableAdbRoot();
}
}