From c10d3fdb2cfee0aaaed8ea115f0a2afce3579804 Mon Sep 17 00:00:00 2001 From: Paul Trautrim Date: Wed, 16 Jan 2019 10:30:24 +0900 Subject: [PATCH] Add presubmit test for vendor overlay Add a test that creates files in the appropriate vendor_overlay directory and verifies that they are correctly overlaid (or not) onto /vendor after rebooting. Test: locally running atest Change-Id: I65860dbeb837f86ac030fa51b3af93844e82de96 --- TEST_MAPPING | 3 + fs_mgr/tests/Android.bp | 12 ++ .../vendoroverlay/VendorOverlayHostTest.java | 151 ++++++++++++++++++ fs_mgr/tests/vendor-overlay-test.xml | 21 +++ 4 files changed, 187 insertions(+) create mode 100644 fs_mgr/tests/src/com/android/tests/vendoroverlay/VendorOverlayHostTest.java create mode 100644 fs_mgr/tests/vendor-overlay-test.xml diff --git a/TEST_MAPPING b/TEST_MAPPING index cc85408e0..716378be7 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -9,6 +9,9 @@ { "name": "fs_mgr_unit_test" }, + { + "name": "fs_mgr_vendor_overlay_test" + }, { "name": "init_tests" }, diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp index 565597af7..59af9240d 100644 --- a/fs_mgr/tests/Android.bp +++ b/fs_mgr/tests/Android.bp @@ -53,3 +53,15 @@ cc_prebuilt_binary { }, host_supported: true, } + +java_test_host { + name: "fs_mgr_vendor_overlay_test", + + srcs: ["src/**/VendorOverlayHostTest.java"], + + libs: ["tradefed"], + + test_config: "vendor-overlay-test.xml", + + test_suites: ["general-tests"], +} diff --git a/fs_mgr/tests/src/com/android/tests/vendoroverlay/VendorOverlayHostTest.java b/fs_mgr/tests/src/com/android/tests/vendoroverlay/VendorOverlayHostTest.java new file mode 100644 index 000000000..f08cab239 --- /dev/null +++ b/fs_mgr/tests/src/com/android/tests/vendoroverlay/VendorOverlayHostTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2019 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.tests.vendoroverlay; + +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.tradefed.util.CommandResult; +import com.android.tradefed.util.CommandStatus; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test the vendor overlay feature. Requires adb remount with OverlayFS. + */ +@RunWith(DeviceJUnit4ClassRunner.class) +public class VendorOverlayHostTest extends BaseHostJUnit4Test { + boolean wasRoot = false; + + @Before + public void setup() throws DeviceNotAvailableException { + wasRoot = getDevice().isAdbRoot(); + if (!wasRoot) { + Assume.assumeTrue("Test requires root", getDevice().enableAdbRoot()); + } + + Assume.assumeTrue("Skipping vendor overlay test due to lack of necessary OverlayFS support", + testConditionsMet()); + + getDevice().remountSystemWritable(); + // Was OverlayFS used by adb remount? Without it we can't safely re-enable dm-verity. + Pattern vendorPattern = Pattern.compile("^overlay .+ /vendor$", Pattern.MULTILINE); + Pattern productPattern = Pattern.compile("^overlay .+ /product$", Pattern.MULTILINE); + CommandResult result = getDevice().executeShellV2Command("df"); + Assume.assumeTrue("OverlayFS not used for adb remount on /vendor", + vendorPattern.matcher(result.getStdout()).find()); + Assume.assumeTrue("OverlayFS not used for adb remount on /product", + productPattern.matcher(result.getStdout()).find()); + } + + private boolean cmdSucceeded(CommandResult result) { + return result.getStatus() == CommandStatus.SUCCESS; + } + + private void assumeMkdirSuccess(String dir) throws DeviceNotAvailableException { + CommandResult result = getDevice().executeShellV2Command("mkdir -p " + dir); + Assume.assumeTrue("Couldn't create " + dir, cmdSucceeded(result)); + } + + /** + * Tests that files in the appropriate /product/vendor_overlay dir are overlaid onto /vendor. + */ + @Test + public void testVendorOverlay() throws DeviceNotAvailableException { + String vndkVersion = getDevice().executeShellV2Command("getprop ro.vndk.version").getStdout(); + + // Create files and modify policy + CommandResult result = getDevice().executeShellV2Command( + "echo '/(product|system/product)/vendor_overlay/" + vndkVersion + + "/.* u:object_r:vendor_file:s0'" + " >> /system/etc/selinux/plat_file_contexts"); + Assume.assumeTrue("Couldn't modify plat_file_contexts", cmdSucceeded(result)); + assumeMkdirSuccess("/vendor/testdir"); + assumeMkdirSuccess("/vendor/diffcontext"); + assumeMkdirSuccess("/product/vendor_overlay/'" + vndkVersion + "'/testdir"); + result = getDevice().executeShellV2Command( + "echo overlay > /product/vendor_overlay/'" + vndkVersion + "'/testdir/test"); + Assume.assumeTrue("Couldn't create text file in testdir", cmdSucceeded(result)); + assumeMkdirSuccess("/product/vendor_overlay/'" + vndkVersion + "'/noexist/test"); + assumeMkdirSuccess("/product/vendor_overlay/'" + vndkVersion + "'/diffcontext/test"); + result = getDevice().executeShellV2Command( + "restorecon -r /product/vendor_overlay/'" + vndkVersion + "'/testdir"); + Assume.assumeTrue("Couldn't write testdir context", cmdSucceeded(result)); + + getDevice().reboot(); + + // Test that the file was overlaid properly + result = getDevice().executeShellV2Command("[ $(cat /vendor/testdir/test) = overlay ]"); + Assert.assertTrue("test file was not overlaid onto /vendor/", cmdSucceeded(result)); + result = getDevice().executeShellV2Command("[ ! -d /vendor/noexist/test ]"); + Assert.assertTrue("noexist dir shouldn't exist on /vendor", cmdSucceeded(result)); + result = getDevice().executeShellV2Command("[ ! -d /vendor/diffcontext/test ]"); + Assert.assertTrue("diffcontext dir shouldn't exist on /vendor", cmdSucceeded(result)); + } + + // Duplicate of fs_mgr_overlayfs_valid() logic + // Requires root + public boolean testConditionsMet() throws DeviceNotAvailableException { + if (cmdSucceeded(getDevice().executeShellV2Command( + "[ -e /sys/module/overlay/parameters/override_creds ]"))) { + return true; + } + if (cmdSucceeded(getDevice().executeShellV2Command("[ ! -e /sys/module/overlay ]"))) { + return false; + } + CommandResult result = getDevice().executeShellV2Command("awk '{ print $3 }' /proc/version"); + Pattern kernelVersionPattern = Pattern.compile("([1-9])[.]([0-9]+).*"); + Matcher kernelVersionMatcher = kernelVersionPattern.matcher(result.getStdout()); + kernelVersionMatcher.find(); + int majorKernelVersion; + int minorKernelVersion; + try { + majorKernelVersion = Integer.parseInt(kernelVersionMatcher.group(1)); + minorKernelVersion = Integer.parseInt(kernelVersionMatcher.group(2)); + } catch (Exception e) { + return false; + } + if (majorKernelVersion < 4) { + return true; + } + if (majorKernelVersion > 4) { + return false; + } + if (minorKernelVersion > 6) { + return false; + } + return true; + } + + @After + public void tearDown() throws DeviceNotAvailableException { + if (getDevice().executeAdbCommand("enable-verity").contains("Now reboot your device")) { + getDevice().reboot(); + } + if (!wasRoot) { + getDevice().disableAdbRoot(); + } + } +} + diff --git a/fs_mgr/tests/vendor-overlay-test.xml b/fs_mgr/tests/vendor-overlay-test.xml new file mode 100644 index 000000000..0b5c8cc4e --- /dev/null +++ b/fs_mgr/tests/vendor-overlay-test.xml @@ -0,0 +1,21 @@ + + + + + + +