summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-02-14 07:55:19 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-02-14 07:55:19 +0000
commit68abbff8fc44c8ee85eacb00b4544c02946f0a5d (patch)
tree291db6cc282f9aa3afbcbae93350caeb99b5af1c
parentb38719428ea52eda6ded644a4365cb431c918335 (diff)
parentb1e956e056edffec55e0f99f3849208a911669b3 (diff)
downloadplatform_testing-68abbff8fc44c8ee85eacb00b4544c02946f0a5d.tar.gz
Snap for 8180713 from b1e956e056edffec55e0f99f3849208a911669b3 to mainline-ipsec-release
Change-Id: I7ccfed379f266e41f6e541af18a59991fefd1767
-rw-r--r--libraries/compatibility-common-util/Android.bp1
-rw-r--r--libraries/sts-common-util/OWNERS3
-rw-r--r--libraries/sts-common-util/device-side/Android.bp32
-rw-r--r--libraries/sts-common-util/device-side/src/com/android/sts/common/util/StsExtraBusinessLogicTestCase.java134
-rw-r--r--libraries/sts-common-util/host-side/Android.bp33
-rw-r--r--libraries/sts-common-util/host-side/src/com/android/sts/common/OverlayFsUtils.java94
-rw-r--r--libraries/sts-common-util/host-side/src/com/android/sts/common/tradefed/testtype/StsExtraBusinessLogicHostTestBase.java135
-rw-r--r--libraries/sts-common-util/util/Android.bp48
-rw-r--r--libraries/sts-common-util/util/src/com/android/sts/common/util/BusinessLogicSetStore.java53
-rw-r--r--libraries/sts-common-util/util/src/com/android/sts/common/util/DescriptionProvider.java34
-rw-r--r--libraries/sts-common-util/util/src/com/android/sts/common/util/SplUtils.java51
-rw-r--r--libraries/sts-common-util/util/src/com/android/sts/common/util/StsLogic.java238
12 files changed, 856 insertions, 0 deletions
diff --git a/libraries/compatibility-common-util/Android.bp b/libraries/compatibility-common-util/Android.bp
index 5b58337e9..485a5f441 100644
--- a/libraries/compatibility-common-util/Android.bp
+++ b/libraries/compatibility-common-util/Android.bp
@@ -34,6 +34,7 @@ java_library {
visibility: [
"//test/suite_harness/common/util",
"//platform_testing/libraries/compatibility-common-util/tests",
+ "//platform_testing/libraries/sts-common-util/util",
],
srcs: ["src/**/*.java"],
host_supported: true,
diff --git a/libraries/sts-common-util/OWNERS b/libraries/sts-common-util/OWNERS
new file mode 100644
index 000000000..69d208103
--- /dev/null
+++ b/libraries/sts-common-util/OWNERS
@@ -0,0 +1,3 @@
+# STS Owners
+cdombroski@google.com
+musashi@google.com
diff --git a/libraries/sts-common-util/device-side/Android.bp b/libraries/sts-common-util/device-side/Android.bp
new file mode 100644
index 000000000..1692a7c2e
--- /dev/null
+++ b/libraries/sts-common-util/device-side/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2021 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library_static {
+ name: "sts-device-util",
+ sdk_version: "test_current",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "sts-common-util-devicesidelib",
+ ],
+
+ libs: [
+ "compatibility-device-util-axt",
+ ],
+}
diff --git a/libraries/sts-common-util/device-side/src/com/android/sts/common/util/StsExtraBusinessLogicTestCase.java b/libraries/sts-common-util/device-side/src/com/android/sts/common/util/StsExtraBusinessLogicTestCase.java
new file mode 100644
index 000000000..f50c60702
--- /dev/null
+++ b/libraries/sts-common-util/device-side/src/com/android/sts/common/util/StsExtraBusinessLogicTestCase.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2021 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.util;
+
+import android.os.Build;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ExtraBusinessLogicTestCase;
+import com.android.compatibility.common.util.PropertyUtil;
+
+import org.junit.Rule;
+import org.junit.runner.Description;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/** The device-side implementation of StsLogic. */
+public class StsExtraBusinessLogicTestCase extends ExtraBusinessLogicTestCase implements StsLogic {
+
+ private LocalDate deviceSpl = null;
+ private LocalDate kernelSpl = null;
+ @Rule public DescriptionProvider descriptionProvider = new DescriptionProvider();
+
+ protected StsExtraBusinessLogicTestCase() {
+ mDependentOnBusinessLogic = false;
+ }
+
+ @Override
+ public List<String> getExtraBusinessLogics() {
+ // set in test/sts/tools/sts-tradefed/res/config/sts-base-dynamic-*.xml
+ String stsDynamicPlan =
+ InstrumentationRegistry.getArguments().getString("sts-dynamic-plan");
+ switch (stsDynamicPlan) {
+ case "incremental":
+ return StsLogic.STS_EXTRA_BUSINESS_LOGIC_INCREMENTAL;
+ case "full":
+ return StsLogic.STS_EXTRA_BUSINESS_LOGIC_FULL;
+ default:
+ throw new RuntimeException(
+ "Could not find Dynamic STS plan in InstrumentationRegistry arguments");
+ }
+ }
+
+ @Override
+ public Description getTestDescription() {
+ return descriptionProvider.getDescription();
+ }
+
+ @Override
+ public LocalDate getPlatformSpl() {
+ if (deviceSpl == null) {
+ deviceSpl = SplUtils.localDateFromSplString(Build.VERSION.SECURITY_PATCH);
+ }
+ return deviceSpl;
+ }
+
+ @Override
+ public LocalDate getKernelSpl() {
+ if (kernelSpl == null) {
+ // set in:
+ // test/sts/tools/sts-tradefed/src/com/android/tradefed/targetprep/multi/KernelSPL.java
+ String kernelSplString =
+ PropertyUtil.getProperty("persist.sts.build_version_kernel_security_patch");
+ if (kernelSplString == null) {
+ return null;
+ }
+ kernelSpl = SplUtils.localDateFromSplString(kernelSplString);
+ }
+ return kernelSpl;
+ }
+
+ @Override
+ public boolean shouldUseKernelSpl() {
+ // set in test/sts/tools/sts-tradefed/res/config/sts-base-use-kernel-spl.xml
+ String useKernelSplString =
+ InstrumentationRegistry.getArguments().getString("sts-use-kernel-spl");
+ return Boolean.parseBoolean(useKernelSplString);
+ }
+
+ /**
+ * Specify the latest release bulletin. Control this from the command-line with the following:
+ * --test-arg
+ * com.android.tradefed.testtype.AndroidJUnitTest:instrumentation-arg:release-bulletin-spl:=2020-06
+ */
+ @Override
+ public LocalDate getReleaseBulletinSpl() {
+ // set manually with command-line args at runtime
+ String releaseBulletinSpl =
+ InstrumentationRegistry.getArguments().getString("release-bulletin-spl");
+ if (releaseBulletinSpl == null) {
+ return null;
+ }
+ // bulletin is released by month; add any day - only the year and month are compared.
+ releaseBulletinSpl =
+ String.format("%s-%02d", releaseBulletinSpl, SplUtils.Type.PARTIAL.day);
+ return SplUtils.localDateFromSplString(releaseBulletinSpl);
+ }
+
+ @Override
+ public void logInfo(String logTag, String format, Object... args) {
+ Log.i(logTag, String.format(format, args));
+ }
+
+ @Override
+ public void logDebug(String logTag, String format, Object... args) {
+ Log.d(logTag, String.format(format, args));
+ }
+
+ @Override
+ public void logWarn(String logTag, String format, Object... args) {
+ Log.w(logTag, String.format(format, args));
+ }
+
+ @Override
+ public void logError(String logTag, String format, Object... args) {
+ Log.e(logTag, String.format(format, args));
+ }
+}
diff --git a/libraries/sts-common-util/host-side/Android.bp b/libraries/sts-common-util/host-side/Android.bp
new file mode 100644
index 000000000..49f51f4d7
--- /dev/null
+++ b/libraries/sts-common-util/host-side/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2021 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library_host {
+ name: "sts-host-util",
+ defaults: ["cts_error_prone_rules"],
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "sts-common-util-lib",
+ ],
+
+ libs: [
+ "compatibility-tradefed",
+ "tradefed",
+ ],
+}
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();
+ }
+}
diff --git a/libraries/sts-common-util/host-side/src/com/android/sts/common/tradefed/testtype/StsExtraBusinessLogicHostTestBase.java b/libraries/sts-common-util/host-side/src/com/android/sts/common/tradefed/testtype/StsExtraBusinessLogicHostTestBase.java
new file mode 100644
index 000000000..68132f93e
--- /dev/null
+++ b/libraries/sts-common-util/host-side/src/com/android/sts/common/tradefed/testtype/StsExtraBusinessLogicHostTestBase.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 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.tradefed.testtype;
+
+import com.android.compatibility.common.tradefed.testtype.ExtraBusinessLogicHostTestBase;
+import com.android.ddmlib.Log;
+import com.android.sts.common.util.DescriptionProvider;
+import com.android.sts.common.util.SplUtils;
+import com.android.sts.common.util.StsLogic;
+import com.android.tradefed.device.DeviceNotAvailableException;
+
+import org.junit.Rule;
+import org.junit.runner.Description;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/** The host-side implementation of StsLogic. */
+public class StsExtraBusinessLogicHostTestBase extends ExtraBusinessLogicHostTestBase
+ implements StsLogic {
+
+ private LocalDate deviceSpl = null;
+ private LocalDate kernelSpl = null;
+ @Rule public DescriptionProvider descriptionProvider = new DescriptionProvider();
+
+ public StsExtraBusinessLogicHostTestBase() {
+ super();
+ mDependentOnBusinessLogic = false;
+ }
+
+ @Override
+ public List<String> getExtraBusinessLogics() {
+ // set in test/sts/tools/sts-tradefed/res/config/sts-base-dynamic-*.xml
+ String stsDynamicPlan = getBuild().getBuildAttributes().get("sts-dynamic-plan");
+ switch (stsDynamicPlan) {
+ case "incremental":
+ return StsLogic.STS_EXTRA_BUSINESS_LOGIC_INCREMENTAL;
+ case "full":
+ return StsLogic.STS_EXTRA_BUSINESS_LOGIC_FULL;
+ default:
+ throw new RuntimeException("Could not find Dynamic STS plan in build attributes");
+ }
+ }
+
+ @Override
+ public Description getTestDescription() {
+ return descriptionProvider.getDescription();
+ }
+
+ @Override
+ public LocalDate getPlatformSpl() {
+ if (deviceSpl == null) {
+ try {
+ String splString = getDevice().getProperty("ro.build.version.security_patch");
+ deviceSpl = SplUtils.localDateFromSplString(splString);
+ } catch (DeviceNotAvailableException e) {
+ throw new RuntimeException("couldn't get the security patch level", e);
+ }
+ }
+ return deviceSpl;
+ }
+
+ @Override
+ public LocalDate getKernelSpl() {
+ if (kernelSpl == null) {
+ // set in:
+ // test/sts/tools/sts-tradefed/src/com/android/tradefed/targetprep/multi/KernelSPL.java
+ String kernelSplString =
+ getBuild().getBuildAttributes().get("cts:build_version_kernel_security_patch");
+ if (kernelSplString == null) {
+ return null;
+ }
+ kernelSpl = SplUtils.localDateFromSplString(kernelSplString);
+ }
+ return kernelSpl;
+ }
+
+ @Override
+ public boolean shouldUseKernelSpl() {
+ // set in test/sts/tools/sts-tradefed/res/config/sts-base-use-kernel-spl.xml
+ String useKernelSplString = getBuild().getBuildAttributes().get("sts-use-kernel-spl");
+ return Boolean.parseBoolean(useKernelSplString);
+ }
+
+ /**
+ * Specify the latest release bulletin. Control this from the command-line with the following
+ * command line argument: --build-attribute "release-bulletin-spl=2021-06"
+ */
+ @Override
+ public LocalDate getReleaseBulletinSpl() {
+ // set manually with command-line args at runtime
+ String releaseBulletinSpl = getBuild().getBuildAttributes().get("release-bulletin-spl");
+ if (releaseBulletinSpl == null) {
+ return null;
+ }
+ // bulletin is released by month; add any day - only the year and month are compared.
+ releaseBulletinSpl =
+ String.format("%s-%02d", releaseBulletinSpl, SplUtils.Type.PARTIAL.day);
+ return SplUtils.localDateFromSplString(releaseBulletinSpl);
+ }
+
+ @Override
+ public void logInfo(String logTag, String format, Object... args) {
+ Log.i(logTag, String.format(format, args));
+ }
+
+ @Override
+ public void logDebug(String logTag, String format, Object... args) {
+ Log.d(logTag, String.format(format, args));
+ }
+
+ @Override
+ public void logWarn(String logTag, String format, Object... args) {
+ Log.w(logTag, String.format(format, args));
+ }
+
+ @Override
+ public void logError(String logTag, String format, Object... args) {
+ Log.e(logTag, String.format(format, args));
+ }
+}
diff --git a/libraries/sts-common-util/util/Android.bp b/libraries/sts-common-util/util/Android.bp
new file mode 100644
index 000000000..403dcc245
--- /dev/null
+++ b/libraries/sts-common-util/util/Android.bp
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+// Build the common utility library for use device-side
+java_library_static {
+ name: "sts-common-util-devicesidelib",
+ visibility: [
+ "//platform_testing/libraries/sts-common-util/device-side",
+ ],
+ sdk_version: "current",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "junit",
+ "platform-test-annotations",
+ "compatibility-common-util-devicesidelib",
+ ],
+}
+
+java_library {
+ name: "sts-common-util-lib",
+ visibility: [
+ "//platform_testing/libraries/sts-common-util/host-side",
+ ],
+ host_supported: true,
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "compatibility-common-util-lib",
+ ],
+ libs: [
+ "junit",
+ "platform-test-annotations",
+ ],
+}
diff --git a/libraries/sts-common-util/util/src/com/android/sts/common/util/BusinessLogicSetStore.java b/libraries/sts-common-util/util/src/com/android/sts/common/util/BusinessLogicSetStore.java
new file mode 100644
index 000000000..ea63f2326
--- /dev/null
+++ b/libraries/sts-common-util/util/src/com/android/sts/common/util/BusinessLogicSetStore.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/** Business-Logic GCL-accessible utility for sets. */
+public class BusinessLogicSetStore {
+
+ private static Map<String, Set<String>> sets = new HashMap<>();
+
+ public boolean hasSet(String setName) {
+ return sets.containsKey(setName);
+ }
+
+ public void putSet(String setName, String... elements) {
+ Set<String> set = sets.get(setName);
+ if (set == null) {
+ set = new HashSet<>();
+ sets.put(setName, set);
+ }
+
+ for (String element : elements) {
+ set.add(element);
+ }
+ }
+
+ public static Set<String> getSet(String setName) {
+ Set<String> set = sets.get(setName);
+ if (set == null) {
+ return null;
+ }
+ return Collections.unmodifiableSet(set);
+ }
+}
diff --git a/libraries/sts-common-util/util/src/com/android/sts/common/util/DescriptionProvider.java b/libraries/sts-common-util/util/src/com/android/sts/common/util/DescriptionProvider.java
new file mode 100644
index 000000000..60d46ea97
--- /dev/null
+++ b/libraries/sts-common-util/util/src/com/android/sts/common/util/DescriptionProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 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.util;
+
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+/** Provide a way for tests to get their description while running. */
+public class DescriptionProvider extends TestWatcher {
+ private volatile Description description;
+
+ @Override
+ protected void starting(Description description) {
+ this.description = description;
+ }
+
+ public Description getDescription() {
+ return description;
+ }
+}
diff --git a/libraries/sts-common-util/util/src/com/android/sts/common/util/SplUtils.java b/libraries/sts-common-util/util/src/com/android/sts/common/util/SplUtils.java
new file mode 100644
index 000000000..afb7b12af
--- /dev/null
+++ b/libraries/sts-common-util/util/src/com/android/sts/common/util/SplUtils.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 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.util;
+
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+
+/** Tools for Security Patch Levels and LocalDates representing them. */
+public final class SplUtils {
+ private static final ZoneId UTC_ZONE_ID = ZoneId.of("UTC");
+ private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+ public enum Type {
+ PARTIAL(1), // platform
+ COMPLETE(5); // device-specific (kernel, soc, etc)
+
+ public final int day;
+
+ Type(int day) {
+ this.day = day;
+ }
+ }
+
+ public static LocalDate localDateFromMillis(long millis) {
+ return Instant.ofEpochMilli(millis).atZone(UTC_ZONE_ID).toLocalDate();
+ }
+
+ public static LocalDate localDateFromSplString(String spl) {
+ return LocalDate.parse(spl, formatter);
+ }
+
+ public static String format(LocalDate date) {
+ return date.format(formatter);
+ }
+}
diff --git a/libraries/sts-common-util/util/src/com/android/sts/common/util/StsLogic.java b/libraries/sts-common-util/util/src/com/android/sts/common/util/StsLogic.java
new file mode 100644
index 000000000..35582d331
--- /dev/null
+++ b/libraries/sts-common-util/util/src/com/android/sts/common/util/StsLogic.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2021 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.util;
+
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.BusinessLogicMapStore;
+
+import org.junit.runner.Description;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Common STS extra business logic for host-side and device-side to implement. */
+public interface StsLogic {
+
+ static final String LOG_TAG = StsLogic.class.getSimpleName();
+
+ // keep in sync with google3:
+ // //wireless/android/partner/apbs/*/config/xtsbgusinesslogic/sts_business_logic.gcl
+ List<String> STS_EXTRA_BUSINESS_LOGIC_FULL = Arrays.asList(new String[] {
+ "uploadSpl",
+ "uploadModificationTime",
+ "uploadKernelBugs",
+ "declaredSpl",
+ });
+ List<String> STS_EXTRA_BUSINESS_LOGIC_INCREMENTAL = Arrays.asList(new String[] {
+ "uploadSpl",
+ "uploadModificationTime",
+ "uploadKernelBugs",
+ "declaredSpl",
+ "incremental",
+ });
+
+ Description getTestDescription();
+
+ LocalDate getPlatformSpl();
+
+ LocalDate getKernelSpl();
+
+ boolean shouldUseKernelSpl();
+
+ LocalDate getReleaseBulletinSpl();
+
+ default long[] getCveBugIds() {
+ AsbSecurityTest annotation = getTestDescription().getAnnotation(AsbSecurityTest.class);
+ if (annotation == null) {
+ return null;
+ }
+ return annotation.cveBugId();
+ }
+
+ default boolean isBugSplDataKnownMissing() {
+ long[] bugIds = getCveBugIds();
+ if (bugIds == null) {
+ // no spl data, don't complain
+ return true;
+ }
+ // true if the bug id is older than ~ June 2020
+ return Arrays.stream(bugIds).min().getAsLong() < 157905780;
+ }
+
+ default LocalDate getDeviceSpl() {
+ if (shouldUseKernelSpl()) {
+ Set<String> bugIds = BusinessLogicSetStore.getSet("kernel_bugs");
+ boolean isKernel = false;
+ for (long bugId : getCveBugIds()) {
+ isKernel |= bugIds.contains(Long.toString(bugId));
+ }
+ if (isKernel) {
+ LocalDate kernelSpl = getKernelSpl();
+ if (kernelSpl != null) {
+ return kernelSpl;
+ }
+ // could not get the kernel SPL even though we should use it
+ // falling back to platform SPL
+ logWarn(LOG_TAG, "could not read kernel SPL, falling back to platform SPL");
+ }
+ }
+ return getPlatformSpl();
+ }
+
+ default LocalDate getMinTestSpl() {
+ Map<String, String> map = BusinessLogicMapStore.getMap("security_bulletins");
+ if (map == null) {
+ throw new IllegalArgumentException("Could not find the security bulletin map");
+ }
+ LocalDate minSpl = null;
+ for (long cveBugId : getCveBugIds()) {
+ String splString = map.get(Long.toString(cveBugId));
+ if (splString == null) {
+ // This bug id wasn't found in the map.
+ // This is a new test or the bug was removed from the bulletin and this is an old
+ // binary. Neither is a critical issue and the test will run in these cases.
+ // New test: developer should be able to write the test without getting blocked.
+ // Removed bug + old binary: test will run.
+ logWarn(LOG_TAG, "could not find the CVE bug %d in the spl map", cveBugId);
+ continue;
+ }
+ LocalDate spl = SplUtils.localDateFromSplString(splString);
+ if (minSpl == null) {
+ minSpl = spl;
+ } else if (spl.isBefore(minSpl)) {
+ minSpl = spl;
+ }
+ }
+ return minSpl;
+ }
+
+ default LocalDate getMinModificationDate() {
+ Map<String, String> map = BusinessLogicMapStore.getMap("sts_modification_times");
+ if (map == null) {
+ throw new IllegalArgumentException("Could not find the modification date map");
+ }
+ LocalDate minModificationDate = null;
+ for (long cveBugId : getCveBugIds()) {
+ String modificationMillisString = map.get(Long.toString(cveBugId));
+ if (modificationMillisString == null) {
+ logInfo(
+ LOG_TAG,
+ "Could not find the CVE bug %d in the modification date map",
+ cveBugId);
+ continue;
+ }
+ LocalDate modificationDate =
+ SplUtils.localDateFromMillis(Long.parseLong(modificationMillisString));
+ if (minModificationDate == null) {
+ minModificationDate = modificationDate;
+ } else if (modificationDate.isBefore(minModificationDate)) {
+ minModificationDate = modificationDate;
+ }
+ }
+ return minModificationDate;
+ }
+
+ default boolean shouldSkipIncremental() {
+ logDebug(LOG_TAG, "filtering by incremental");
+
+ long[] bugIds = getCveBugIds();
+ if (bugIds == null) {
+ // There were no @AsbSecurityTest annotations
+ logInfo(LOG_TAG, "not an ASB test");
+ return false;
+ }
+
+ // check if test spl is older than the past 6 months from the device spl
+ LocalDate deviceSpl = getDeviceSpl();
+ LocalDate incrementalCutoffSpl = deviceSpl.plusMonths(-6);
+
+ LocalDate minTestModifiedDate = getMinModificationDate();
+ if (minTestModifiedDate == null) {
+ // could not get the modification date - run the test
+ if (isBugSplDataKnownMissing()) {
+ logDebug(LOG_TAG, "no data for this old test");
+ return true;
+ }
+ return false;
+ }
+ if (minTestModifiedDate.isAfter(incrementalCutoffSpl)) {
+ logDebug(LOG_TAG, "the test was recently modified");
+ return false;
+ }
+
+ LocalDate minTestSpl = getMinTestSpl();
+ if (minTestSpl == null) {
+ // could not get the test spl - run the test
+ logWarn(LOG_TAG, "could not get the test SPL");
+ return false;
+ }
+ if (minTestSpl.isAfter(incrementalCutoffSpl)) {
+ logDebug(LOG_TAG, "the test has a recent SPL");
+ return false;
+ }
+
+ logDebug(LOG_TAG, "test should skip");
+ return true;
+ }
+
+ default boolean shouldSkipDeclaredSpl() {
+ if (getCveBugIds() == null) {
+ // There were no @AsbSecurityTest annotations
+ logInfo(LOG_TAG, "not an ASB test");
+ return false;
+ }
+
+ LocalDate releaseBulletinSpl = getReleaseBulletinSpl();
+ LocalDate minTestSpl = getMinTestSpl();
+ if (releaseBulletinSpl != null && !isBugSplDataKnownMissing()) {
+ // assert that the test has a known SPL when we expect the data to be fresh
+ assertNotNull("Unknown SPL for new CVE", minTestSpl);
+
+ // set the days to be the same so we only compare year-month
+ releaseBulletinSpl = releaseBulletinSpl.withDayOfMonth(minTestSpl.getDayOfMonth());
+ // the test SPL can't be equal to or after the release bulletin SPL
+ assertFalse("Newer SPL than release bulletin", releaseBulletinSpl.isBefore(minTestSpl));
+ }
+ if (minTestSpl == null) {
+ // no SPL for this test; run normally
+ return false;
+ }
+
+ // skip if the test is newer than the device SPL
+ LocalDate deviceSpl = getDeviceSpl();
+ return minTestSpl.isAfter(deviceSpl);
+ }
+
+ default void skip(String message) {
+ assumeTrue(message, false);
+ }
+
+ public void logInfo(String logTag, String format, Object... args);
+
+ public void logDebug(String logTag, String format, Object... args);
+
+ public void logWarn(String logTag, String format, Object... args);
+
+ public void logError(String logTag, String format, Object... args);
+}