aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-10-13 03:30:58 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-10-13 03:30:58 +0000
commit95c4168fbc77ef775fc646d87f84a4b9970eac4a (patch)
tree04d77fef556447b08cd12a39d16b4c547a85dc0c
parent01dc038625d348fc4aebf48239fcbc8d1780114b (diff)
parent8874ecbe733278c1e30c143ec14ac2a74111c1e0 (diff)
downloadlinkerconfig-95c4168fbc77ef775fc646d87f84a4b9970eac4a.tar.gz
Snap for 10942032 from 8874ecbe733278c1e30c143ec14ac2a74111c1e0 to 24Q1-release
Change-Id: I4b5f3f92e524ed2fd6572faff91f7095605c86d8
-rw-r--r--devicetest/Android.bp39
-rw-r--r--devicetest/AndroidTest.xml28
-rw-r--r--devicetest/src/android/linkerconfig/gts/LinkerConfigTest.java235
-rw-r--r--devicetest/src/android/linkerconfig/gts/utils/LibraryListLoader.java95
-rw-r--r--devicetest/src/android/linkerconfig/gts/utils/LinkerConfigParser.java63
-rw-r--r--devicetest/src/android/linkerconfig/gts/utils/elements/Configuration.java58
-rw-r--r--devicetest/src/android/linkerconfig/gts/utils/elements/Link.java27
-rw-r--r--devicetest/src/android/linkerconfig/gts/utils/elements/Namespace.java32
-rw-r--r--devicetest/src/android/linkerconfig/gts/utils/elements/Section.java154
9 files changed, 731 insertions, 0 deletions
diff --git a/devicetest/Android.bp b/devicetest/Android.bp
new file mode 100644
index 0000000..233b5cb
--- /dev/null
+++ b/devicetest/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 Google LLC.
+ *
+ * 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_test_host {
+ name: "GtsLinkerConfigTestCases",
+ libs: [
+ "tradefed",
+ ],
+ static_libs: [
+ "hamcrest-library",
+ "compatibility-host-util",
+ ],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a gts test artifact
+ test_suites: [
+ "gts",
+ "general-tests",
+ "mts-mainline-infra",
+ ],
+}
diff --git a/devicetest/AndroidTest.xml b/devicetest/AndroidTest.xml
new file mode 100644
index 0000000..44f325d
--- /dev/null
+++ b/devicetest/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 Google LLC.
+
+ 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.
+-->
+<configuration description="Config for GTS Linkerconfig test cases">
+ <option name="test-suite-tag" value="gts" />
+ <option name="config-descriptor:metadata" key="component" value="gms" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="jar" value="GtsLinkerConfigTestCases.jar" />
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController"/>
+</configuration>
diff --git a/devicetest/src/android/linkerconfig/gts/LinkerConfigTest.java b/devicetest/src/android/linkerconfig/gts/LinkerConfigTest.java
new file mode 100644
index 0000000..e24ae18
--- /dev/null
+++ b/devicetest/src/android/linkerconfig/gts/LinkerConfigTest.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2020 Google LLC.
+ *
+ * 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 android.linkerconfig.gts;
+
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.linkerconfig.gts.utils.LibraryListLoader;
+import android.linkerconfig.gts.utils.LinkerConfigParser;
+import android.linkerconfig.gts.utils.elements.Configuration;
+import android.linkerconfig.gts.utils.elements.Namespace;
+import android.linkerconfig.gts.utils.elements.Section;
+
+import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.GmsTest;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.INativeDevice;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class LinkerConfigTest extends BaseHostJUnit4Test {
+
+ private static final String LINKER_CONFIG_LOCATION = "/linkerconfig/ld.config.txt";
+ private static final String VENDOR_VNDK_LITE = "ro.vndk.lite";
+ private static final String VENDOR_VNDK_VERSION = "ro.vndk.version";
+ private static final int TARGET_MIN_VER = 30; // linkerconfig is available from R
+
+ private static boolean isValidVersion(ITestDevice device) {
+ try {
+ return ApiLevelUtil.isAtLeast(device, TARGET_MIN_VER);
+ } catch (DeviceNotAvailableException e) {
+ fail("There is no available device : " + e.getMessage());
+ }
+
+ return false;
+ }
+
+ private static Configuration loadConfig(INativeDevice targetDevice, String path) {
+ File target = null;
+
+ try {
+ target = targetDevice.pullFile(path);
+ } catch (DeviceNotAvailableException e) {
+ fail("There is no available device : " + e.getMessage());
+ }
+
+ assertTrue("Failed to get linker configuration from expected location",
+ target.exists());
+
+ List<String> lines = new ArrayList<>();
+ try (BufferedReader reader = new BufferedReader(new FileReader(target))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (!line.isEmpty()) {
+ lines.add(line);
+ }
+ }
+ } catch (Exception e) {
+ fail("Failed to read file " + path + " with error : " + e.getMessage());
+ }
+
+ return LinkerConfigParser.parseConfiguration(lines);
+ }
+
+ private static void verifyVendorSection(Section section, Set<String> systemAvailableLibraries) {
+ List<Namespace> systemNamespaces = section.namespaces.values().stream()
+ .filter(ns -> ns.searchPaths.stream()
+ .anyMatch(searchPath -> searchPath.startsWith("/system")
+ && !searchPath.startsWith("/system/vendor")))
+ .distinct()
+ .collect(Collectors.toList());
+
+ assertFalse("System namespace should not be visible",
+ systemNamespaces.parallelStream().anyMatch(ns -> ns.isVisible));
+
+ section.namespaces.values().forEach((ns) -> {
+ boolean isVendorNamespace = false;
+ for (String libPath : ns.searchPaths) {
+ if (libPath.startsWith(("/vendor")) || libPath.startsWith("/odm")) {
+ isVendorNamespace = true;
+ break;
+ }
+ }
+
+ if (!isVendorNamespace) {
+ return;
+ }
+
+ assertThat(
+ "Vendor libs and System libs should not exist in same namespace : " + ns.name,
+ systemNamespaces, not(contains(ns)));
+
+ ns.links.values().forEach((link) -> {
+ if (systemNamespaces.contains(link.to)) {
+ assertFalse(
+ "It is not allowed to link all shared libs from non-system namespace "
+ + link.from
+ + "to system namespace " + link.to,
+ link.allowAll);
+
+ link.libraries.forEach(library -> {
+ assertTrue("Library " + library + " is not allowed to use",
+ systemAvailableLibraries.contains(library));
+ });
+ }
+ });
+ });
+ }
+
+
+ private static Set<String> loadSystemAvailableLibraries(INativeDevice targetDevice,
+ String vendorVndkVersion) {
+ Set<String> libraries = new HashSet<>();
+
+ // Add Sanitizer libraries
+ libraries.addAll(LibraryListLoader.getLibrariesFromFile(targetDevice,
+ "/system/etc/sanitizer.libraries.txt", true));
+
+ // Add LLNDK libraries
+ libraries.addAll(LibraryListLoader.getLibrariesFromFile(targetDevice,
+ "/apex/com.android.vndk.v" + vendorVndkVersion + "/etc/llndk.libraries."
+ + vendorVndkVersion + ".txt", true));
+
+ // Add Stub libraries
+ libraries.addAll(LibraryListLoader.STUB_LIBRARIES);
+
+ // Allowed on userdebug/eng for debugging.
+ libraries.add("libfdtrack.so");
+
+ // Add VNDK core variant libraries
+ libraries.addAll(LibraryListLoader.getLibrariesFromFile(targetDevice,
+ "/system/etc/vndkcorevariant.libraries.txt", false));
+
+ return libraries;
+ }
+
+ @GmsTest(requirement = "GMS-3.5-014")
+ @Test
+ public void shouldHaveLinkerConfigAtExpectedLocation() {
+ ITestDevice targetDevice = getDevice();
+
+ if (!isValidVersion(targetDevice)) {
+ return;
+ }
+
+ try {
+ File linkerConfigFile = targetDevice.pullFile(LINKER_CONFIG_LOCATION);
+ assertTrue("Failed to get linker configuration from expected location",
+ linkerConfigFile.exists());
+ } catch (DeviceNotAvailableException e) {
+ fail("Target device is not available : " + e.getMessage());
+ }
+ }
+
+ @GmsTest(requirement = "GMS-3.5-014")
+ @Test
+ public void shouldNotAccessSystemFromVendorExceptVndk() {
+ ITestDevice targetDevice = getDevice();
+ boolean vndkLiteEnabled = false;
+
+ try {
+ vndkLiteEnabled = Boolean.parseBoolean(targetDevice.getProperty(VENDOR_VNDK_LITE));
+ } catch (DeviceNotAvailableException e) {
+ fail("Target device is not available : " + e.getMessage());
+ }
+
+ if (!isValidVersion(targetDevice) || vndkLiteEnabled) {
+ return;
+ }
+
+ String vendorVndkVersion = "";
+ try {
+ vendorVndkVersion = targetDevice.getProperty(VENDOR_VNDK_VERSION);
+ } catch (DeviceNotAvailableException e) {
+ fail("Target device is not available : " + e.getMessage());
+ }
+
+ if (vendorVndkVersion == null || vendorVndkVersion.isEmpty()) {
+ return;
+ }
+
+ Configuration conf = loadConfig(targetDevice, LINKER_CONFIG_LOCATION);
+
+ List<Section> vendorSections = conf.dirToSections.entrySet().stream()
+ .filter(item -> item.getKey().startsWith("/vendor") || item.getKey().startsWith(
+ ("/odm")))
+ .map(Map.Entry::getValue)
+ .distinct()
+ .collect(Collectors.toList());
+
+ assertThat("No section for vendor", vendorSections, not(empty()));
+
+ Set<String> availableLibraries = loadSystemAvailableLibraries(targetDevice,
+ vendorVndkVersion);
+
+ for (Section section : vendorSections) {
+ verifyVendorSection(section, availableLibraries);
+ }
+ }
+}
diff --git a/devicetest/src/android/linkerconfig/gts/utils/LibraryListLoader.java b/devicetest/src/android/linkerconfig/gts/utils/LibraryListLoader.java
new file mode 100644
index 0000000..c12a7c3
--- /dev/null
+++ b/devicetest/src/android/linkerconfig/gts/utils/LibraryListLoader.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 Google LLC.
+ *
+ * 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 android.linkerconfig.gts.utils;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.INativeDevice;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class LibraryListLoader {
+ public static List<String> getLibrariesFromFile(INativeDevice targetDevice,
+ String path, boolean expectFileExists) {
+ List<String> libraries = new ArrayList<>();
+
+ File target = null;
+
+ try {
+ target = targetDevice.pullFile(path);
+ } catch (DeviceNotAvailableException e) {
+ fail("There is no available device : " + e.getMessage());
+ }
+
+ assertTrue("Failed to get library list file from " + path,
+ target.exists() || !expectFileExists);
+
+ if (target.exists()) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(target))) {
+ String library;
+ while ((library = reader.readLine()) != null) {
+ library = library.trim();
+ if (!library.isEmpty()) {
+ libraries.add(library);
+ }
+ }
+ } catch (Exception e) {
+ fail("Failed to read file " + path + " with error : " + e.getMessage());
+ }
+ }
+
+ return libraries;
+ }
+
+ public static final List<String> STUB_LIBRARIES = Arrays.asList("libEGL.so",
+ "libGLESv1_CM.so",
+ "libGLESv2.so",
+ "libGLESv3.so",
+ "libRS.so",
+ "libaaudio.so",
+ "libadbd_auth.so",
+ "libadbd_fs.so",
+ "libandroid.so",
+ "libandroid_net.so",
+ "libbinder_ndk.so",
+ "libc.so",
+ "libcgrouprc.so",
+ "libclang_rt.asan-arm-android.so",
+ "libclang_rt.asan-i686-android.so",
+ "libclang_rt.asan-x86_64-android.so",
+ "libdl.so",
+ "libdl_android.so",
+ "libft2.so",
+ "libincident.so",
+ "liblog.so",
+ "libm.so",
+ "libmediametrics.so",
+ "libmediandk.so",
+ "libnativewindow.so",
+ "libneuralnetworks_packageinfo.so",
+ "libsync.so",
+ "libvndksupport.so",
+ "libvulkan.so",
+ "libselinux.so");
+}
diff --git a/devicetest/src/android/linkerconfig/gts/utils/LinkerConfigParser.java b/devicetest/src/android/linkerconfig/gts/utils/LinkerConfigParser.java
new file mode 100644
index 0000000..a1db499
--- /dev/null
+++ b/devicetest/src/android/linkerconfig/gts/utils/LinkerConfigParser.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 Google LLC.
+ *
+ * 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 android.linkerconfig.gts.utils;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.linkerconfig.gts.utils.elements.Configuration;
+import android.linkerconfig.gts.utils.elements.Section;
+
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LinkerConfigParser {
+ static final String REGEX_SECTION_NAME = "\\[\\s*(\\w+)\\s*\\]";
+ static Pattern sSectionNamePattern = Pattern.compile(REGEX_SECTION_NAME);
+
+ public static Configuration parseConfiguration(List<String> contents) {
+ Configuration configuration = new Configuration();
+ Section currentSection = null;
+
+ for (String content : contents) {
+ if (content.isEmpty()) {
+ continue;
+ }
+
+ Matcher sectionNameMatcher = sSectionNamePattern.matcher(content);
+ if (sectionNameMatcher.matches()) {
+ String sectionName = sectionNameMatcher.group(1);
+ assertTrue("Section should have been defined from dir to section map",
+ configuration.sections.containsKey(sectionName));
+ currentSection = configuration.getSectionFromName(sectionName);
+ continue;
+ }
+
+ if (currentSection == null && configuration.parseConfiguration(content)) {
+ continue;
+ }
+
+ assertNotNull("This line cannot be parsed without section : " + content,
+ currentSection);
+
+ currentSection.parseConfiguration(content);
+ }
+
+ return configuration;
+ }
+}
diff --git a/devicetest/src/android/linkerconfig/gts/utils/elements/Configuration.java b/devicetest/src/android/linkerconfig/gts/utils/elements/Configuration.java
new file mode 100644
index 0000000..9ee3278
--- /dev/null
+++ b/devicetest/src/android/linkerconfig/gts/utils/elements/Configuration.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 Google LLC.
+ *
+ * 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 android.linkerconfig.gts.utils.elements;
+
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Configuration {
+ private static final String REGEX_DIR_TO_SECTION = "dir\\.(\\w+)\\s*=\\s([\\w.\\-/]+)";
+ private Pattern mDirToSectionPattern = Pattern.compile(REGEX_DIR_TO_SECTION);
+
+ public Map<String, Section> sections = new HashMap<>();
+ public Map<String, Section> dirToSections = new HashMap<>();
+
+ public Section getSectionFromName(String name) {
+ if (sections.containsKey(name)) {
+ return sections.get(name);
+ }
+
+ Section s = new Section();
+ s.name = name;
+ sections.put(name, s);
+
+ return s;
+ }
+
+ public boolean parseConfiguration(String dirDefinition) {
+ Matcher dirToSectionMatcher = mDirToSectionPattern.matcher(dirDefinition);
+
+ if (!dirToSectionMatcher.matches()) {
+ return false;
+ }
+
+ String sectionName = dirToSectionMatcher.group(1);
+ String dirPath = dirToSectionMatcher.group(2);
+ Section section = getSectionFromName(sectionName);
+ dirToSections.put(dirPath, section);
+
+ return true;
+ }
+}
diff --git a/devicetest/src/android/linkerconfig/gts/utils/elements/Link.java b/devicetest/src/android/linkerconfig/gts/utils/elements/Link.java
new file mode 100644
index 0000000..045b47b
--- /dev/null
+++ b/devicetest/src/android/linkerconfig/gts/utils/elements/Link.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 Google LLC.
+ *
+ * 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 android.linkerconfig.gts.utils.elements;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Link {
+ public Namespace from, to;
+ public List<String> libraries = new ArrayList<>();
+ public boolean allowAll;
+}
diff --git a/devicetest/src/android/linkerconfig/gts/utils/elements/Namespace.java b/devicetest/src/android/linkerconfig/gts/utils/elements/Namespace.java
new file mode 100644
index 0000000..25649e1
--- /dev/null
+++ b/devicetest/src/android/linkerconfig/gts/utils/elements/Namespace.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 Google LLC.
+ *
+ * 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 android.linkerconfig.gts.utils.elements;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Namespace {
+ public String name;
+ public boolean isVisible;
+ public boolean isIsolated;
+
+ public List<String> searchPaths = new ArrayList<>();
+ public List<String> permittedPaths = new ArrayList<>();
+ public Map<String, Link> links = new HashMap<>();
+}
diff --git a/devicetest/src/android/linkerconfig/gts/utils/elements/Section.java b/devicetest/src/android/linkerconfig/gts/utils/elements/Section.java
new file mode 100644
index 0000000..a63b1aa
--- /dev/null
+++ b/devicetest/src/android/linkerconfig/gts/utils/elements/Section.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 Google LLC.
+ *
+ * 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 android.linkerconfig.gts.utils.elements;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Section {
+ public Section() {
+ Namespace defaultNamespace = new Namespace();
+ defaultNamespace.name = "default";
+
+ namespaces.put("default", defaultNamespace);
+ }
+
+ static final String REGEX_ADDITIONAL_NAMESPACES =
+ "additional\\.namespaces\\s*=\\s*((?:[\\w]+)(?:,[\\w]+)*)";
+ static final String REGEX_NAMESPACE =
+ "namespace\\.(\\w+)\\.([^\\s=]+)\\s*(?:=|\\+=)\\s*([^\\s]+)";
+
+ static Pattern sAdditionalNamespacesPattern = Pattern.compile(REGEX_ADDITIONAL_NAMESPACES);
+ static Pattern sNamespacePattern = Pattern.compile(REGEX_NAMESPACE);
+
+ public String name;
+ public Map<String, Namespace> namespaces = new HashMap<>();
+
+
+ public Namespace getNamespaceFromName(String namespace) {
+ assertTrue("Failed to find namespace " + namespace + " from section " + name,
+ namespaces.containsKey(namespace));
+
+ return namespaces.get(namespace);
+ }
+
+ public void parseConfiguration(String line) {
+ Matcher additionalNamespacesMatcher = sAdditionalNamespacesPattern.matcher(line);
+ if (additionalNamespacesMatcher.matches()) {
+ assertEquals("Additional namespaces are already defined.", 1, namespaces.size());
+ String additionalNamespaces = additionalNamespacesMatcher.group(1);
+ for (String additionalNamespace : additionalNamespaces.split(",")) {
+ Namespace ns = new Namespace();
+ ns.name = additionalNamespace;
+ namespaces.put(additionalNamespace, ns);
+ }
+
+ return;
+ }
+
+ Matcher namespaceMatcher = sNamespacePattern.matcher(line);
+ assertTrue("Cannot parse : " + line, namespaceMatcher.matches());
+
+ String targetNamespace = namespaceMatcher.group(1);
+ String[] commands = namespaceMatcher.group(2).split("\\.");
+ String value = namespaceMatcher.group(3);
+
+ assertTrue("Cannot find namespace " + targetNamespace,
+ namespaces.containsKey(targetNamespace));
+
+ Namespace ns = getNamespaceFromName(targetNamespace);
+
+ assertTrue("Invalid command : " + namespaceMatcher.group(2) + " from " + line,
+ commands.length > 0);
+ switch (commands[0]) {
+ case "isolated":
+ assertEquals("Invalid command : " + line, 1, commands.length);
+ ns.isIsolated = Boolean.parseBoolean(value);
+ return;
+ case "visible":
+ assertEquals("Invalid command : " + line, 1, commands.length);
+ ns.isVisible = Boolean.parseBoolean(value);
+ return;
+ case "search":
+ assertEquals("Invalid command : " + line, 2, commands.length);
+ assertEquals("Invalid command : " + line, "paths", commands[1]);
+ if (!value.isEmpty()) {
+ ns.searchPaths.add(value);
+ }
+ return;
+ case "permitted":
+ assertEquals("Invalid command : " + line, 2, commands.length);
+ assertEquals("Invalid command : " + line, "paths", commands[1]);
+ if (!value.isEmpty()) {
+ ns.permittedPaths.add(value);
+ }
+ return;
+ case "asan":
+ case "hwasan":
+ // Do not parse configuration for hwasan or asan in this test
+ assertEquals("Invalid command : " + line, 3, commands.length);
+ assertTrue("Invalid command : " + line,
+ commands[1].equals("search") || commands[1].equals("permitted"));
+ assertEquals("Invalid command : " + line, "paths", commands[2]);
+ return;
+ case "links":
+ assertEquals("Invalid command : " + line, 1, commands.length);
+ for (String linkTarget : value.split(",")) {
+ assertTrue("Invalid target namespace : " + linkTarget + " from " + line,
+ namespaces.containsKey(linkTarget));
+ Link link = new Link();
+ link.from = ns;
+ link.to = getNamespaceFromName(linkTarget);
+ ns.links.put(linkTarget, link);
+ }
+ return;
+ case "link":
+ assertEquals("Invalid command : " + line, 3, commands.length);
+ String linkTarget = commands[1];
+ assertTrue("Link not defined : " + linkTarget + " from " + line,
+ ns.links.containsKey(linkTarget));
+ Link link = ns.links.get(linkTarget);
+
+ if (commands[2].equals("allow_all_shared_libs")) {
+ link.allowAll = Boolean.parseBoolean(value);
+ } else if (commands[2].equals("shared_libs")) {
+ String[] libs = value.split(":");
+ for (String lib : libs) {
+ link.libraries.add(lib);
+ }
+ } else {
+ fail("Invalid link command : " + line);
+ }
+ return;
+ case "whitelisted":
+ case "allowed_libs":
+ assertEquals("Invalid command : " + line, 1, commands.length);
+ // Do not parse allowed library list in this test
+ return;
+ }
+
+
+ fail("Unable to parse command : " + line);
+ return;
+ }
+}