1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "linkerconfig/section.h"
18
19 #include <android-base/result.h>
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22
23 #include "linkerconfig/apex.h"
24 #include "linkerconfig/basecontext.h"
25 #include "linkerconfig/configwriter.h"
26 #include "modules_testbase.h"
27
28 using namespace android::linkerconfig::modules;
29
30 constexpr const char* kSectionWithNamespacesExpectedResult =
31 R"([test_section]
32 additional.namespaces = namespace1,namespace2
33 namespace.default.isolated = true
34 namespace.default.visible = true
35 namespace.default.search.paths = /search_path1
36 namespace.default.search.paths += /apex/search_path2
37 namespace.default.permitted.paths = /permitted_path1
38 namespace.default.permitted.paths += /apex/permitted_path2
39 namespace.default.asan.search.paths = /data/asan/search_path1
40 namespace.default.asan.search.paths += /search_path1
41 namespace.default.asan.search.paths += /apex/search_path2
42 namespace.default.asan.permitted.paths = /data/asan/permitted_path1
43 namespace.default.asan.permitted.paths += /permitted_path1
44 namespace.default.asan.permitted.paths += /apex/permitted_path2
45 namespace.default.links = namespace1,namespace2
46 namespace.default.link.namespace1.shared_libs = lib1.so
47 namespace.default.link.namespace1.shared_libs += lib2.so
48 namespace.default.link.namespace1.shared_libs += lib3.so
49 namespace.default.link.namespace2.allow_all_shared_libs = true
50 namespace.namespace1.isolated = false
51 namespace.namespace1.search.paths = /search_path1
52 namespace.namespace1.search.paths += /apex/search_path2
53 namespace.namespace1.permitted.paths = /permitted_path1
54 namespace.namespace1.permitted.paths += /apex/permitted_path2
55 namespace.namespace1.asan.search.paths = /data/asan/search_path1
56 namespace.namespace1.asan.search.paths += /search_path1
57 namespace.namespace1.asan.search.paths += /apex/search_path2
58 namespace.namespace1.asan.permitted.paths = /data/asan/permitted_path1
59 namespace.namespace1.asan.permitted.paths += /permitted_path1
60 namespace.namespace1.asan.permitted.paths += /apex/permitted_path2
61 namespace.namespace1.links = default,namespace2
62 namespace.namespace1.link.default.shared_libs = lib1.so
63 namespace.namespace1.link.default.shared_libs += lib2.so
64 namespace.namespace1.link.default.shared_libs += lib3.so
65 namespace.namespace1.link.namespace2.allow_all_shared_libs = true
66 namespace.namespace2.isolated = false
67 namespace.namespace2.search.paths = /search_path1
68 namespace.namespace2.search.paths += /apex/search_path2
69 namespace.namespace2.permitted.paths = /permitted_path1
70 namespace.namespace2.permitted.paths += /apex/permitted_path2
71 namespace.namespace2.asan.search.paths = /data/asan/search_path1
72 namespace.namespace2.asan.search.paths += /search_path1
73 namespace.namespace2.asan.search.paths += /apex/search_path2
74 namespace.namespace2.asan.permitted.paths = /data/asan/permitted_path1
75 namespace.namespace2.asan.permitted.paths += /permitted_path1
76 namespace.namespace2.asan.permitted.paths += /apex/permitted_path2
77 )";
78
79 constexpr const char* kSectionWithOneNamespaceExpectedResult =
80 R"([test_section]
81 namespace.default.isolated = false
82 namespace.default.search.paths = /search_path1
83 namespace.default.search.paths += /apex/search_path2
84 namespace.default.permitted.paths = /permitted_path1
85 namespace.default.permitted.paths += /apex/permitted_path2
86 namespace.default.asan.search.paths = /data/asan/search_path1
87 namespace.default.asan.search.paths += /search_path1
88 namespace.default.asan.search.paths += /apex/search_path2
89 namespace.default.asan.permitted.paths = /data/asan/permitted_path1
90 namespace.default.asan.permitted.paths += /permitted_path1
91 namespace.default.asan.permitted.paths += /apex/permitted_path2
92 )";
93
TEST(linkerconfig_section,section_with_namespaces)94 TEST(linkerconfig_section, section_with_namespaces) {
95 ConfigWriter writer;
96
97 std::vector<Namespace> namespaces;
98
99 namespaces.emplace_back(CreateNamespaceWithLinks(
100 "default", true, true, "namespace1", "namespace2"));
101 namespaces.emplace_back(CreateNamespaceWithLinks(
102 "namespace1", false, false, "default", "namespace2"));
103 namespaces.emplace_back(CreateNamespaceWithPaths("namespace2", false, false));
104
105 Section section("test_section", std::move(namespaces));
106
107 section.WriteConfig(writer);
108 auto config = writer.ToString();
109 ASSERT_EQ(kSectionWithNamespacesExpectedResult, config);
110 }
111
TEST(linkerconfig_section,section_with_one_namespace)112 TEST(linkerconfig_section, section_with_one_namespace) {
113 android::linkerconfig::modules::ConfigWriter writer;
114
115 std::vector<Namespace> namespaces;
116 namespaces.emplace_back(CreateNamespaceWithPaths("default", false, false));
117
118 Section section("test_section", std::move(namespaces));
119 section.WriteConfig(writer);
120 auto config = writer.ToString();
121 ASSERT_EQ(kSectionWithOneNamespaceExpectedResult, config);
122 }
123
TEST(linkerconfig_section,resolve_contraints)124 TEST(linkerconfig_section, resolve_contraints) {
125 BaseContext ctx;
126 std::vector<Namespace> namespaces;
127 Namespace& foo = namespaces.emplace_back("foo");
128 foo.AddProvides(std::vector{"libfoo.so"});
129 foo.AddRequires(std::vector{"libbar.so"});
130 Namespace& bar = namespaces.emplace_back("bar");
131 bar.AddProvides(std::vector{"libbar.so"});
132 Namespace& baz = namespaces.emplace_back("baz");
133 baz.AddRequires(std::vector{"libfoo.so"});
134
135 Section section("section", std::move(namespaces));
136 section.Resolve(ctx);
137
138 ConfigWriter writer;
139 section.WriteConfig(writer);
140
141 ASSERT_EQ(
142 "[section]\n"
143 "additional.namespaces = bar,baz,foo\n"
144 "namespace.bar.isolated = false\n"
145 "namespace.baz.isolated = false\n"
146 "namespace.baz.links = foo\n"
147 "namespace.baz.link.foo.shared_libs = libfoo.so\n"
148 "namespace.foo.isolated = false\n"
149 "namespace.foo.links = bar\n"
150 "namespace.foo.link.bar.shared_libs = libbar.so\n",
151 writer.ToString());
152 }
153
TEST(linkerconfig_section,error_if_duplicate_providing)154 TEST(linkerconfig_section, error_if_duplicate_providing) {
155 BaseContext ctx;
156 std::vector<Namespace> namespaces;
157 Namespace& foo1 = namespaces.emplace_back("foo1");
158 foo1.AddProvides(std::vector{"libfoo.so"});
159 Namespace& foo2 = namespaces.emplace_back("foo2");
160 foo2.AddProvides(std::vector{"libfoo.so"});
161 Namespace& bar = namespaces.emplace_back("bar");
162 bar.AddRequires(std::vector{"libfoo.so"});
163
164 Section section("section", std::move(namespaces));
165 auto result = section.Resolve(ctx);
166 ASSERT_EQ("duplicate: libfoo.so is provided by foo1 and foo2 in [section]",
167 result.error().message());
168 }
169
TEST(linkerconfig_section,error_if_no_providers_in_strict_mode)170 TEST(linkerconfig_section, error_if_no_providers_in_strict_mode) {
171 BaseContext ctx;
172 ctx.SetStrictMode(true);
173
174 std::vector<Namespace> namespaces;
175 Namespace& foo = namespaces.emplace_back("foo");
176 foo.AddRequires(std::vector{"libfoo.so"});
177
178 Section section("section", std::move(namespaces));
179 auto result = section.Resolve(ctx);
180 ASSERT_EQ("not found: libfoo.so is required by foo in [section]",
181 result.error().message());
182 }
183
TEST(linkerconfig_section,ignore_unmet_requirements)184 TEST(linkerconfig_section, ignore_unmet_requirements) {
185 BaseContext ctx;
186 ctx.SetStrictMode(false); // default
187
188 std::vector<Namespace> namespaces;
189 Namespace& foo = namespaces.emplace_back("foo");
190 foo.AddRequires(std::vector{"libfoo.so"});
191
192 Section section("section", std::move(namespaces));
193 auto result = section.Resolve(ctx);
194 ASSERT_RESULT_OK(result);
195
196 ConfigWriter writer;
197 section.WriteConfig(writer);
198
199 ASSERT_EQ(
200 "[section]\n"
201 "namespace.foo.isolated = false\n",
202 writer.ToString());
203 }
204
TEST(linkerconfig_section,resolve_section_with_apex)205 TEST(linkerconfig_section, resolve_section_with_apex) {
206 BaseContext ctx;
207 ctx.AddApexModule(ApexInfo(
208 "foo", "", {"a.so"}, {"b.so"}, {}, {}, true, true, false, false));
209 ctx.AddApexModule(
210 ApexInfo("bar", "", {"b.so"}, {}, {}, {}, true, true, false, false));
211 ctx.AddApexModule(ApexInfo(
212 "baz", "", {"c.so"}, {"a.so"}, {}, {}, true, true, false, false));
213
214 std::vector<Namespace> namespaces;
215 Namespace& default_ns = namespaces.emplace_back("default");
216 default_ns.AddRequires(std::vector{"a.so", "b.so"});
217
218 Section section("section", std::move(namespaces));
219 auto result = section.Resolve(ctx);
220
221 EXPECT_RESULT_OK(result);
222 EXPECT_THAT(
223 std::vector<std::string>{"a.so"},
224 ::testing::ContainerEq(
225 section.GetNamespace("default")->GetLink("foo").GetSharedLibs()));
226 EXPECT_THAT(
227 std::vector<std::string>{"b.so"},
228 ::testing::ContainerEq(
229 section.GetNamespace("default")->GetLink("bar").GetSharedLibs()));
230 EXPECT_THAT(std::vector<std::string>{"b.so"},
231 ::testing::ContainerEq(
232 section.GetNamespace("foo")->GetLink("bar").GetSharedLibs()));
233 EXPECT_EQ(nullptr, section.GetNamespace("baz"));
234 }
235