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 "apex_testbase.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 += /search_path2
37 namespace.default.search.paths += /search_path3
38 namespace.default.permitted.paths = /permitted_path1
39 namespace.default.permitted.paths += /permitted_path2
40 namespace.default.permitted.paths += /permitted_path3
41 namespace.default.asan.search.paths = /data/asan/search_path1
42 namespace.default.asan.search.paths += /search_path1
43 namespace.default.asan.search.paths += /search_path2
44 namespace.default.asan.permitted.paths = /data/asan/permitted_path1
45 namespace.default.asan.permitted.paths += /permitted_path1
46 namespace.default.asan.permitted.paths += /permitted_path2
47 namespace.default.links = namespace1,namespace2
48 namespace.default.link.namespace1.shared_libs = lib1.so
49 namespace.default.link.namespace1.shared_libs += lib2.so
50 namespace.default.link.namespace1.shared_libs += lib3.so
51 namespace.default.link.namespace2.allow_all_shared_libs = true
52 namespace.namespace1.isolated = false
53 namespace.namespace1.search.paths = /search_path1
54 namespace.namespace1.search.paths += /search_path2
55 namespace.namespace1.search.paths += /search_path3
56 namespace.namespace1.permitted.paths = /permitted_path1
57 namespace.namespace1.permitted.paths += /permitted_path2
58 namespace.namespace1.permitted.paths += /permitted_path3
59 namespace.namespace1.asan.search.paths = /data/asan/search_path1
60 namespace.namespace1.asan.search.paths += /search_path1
61 namespace.namespace1.asan.search.paths += /search_path2
62 namespace.namespace1.asan.permitted.paths = /data/asan/permitted_path1
63 namespace.namespace1.asan.permitted.paths += /permitted_path1
64 namespace.namespace1.asan.permitted.paths += /permitted_path2
65 namespace.namespace1.links = default,namespace2
66 namespace.namespace1.link.default.shared_libs = lib1.so
67 namespace.namespace1.link.default.shared_libs += lib2.so
68 namespace.namespace1.link.default.shared_libs += lib3.so
69 namespace.namespace1.link.namespace2.allow_all_shared_libs = true
70 namespace.namespace2.isolated = false
71 namespace.namespace2.search.paths = /search_path1
72 namespace.namespace2.search.paths += /search_path2
73 namespace.namespace2.search.paths += /search_path3
74 namespace.namespace2.permitted.paths = /permitted_path1
75 namespace.namespace2.permitted.paths += /permitted_path2
76 namespace.namespace2.permitted.paths += /permitted_path3
77 namespace.namespace2.asan.search.paths = /data/asan/search_path1
78 namespace.namespace2.asan.search.paths += /search_path1
79 namespace.namespace2.asan.search.paths += /search_path2
80 namespace.namespace2.asan.permitted.paths = /data/asan/permitted_path1
81 namespace.namespace2.asan.permitted.paths += /permitted_path1
82 namespace.namespace2.asan.permitted.paths += /permitted_path2
83 )";
84
85 constexpr const char* kSectionWithOneNamespaceExpectedResult =
86 R"([test_section]
87 namespace.default.isolated = false
88 namespace.default.search.paths = /search_path1
89 namespace.default.search.paths += /search_path2
90 namespace.default.search.paths += /search_path3
91 namespace.default.permitted.paths = /permitted_path1
92 namespace.default.permitted.paths += /permitted_path2
93 namespace.default.permitted.paths += /permitted_path3
94 namespace.default.asan.search.paths = /data/asan/search_path1
95 namespace.default.asan.search.paths += /search_path1
96 namespace.default.asan.search.paths += /search_path2
97 namespace.default.asan.permitted.paths = /data/asan/permitted_path1
98 namespace.default.asan.permitted.paths += /permitted_path1
99 namespace.default.asan.permitted.paths += /permitted_path2
100 )";
101
TEST(linkerconfig_section,section_with_namespaces)102 TEST(linkerconfig_section, section_with_namespaces) {
103 ConfigWriter writer;
104
105 std::vector<Namespace> namespaces;
106
107 namespaces.emplace_back(CreateNamespaceWithLinks(
108 "default", true, true, "namespace1", "namespace2"));
109 namespaces.emplace_back(CreateNamespaceWithLinks(
110 "namespace1", false, false, "default", "namespace2"));
111 namespaces.emplace_back(CreateNamespaceWithPaths("namespace2", false, false));
112
113 Section section("test_section", std::move(namespaces));
114
115 section.WriteConfig(writer);
116 auto config = writer.ToString();
117 ASSERT_EQ(kSectionWithNamespacesExpectedResult, config);
118 }
119
TEST(linkerconfig_section,section_with_one_namespace)120 TEST(linkerconfig_section, section_with_one_namespace) {
121 android::linkerconfig::modules::ConfigWriter writer;
122
123 std::vector<Namespace> namespaces;
124 namespaces.emplace_back(CreateNamespaceWithPaths("default", false, false));
125
126 Section section("test_section", std::move(namespaces));
127 section.WriteConfig(writer);
128 auto config = writer.ToString();
129 ASSERT_EQ(kSectionWithOneNamespaceExpectedResult, config);
130 }
131
TEST(linkerconfig_section,resolve_contraints)132 TEST(linkerconfig_section, resolve_contraints) {
133 BaseContext ctx;
134 std::vector<Namespace> namespaces;
135 Namespace& foo = namespaces.emplace_back("foo");
136 foo.AddProvides(std::vector{"libfoo.so"});
137 foo.AddRequires(std::vector{"libbar.so"});
138 Namespace& bar = namespaces.emplace_back("bar");
139 bar.AddProvides(std::vector{"libbar.so"});
140 Namespace& baz = namespaces.emplace_back("baz");
141 baz.AddRequires(std::vector{"libfoo.so"});
142
143 Section section("section", std::move(namespaces));
144 section.Resolve(ctx);
145
146 ConfigWriter writer;
147 section.WriteConfig(writer);
148
149 ASSERT_EQ(
150 "[section]\n"
151 "additional.namespaces = bar,baz,foo\n"
152 "namespace.bar.isolated = false\n"
153 "namespace.baz.isolated = false\n"
154 "namespace.baz.links = foo\n"
155 "namespace.baz.link.foo.shared_libs = libfoo.so\n"
156 "namespace.foo.isolated = false\n"
157 "namespace.foo.links = bar\n"
158 "namespace.foo.link.bar.shared_libs = libbar.so\n",
159 writer.ToString());
160 }
161
TEST(linkerconfig_section,error_if_duplicate_providing)162 TEST(linkerconfig_section, error_if_duplicate_providing) {
163 BaseContext ctx;
164 std::vector<Namespace> namespaces;
165 Namespace& foo1 = namespaces.emplace_back("foo1");
166 foo1.AddProvides(std::vector{"libfoo.so"});
167 Namespace& foo2 = namespaces.emplace_back("foo2");
168 foo2.AddProvides(std::vector{"libfoo.so"});
169 Namespace& bar = namespaces.emplace_back("bar");
170 bar.AddRequires(std::vector{"libfoo.so"});
171
172 Section section("section", std::move(namespaces));
173 auto result = section.Resolve(ctx);
174 ASSERT_EQ("duplicate: libfoo.so is provided by foo1 and foo2 in [section]",
175 result.error().message());
176 }
177
TEST(linkerconfig_section,error_if_no_providers_in_strict_mode)178 TEST(linkerconfig_section, error_if_no_providers_in_strict_mode) {
179 BaseContext ctx;
180 ctx.SetStrictMode(true);
181
182 std::vector<Namespace> namespaces;
183 Namespace& foo = namespaces.emplace_back("foo");
184 foo.AddRequires(std::vector{"libfoo.so"});
185
186 Section section("section", std::move(namespaces));
187 auto result = section.Resolve(ctx);
188 ASSERT_EQ("not found: libfoo.so is required by foo in [section]",
189 result.error().message());
190 }
191
TEST(linkerconfig_section,ignore_unmet_requirements)192 TEST(linkerconfig_section, ignore_unmet_requirements) {
193 BaseContext ctx;
194 ctx.SetStrictMode(false); // default
195
196 std::vector<Namespace> namespaces;
197 Namespace& foo = namespaces.emplace_back("foo");
198 foo.AddRequires(std::vector{"libfoo.so"});
199
200 Section section("section", std::move(namespaces));
201 auto result = section.Resolve(ctx);
202 ASSERT_RESULT_OK(result);
203
204 ConfigWriter writer;
205 section.WriteConfig(writer);
206
207 ASSERT_EQ(
208 "[section]\n"
209 "namespace.foo.isolated = false\n",
210 writer.ToString());
211 }
212
TEST_F(ApexTest,resolve_section_with_apex)213 TEST_F(ApexTest, resolve_section_with_apex) {
214 BaseContext ctx;
215 ctx.AddApexModule(PrepareApex("foo", {"a.so"}, {"b.so"}));
216 ctx.AddApexModule(PrepareApex("bar", {"b.so"}, {}));
217 ctx.AddApexModule(PrepareApex("baz", {"c.so"}, {"a.so"}));
218
219 std::vector<Namespace> namespaces;
220 Namespace& default_ns = namespaces.emplace_back("default");
221 default_ns.AddRequires(std::vector{"a.so", "b.so"});
222
223 Section section("section", std::move(namespaces));
224 auto result = section.Resolve(ctx);
225
226 EXPECT_RESULT_OK(result);
227 EXPECT_THAT(
228 std::vector<std::string>{"a.so"},
229 ::testing::ContainerEq(
230 section.GetNamespace("default")->GetLink("foo").GetSharedLibs()));
231 EXPECT_THAT(
232 std::vector<std::string>{"b.so"},
233 ::testing::ContainerEq(
234 section.GetNamespace("default")->GetLink("bar").GetSharedLibs()));
235 EXPECT_THAT(std::vector<std::string>{"b.so"},
236 ::testing::ContainerEq(
237 section.GetNamespace("foo")->GetLink("bar").GetSharedLibs()));
238 EXPECT_EQ(nullptr, section.GetNamespace("baz"));
239 }
240