diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-03-31 23:09:02 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-03-31 23:09:02 +0000 |
commit | 75c6421176188027b8ab877163921749b0c2b9cd (patch) | |
tree | 54a67667a1cefd0275e7a7236758eee1cdc2a3ab | |
parent | 202b44c213f9297a2990408eabfc855ec50ace0d (diff) | |
parent | 481d021cfa2529413b13fa37ffdc033ff9a9804e (diff) | |
download | platform_testing-android12-qpr3-s7-release.tar.gz |
Snap for 8390762 from 481d021cfa2529413b13fa37ffdc033ff9a9804e to sc-qpr3-releaseandroid-12.1.0_r9android-12.1.0_r8android-12.1.0_r7android-12.1.0_r22android-12.1.0_r21android-12.1.0_r20android-12.1.0_r19android-12.1.0_r11android-12.1.0_r10android12-qpr3-s7-releaseandroid12-qpr3-s6-releaseandroid12-qpr3-s5-releaseandroid12-qpr3-s4-releaseandroid12-qpr3-s3-releaseandroid12-qpr3-s2-releaseandroid12-qpr3-s1-releaseandroid12-qpr3-release
Change-Id: I1a61066330a6c0d573abef88275473a90fe9bed3
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; |