summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-31 23:09:02 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-31 23:09:02 +0000
commit75c6421176188027b8ab877163921749b0c2b9cd (patch)
tree54a67667a1cefd0275e7a7236758eee1cdc2a3ab
parent202b44c213f9297a2990408eabfc855ec50ace0d (diff)
parent481d021cfa2529413b13fa37ffdc033ff9a9804e (diff)
downloadplatform_testing-android12-qpr3-s7-release.tar.gz
Change-Id: I1a61066330a6c0d573abef88275473a90fe9bed3
-rw-r--r--libraries/sts-common-util/host-side/src/com/android/sts/common/CommandUtil.java24
-rw-r--r--libraries/sts-common-util/host-side/src/com/android/sts/common/OverlayFsUtils.java58
-rw-r--r--libraries/sts-common-util/host-side/src/com/android/sts/common/RootcanalUtils.java38
3 files changed, 96 insertions, 24 deletions
diff --git a/libraries/sts-common-util/host-side/src/com/android/sts/common/CommandUtil.java b/libraries/sts-common-util/host-side/src/com/android/sts/common/CommandUtil.java
index 64072df19..bdd65e742 100644
--- a/libraries/sts-common-util/host-side/src/com/android/sts/common/CommandUtil.java
+++ b/libraries/sts-common-util/host-side/src/com/android/sts/common/CommandUtil.java
@@ -28,7 +28,7 @@ public final class CommandUtil {
private CommandUtil() {}
/**
- * Execute shell command on device, throws AssertionError upon failure.
+ * Execute shell command on device, throws AssertionError if command does not return 0.
*
* @param device the device to use
* @param cmd the command to run
@@ -36,7 +36,27 @@ public final class CommandUtil {
*/
public static CommandResult runAndCheck(ITestDevice device, String cmd)
throws DeviceNotAvailableException {
- CommandResult res = device.executeShellV2Command(cmd);
+ return runAndCheck(device, cmd, 0);
+ }
+
+ /**
+ * Execute shell command on device, throws AssertionError if command does not return 0.
+ *
+ * @param device the device to use
+ * @param cmd the command to run
+ * @param retries the number of retries to attempt
+ * @return the result of device.executeShellV2Command
+ */
+ public static CommandResult runAndCheck(ITestDevice device, String cmd, int retries)
+ throws DeviceNotAvailableException {
+ int attempt = 0;
+ CommandResult res;
+
+ do {
+ attempt += 1;
+ res = device.executeShellV2Command(cmd);
+ } while (res.getStatus() != CommandStatus.SUCCESS && attempt <= retries);
+
String failMsg =
String.format(
"cmd failed: %s\ncode: %s\nstdout:\n%s\nstderr:\n%s",
diff --git a/libraries/sts-common-util/host-side/src/com/android/sts/common/OverlayFsUtils.java b/libraries/sts-common-util/host-side/src/com/android/sts/common/OverlayFsUtils.java
index a21ce577b..1fa55de31 100644
--- a/libraries/sts-common-util/host-side/src/com/android/sts/common/OverlayFsUtils.java
+++ b/libraries/sts-common-util/host-side/src/com/android/sts/common/OverlayFsUtils.java
@@ -23,6 +23,10 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.rules.TestWatcher;
@@ -35,9 +39,11 @@ import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
import com.google.common.hash.Hashing;
+
/** TestWatcher that enables writing to read-only partitions and reboots device when done. */
public class OverlayFsUtils extends TestWatcher {
- private static final String OVERLAYFS_PREFIX = "overlay_sts_";
+ private static final String OVERLAYFS_PREFIX = "sts_overlayfs_";
+ private static final Path WRITABLE_DIR = Paths.get("/data", "local", "tmp");
private final BaseHostJUnit4Test test;
@@ -47,6 +53,8 @@ public class OverlayFsUtils extends TestWatcher {
"^(?<user>[a-zA-Z0-9_-]+) (?<group>[a-zA-Z0-9_-]+) (?<perm>[0-7]+)"
+ " (?<secontext>.*)$");
+ private Map<ITestDevice, List<String>> workingDirs = new HashMap<>();
+
public OverlayFsUtils(BaseHostJUnit4Test test) {
assertNotNull("Need to pass in a valid testcase object.", test);
this.test = test;
@@ -60,16 +68,21 @@ public class OverlayFsUtils extends TestWatcher {
*
* @param dir The directory to make writable. Directories with single quotes are not supported.
*/
- public void makeWritable(final String dir)
+ public void makeWritable(final String dir, int megabytes)
throws DeviceNotAvailableException, IOException, IllegalStateException {
ITestDevice device = test.getDevice();
assertNotNull("device not set.", device);
assertTrue("dir needs to be an absolute path.", dir.startsWith("/"));
+ // losetup doesn't work for image paths 64 bytes or longer, so we have to truncate
+ String dirHash = Hashing.md5().hashString(dir, StandardCharsets.UTF_8).toString();
+ int pathPrefixLength = WRITABLE_DIR.toString().length() + 1 + OVERLAYFS_PREFIX.length();
+ int dirHashLength = Math.min(64 - pathPrefixLength - 5, dirHash.length());
+ assertTrue("Can't fit overlayFS image path in 64 chars.", dirHashLength >= 5);
+ String id = OVERLAYFS_PREFIX + dirHash.substring(0, dirHashLength);
+
// Check and make sure we have not already mounted over this dir. We do that by hashing
// the lower dir path and put that as part of the device ID for `mount`.
- String dirHash = Hashing.md5().hashString(dir, StandardCharsets.UTF_8).toString();
- String id = OVERLAYFS_PREFIX + dirHash;
CommandResult res = device.executeShellV2Command("mount | grep -q " + id);
if (res.getStatus() == CommandStatus.SUCCESS) {
// a mount with the same ID already exists
@@ -88,7 +101,28 @@ public class OverlayFsUtils extends TestWatcher {
String unixPerm = m.group("perm");
String seContext = m.group("secontext");
- Path tempdir = Paths.get("/mnt", "stsoverlayfs", id);
+ // Disable SELinux enforcement and mount a loopback ext4 image
+ CommandUtil.runAndCheck(device, "setenforce 0");
+ Path tempdir = WRITABLE_DIR.resolve(id);
+ Path tempimg = tempdir.getParent().resolve(tempdir.getFileName().toString() + ".img");
+ CommandUtil.runAndCheck(
+ device,
+ String.format("dd if=/dev/zero of='%s' bs=%dM count=1", tempimg, megabytes));
+ CommandUtil.runAndCheck(device, String.format("mkdir '%s'", tempdir));
+ CommandUtil.runAndCheck(device, String.format("mkfs.ext4 '%s'", tempimg));
+ CommandUtil.runAndCheck(
+ device, String.format("mount -o loop '%s' '%s'", tempimg, tempdir), 3);
+
+ List<String> dirs;
+ if (!workingDirs.containsKey(device)) {
+ dirs = new ArrayList<>(2);
+ workingDirs.put(device, dirs);
+ } else {
+ dirs = workingDirs.get(device);
+ }
+ dirs.add(tempdir.toString());
+ dirs.add(tempimg.toString());
+
String upperdir = tempdir.resolve("upper").toString();
String workdir = tempdir.resolve("workdir").toString();
@@ -116,10 +150,24 @@ public class OverlayFsUtils extends TestWatcher {
ITestDevice device = test.getDevice();
assertNotNull("Device not set", device);
try {
+ // Since we can't umount an overlayfs cleanly, reboot the device to cleanup
if (anyOverlayFsMounted()) {
device.rebootUntilOnline();
device.waitForDeviceAvailable();
}
+
+ // Remove upper and working dirs
+ assertTrue("Can't acquire root: " + device.getSerialNumber(), device.enableAdbRoot());
+ if (workingDirs.containsKey(device)) {
+ for (String dir : workingDirs.get(device)) {
+ CommandUtil.runAndCheck(device, String.format("rm -rf '%s'", dir));
+ }
+ }
+
+ // Restore SELinux enforcement state
+ CommandUtil.runAndCheck(device, "setenforce 1");
+
+ assertTrue("Can't remove root: " + device.getSerialNumber(), device.disableAdbRoot());
} catch (DeviceNotAvailableException e) {
throw new AssertionError("Device unavailable when cleaning up", e);
}
diff --git a/libraries/sts-common-util/host-side/src/com/android/sts/common/RootcanalUtils.java b/libraries/sts-common-util/host-side/src/com/android/sts/common/RootcanalUtils.java
index d3d23c30c..3849b954d 100644
--- a/libraries/sts-common-util/host-side/src/com/android/sts/common/RootcanalUtils.java
+++ b/libraries/sts-common-util/host-side/src/com/android/sts/common/RootcanalUtils.java
@@ -18,6 +18,7 @@ package com.android.sts.common;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertFalse;
+import static com.android.sts.common.CommandUtil.runAndCheck;
import java.io.File;
import java.io.FileWriter;
@@ -56,13 +57,15 @@ import com.android.tradefed.util.RunUtil;
/** TestWatcher that sets up a virtual bluetooth HAL and reboots the device once done. */
public class RootcanalUtils extends TestWatcher {
- private static final String LOCK_FILENAME = "/mnt/sts_rootcanal.lck";
+ private static final String LOCK_FILENAME = "/data/local/tmp/sts_rootcanal.lck";
private BaseHostJUnit4Test test;
+ private OverlayFsUtils overlayFsUtils;
public RootcanalUtils(BaseHostJUnit4Test test) {
assertNotNull(test);
this.test = test;
+ this.overlayFsUtils = new OverlayFsUtils(test);
}
@Override
@@ -70,9 +73,11 @@ public class RootcanalUtils extends TestWatcher {
ITestDevice device = test.getDevice();
assertNotNull("Device not set", device);
try {
- // No need to call OverlayFsUtils' finished() because we're restarting anyway
- device.rebootUntilOnline();
- device.waitForDeviceAvailable();
+ device.enableAdbRoot();
+ runAndCheck(device, String.format("rm -rf '%s'", LOCK_FILENAME));
+ device.disableAdbRoot();
+ // OverlayFsUtils' finished() will restart the device.
+ overlayFsUtils.finished(d);
} catch (DeviceNotAvailableException e) {
throw new AssertionError("Device unavailable when cleaning up", e);
}
@@ -104,16 +109,16 @@ public class RootcanalUtils extends TestWatcher {
// Make sure that /vendor is writable
try {
- new OverlayFsUtils(test).makeWritable("/vendor");
+ overlayFsUtils.makeWritable("/vendor", 100);
} catch (IllegalStateException e) {
CLog.w(e);
}
// Remove existing HAL files and push new virtual HAL files.
- CommandUtil.runAndCheck(device, "svc bluetooth disable");
- CommandUtil.runAndCheck(
+ runAndCheck(device, "svc bluetooth disable");
+ runAndCheck(
device,
- "rm /vendor/lib64/hw/android.hardware.bluetooth@* "
+ "rm -f /vendor/lib64/hw/android.hardware.bluetooth@* "
+ "/vendor/lib/hw/android.hardware.bluetooth@* "
+ "/vendor/bin/hw/android.hardware.bluetooth@* "
+ "/vendor/etc/init/android.hardware.bluetooth@*");
@@ -138,22 +143,21 @@ public class RootcanalUtils extends TestWatcher {
tryUpdateVintfManifest(device);
// Fix up permissions and SELinux contexts of files pushed over
- CommandUtil.runAndCheck(device, "cp /system/lib64/libchrome.so /vendor/lib64/libchrome.so");
- CommandUtil.runAndCheck(
- device, "chmod 755 /vendor/bin/hw/android.hardware.bluetooth@1.1-service.sim");
- CommandUtil.runAndCheck(
+ runAndCheck(device, "cp /system/lib64/libchrome.so /vendor/lib64/libchrome.so");
+ runAndCheck(device, "chmod 755 /vendor/bin/hw/android.hardware.bluetooth@1.1-service.sim");
+ runAndCheck(
device,
"chcon u:object_r:hal_bluetooth_default_exec:s0 "
+ "/vendor/bin/hw/android.hardware.bluetooth@1.1-service.sim");
- CommandUtil.runAndCheck(
+ runAndCheck(
device,
"chmod 644 "
+ "/vendor/etc/vintf/manifest.xml "
+ "/vendor/lib/hw/android.hardware.bluetooth@1.1-impl-sim.so "
+ "/vendor/lib64/hw/android.hardware.bluetooth@1.1-impl-sim.so");
- CommandUtil.runAndCheck(
+ runAndCheck(
device, "chcon u:object_r:vendor_configs_file:s0 /vendor/etc/vintf/manifest.xml");
- CommandUtil.runAndCheck(
+ runAndCheck(
device,
"chcon u:object_r:vendor_file:s0 "
+ "/vendor/lib/hw/android.hardware.bluetooth@1.1-impl-sim.so "
@@ -190,8 +194,8 @@ public class RootcanalUtils extends TestWatcher {
// Reenable Bluetooth and enable RootCanal control channel
String checkCmd = "netstat -l -t -n -W | grep '0\\.0\\.0\\.0:6111'";
while (true) {
- CommandUtil.runAndCheck(device, "svc bluetooth enable");
- CommandUtil.runAndCheck(device, "setprop vendor.bt.rootcanal_test_console true");
+ runAndCheck(device, "svc bluetooth enable");
+ runAndCheck(device, "setprop vendor.bt.rootcanal_test_console true");
CommandResult res = device.executeShellV2Command(checkCmd);
if (res.getStatus() == CommandStatus.SUCCESS) {
break;