diff options
author | Duy Truong <duytruong@google.com> | 2022-01-25 18:45:07 -0800 |
---|---|---|
committer | Duy Truong <duytruong@google.com> | 2022-01-27 23:28:27 +0000 |
commit | f198453ca886201a4c734fe294b7bc560649b3f5 (patch) | |
tree | e37b2758352c6fbe1ad919794ae676ed90fffc81 | |
parent | f26df263bd2ddc063422a26c3c4fdc716d8c8c81 (diff) | |
download | platform_testing-f198453ca886201a4c734fe294b7bc560649b3f5.tar.gz |
Add library to use OverlayFS to make read-only partitions writable.
Using OverlayFsUtils class will allow writing to read-only partitions
without having to disable verity and without having to reboot.
Note that all modifications will be deleted upon reboot.
Bug: 216394844
Test: build sts; run sts with a manually crafted test testcase.
Change-Id: Ia176be66e2f45cad053e7e84e20682106f6ea95c
Merged-In: Ia176be66e2f45cad053e7e84e20682106f6ea95c
(cherry picked from commit e17890701925962292d9ac0f02243fc8d0b88ee2)
-rw-r--r-- | libraries/sts-common-util/host-side/src/com/android/sts/common/OverlayFsUtils.java | 94 |
1 files changed, 94 insertions, 0 deletions
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 new file mode 100644 index 000000000..f523fb7a4 --- /dev/null +++ b/libraries/sts-common-util/host-side/src/com/android/sts/common/OverlayFsUtils.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2022 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.sts.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.util.CommandResult; +import com.android.tradefed.util.CommandStatus; + +public class OverlayFsUtils { + // output of `stat`, e.g. "root shell 755 u:object_r:vendor_file:s0" + static final Pattern PERM_PATTERN = + Pattern.compile( + "^(?<user>[a-zA-Z0-9_-]+) (?<group>[a-zA-Z0-9_-]+) (?<perm>[0-7]+)" + + " (?<secontext>.*)$"); + + /** + * Mounts an OverlayFS dir over the top most common dir in the list. + * + * <p>The directory should be writable after this returns successfully. To cleanup, reboot the + * device as unfortunately unmounting overlayfs is complicated. + * + * @param device The test device to setup overlayfs for. + * @param dir The directory to make writable. Directories with single quotes are not supported. + */ + public static void makeWritable(ITestDevice device, String dir) + throws DeviceNotAvailableException, IOException { + // TODO(duytruong): This should ideally be made into a TestRule that also handles cleanups + // However, test devices initiation is done in one of the @Before, after a rule's setup. + assertTrue("Can't acquire root for " + device.getSerialNumber(), device.enableAdbRoot()); + + String statOut = runAndCheck(device, "stat -c '%U %G %a %C' '" + dir + "'"); + Matcher m = PERM_PATTERN.matcher(statOut); + assertTrue("Bad stats output: " + statOut, m.find()); + String user = m.group("user"); + String group = m.group("group"); + String unixPerm = m.group("perm"); + String seContext = m.group("secontext"); + + Path tempdir = Paths.get("/mnt", "stsoverlayfs", dir); + String upperdir = tempdir.resolve("upper").toString(); + String workdir = tempdir.resolve("workdir").toString(); + + runAndCheck(device, String.format("mkdir -p '%s' '%s'", upperdir, workdir)); + runAndCheck(device, String.format("chown %s:%s '%s'", user, group, upperdir)); + runAndCheck(device, String.format("chcon '%s' '%s'", seContext, upperdir)); + runAndCheck(device, String.format("chmod %s '%s'", unixPerm, upperdir)); + + String mountCmd = + String.format( + "mount -t overlay overlay -o lowerdir='%s',upperdir='%s',workdir='%s' '%s'", + dir, upperdir, workdir, dir); + runAndCheck(device, mountCmd); + } + + /** + * Execute shell command on device, throws AssumptionViolatedException upon failure. + * + * @return stdout. + */ + private static String runAndCheck(ITestDevice device, String cmd) + throws DeviceNotAvailableException { + CommandResult res = device.executeShellV2Command(cmd); + String failMsg = + String.format( + "cmd failed: %s\ncode: %s\nstdout:\n%s\nstderr:\n%s", + cmd, res.getExitCode(), res.getStdout(), res.getStderr()); + assertEquals(failMsg, res.getStatus(), CommandStatus.SUCCESS); + return res.getStdout(); + } +} |