1 /*
2  * Copyright (C) 2015 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 "link/ReferenceLinker.h"
18 
19 #include "test/Test.h"
20 
21 using ::android::ResTable_map;
22 using ::testing::Eq;
23 using ::testing::IsNull;
24 using ::testing::NotNull;
25 
26 namespace aapt {
27 
TEST(ReferenceLinkerTest,LinkSimpleReferences)28 TEST(ReferenceLinkerTest, LinkSimpleReferences) {
29   std::unique_ptr<ResourceTable> table =
30       test::ResourceTableBuilder()
31           .SetPackageId("com.app.test", 0x7f)
32           .AddReference("com.app.test:string/foo", ResourceId(0x7f020000),
33                         "com.app.test:string/bar")
34 
35           // Test use of local reference (w/o package name).
36           .AddReference("com.app.test:string/bar", ResourceId(0x7f020001),
37                         "string/baz")
38 
39           .AddReference("com.app.test:string/baz", ResourceId(0x7f020002),
40                         "android:string/ok")
41           .Build();
42 
43   std::unique_ptr<IAaptContext> context =
44       test::ContextBuilder()
45           .SetCompilationPackage("com.app.test")
46           .SetPackageId(0x7f)
47           .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
48           .AddSymbolSource(
49               util::make_unique<ResourceTableSymbolSource>(table.get()))
50           .AddSymbolSource(
51               test::StaticSymbolSourceBuilder()
52                   .AddPublicSymbol("android:string/ok", ResourceId(0x01040034))
53                   .Build())
54           .Build();
55 
56   ReferenceLinker linker;
57   ASSERT_TRUE(linker.Consume(context.get(), table.get()));
58 
59   Reference* ref = test::GetValue<Reference>(table.get(), "com.app.test:string/foo");
60   ASSERT_THAT(ref, NotNull());
61   ASSERT_TRUE(ref->id);
62   EXPECT_EQ(ResourceId(0x7f020001), ref->id.value());
63 
64   ref = test::GetValue<Reference>(table.get(), "com.app.test:string/bar");
65   ASSERT_THAT(ref, NotNull());
66   ASSERT_TRUE(ref->id);
67   EXPECT_EQ(ResourceId(0x7f020002), ref->id.value());
68 
69   ref = test::GetValue<Reference>(table.get(), "com.app.test:string/baz");
70   ASSERT_THAT(ref, NotNull());
71   ASSERT_TRUE(ref->id);
72   EXPECT_EQ(ResourceId(0x01040034), ref->id.value());
73 }
74 
TEST(ReferenceLinkerTest,LinkStyleAttributes)75 TEST(ReferenceLinkerTest, LinkStyleAttributes) {
76   std::unique_ptr<ResourceTable> table =
77       test::ResourceTableBuilder()
78           .SetPackageId("com.app.test", 0x7f)
79           .AddValue("com.app.test:style/Theme",
80                     test::StyleBuilder()
81                         .SetParent("android:style/Theme.Material")
82                         .AddItem("android:attr/foo",
83                                  ResourceUtils::TryParseColor("#ff00ff"))
84                         .AddItem("android:attr/bar", {} /* placeholder */)
85                         .Build())
86           .Build();
87 
88   {
89     // We need to fill in the value for the attribute android:attr/bar after we
90     // build the table, because we need access to the string pool.
91     Style* style = test::GetValue<Style>(table.get(), "com.app.test:style/Theme");
92     ASSERT_THAT(style, NotNull());
93     style->entries.back().value =
94         util::make_unique<RawString>(table->string_pool.MakeRef("one|two"));
95   }
96 
97   std::unique_ptr<IAaptContext> context =
98       test::ContextBuilder()
99           .SetCompilationPackage("com.app.test")
100           .SetPackageId(0x7f)
101           .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
102           .AddSymbolSource(
103               test::StaticSymbolSourceBuilder()
104                   .AddPublicSymbol("android:style/Theme.Material",
105                                    ResourceId(0x01060000))
106                   .AddPublicSymbol("android:attr/foo", ResourceId(0x01010001),
107                                    test::AttributeBuilder()
108                                        .SetTypeMask(ResTable_map::TYPE_COLOR)
109                                        .Build())
110                   .AddPublicSymbol("android:attr/bar", ResourceId(0x01010002),
111                                    test::AttributeBuilder()
112                                        .SetTypeMask(ResTable_map::TYPE_FLAGS)
113                                        .AddItem("one", 0x01)
114                                        .AddItem("two", 0x02)
115                                        .Build())
116                   .Build())
117           .Build();
118 
119   ReferenceLinker linker;
120   ASSERT_TRUE(linker.Consume(context.get(), table.get()));
121 
122   Style* style = test::GetValue<Style>(table.get(), "com.app.test:style/Theme");
123   ASSERT_THAT(style, NotNull());
124   ASSERT_TRUE(style->parent);
125   ASSERT_TRUE(style->parent.value().id);
126   EXPECT_EQ(ResourceId(0x01060000), style->parent.value().id.value());
127 
128   ASSERT_EQ(2u, style->entries.size());
129 
130   ASSERT_TRUE(style->entries[0].key.id);
131   EXPECT_EQ(ResourceId(0x01010001), style->entries[0].key.id.value());
132   ASSERT_THAT(ValueCast<BinaryPrimitive>(style->entries[0].value.get()), NotNull());
133 
134   ASSERT_TRUE(style->entries[1].key.id);
135   EXPECT_EQ(ResourceId(0x01010002), style->entries[1].key.id.value());
136   ASSERT_THAT(ValueCast<BinaryPrimitive>(style->entries[1].value.get()), NotNull());
137 }
138 
TEST(ReferenceLinkerTest,LinkMangledReferencesAndAttributes)139 TEST(ReferenceLinkerTest, LinkMangledReferencesAndAttributes) {
140   std::unique_ptr<IAaptContext> context =
141       test::ContextBuilder()
142           .SetCompilationPackage("com.app.test")
143           .SetPackageId(0x7f)
144           .SetNameManglerPolicy(
145               NameManglerPolicy{"com.app.test", {"com.android.support"}})
146           .AddSymbolSource(
147               test::StaticSymbolSourceBuilder()
148                   .AddPublicSymbol("com.app.test:attr/com.android.support$foo",
149                                    ResourceId(0x7f010000),
150                                    test::AttributeBuilder()
151                                        .SetTypeMask(ResTable_map::TYPE_COLOR)
152                                        .Build())
153                   .Build())
154           .Build();
155 
156   std::unique_ptr<ResourceTable> table =
157       test::ResourceTableBuilder()
158           .SetPackageId("com.app.test", 0x7f)
159           .AddValue("com.app.test:style/Theme", ResourceId(0x7f020000),
160                     test::StyleBuilder()
161                         .AddItem("com.android.support:attr/foo",
162                                  ResourceUtils::TryParseColor("#ff0000"))
163                         .Build())
164           .Build();
165 
166   ReferenceLinker linker;
167   ASSERT_TRUE(linker.Consume(context.get(), table.get()));
168 
169   Style* style = test::GetValue<Style>(table.get(), "com.app.test:style/Theme");
170   ASSERT_THAT(style, NotNull());
171   ASSERT_EQ(1u, style->entries.size());
172   ASSERT_TRUE(style->entries.front().key.id);
173   EXPECT_EQ(ResourceId(0x7f010000), style->entries.front().key.id.value());
174 }
175 
TEST(ReferenceLinkerTest,FailToLinkPrivateSymbols)176 TEST(ReferenceLinkerTest, FailToLinkPrivateSymbols) {
177   std::unique_ptr<ResourceTable> table =
178       test::ResourceTableBuilder()
179           .SetPackageId("com.app.test", 0x7f)
180           .AddReference("com.app.test:string/foo", ResourceId(0x7f020000),
181                         "android:string/hidden")
182           .Build();
183 
184   std::unique_ptr<IAaptContext> context =
185       test::ContextBuilder()
186           .SetCompilationPackage("com.app.test")
187           .SetPackageId(0x7f)
188           .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
189           .AddSymbolSource(
190               util::make_unique<ResourceTableSymbolSource>(table.get()))
191           .AddSymbolSource(
192               test::StaticSymbolSourceBuilder()
193                   .AddSymbol("android:string/hidden", ResourceId(0x01040034))
194                   .Build())
195           .Build();
196 
197   ReferenceLinker linker;
198   ASSERT_FALSE(linker.Consume(context.get(), table.get()));
199 }
200 
TEST(ReferenceLinkerTest,FailToLinkPrivateMangledSymbols)201 TEST(ReferenceLinkerTest, FailToLinkPrivateMangledSymbols) {
202   std::unique_ptr<ResourceTable> table =
203       test::ResourceTableBuilder()
204           .SetPackageId("com.app.test", 0x7f)
205           .AddReference("com.app.test:string/foo", ResourceId(0x7f020000),
206                         "com.app.lib:string/hidden")
207           .Build();
208 
209   std::unique_ptr<IAaptContext> context =
210       test::ContextBuilder()
211           .SetCompilationPackage("com.app.test")
212           .SetPackageId(0x7f)
213           .SetNameManglerPolicy(
214               NameManglerPolicy{"com.app.test", {"com.app.lib"}})
215           .AddSymbolSource(
216               util::make_unique<ResourceTableSymbolSource>(table.get()))
217           .AddSymbolSource(
218               test::StaticSymbolSourceBuilder()
219                   .AddSymbol("com.app.test:string/com.app.lib$hidden",
220                              ResourceId(0x7f040034))
221                   .Build())
222 
223           .Build();
224 
225   ReferenceLinker linker;
226   ASSERT_FALSE(linker.Consume(context.get(), table.get()));
227 }
228 
TEST(ReferenceLinkerTest,FailToLinkPrivateStyleAttributes)229 TEST(ReferenceLinkerTest, FailToLinkPrivateStyleAttributes) {
230   std::unique_ptr<ResourceTable> table =
231       test::ResourceTableBuilder()
232           .SetPackageId("com.app.test", 0x7f)
233           .AddValue("com.app.test:style/Theme",
234                     test::StyleBuilder()
235                         .AddItem("android:attr/hidden",
236                                  ResourceUtils::TryParseColor("#ff00ff"))
237                         .Build())
238           .Build();
239 
240   std::unique_ptr<IAaptContext> context =
241       test::ContextBuilder()
242           .SetCompilationPackage("com.app.test")
243           .SetPackageId(0x7f)
244           .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
245           .AddSymbolSource(
246               util::make_unique<ResourceTableSymbolSource>(table.get()))
247           .AddSymbolSource(
248               test::StaticSymbolSourceBuilder()
249                   .AddSymbol("android:attr/hidden", ResourceId(0x01010001),
250                              test::AttributeBuilder()
251                                  .SetTypeMask(android::ResTable_map::TYPE_COLOR)
252                                  .Build())
253                   .Build())
254           .Build();
255 
256   ReferenceLinker linker;
257   ASSERT_FALSE(linker.Consume(context.get(), table.get()));
258 }
259 
TEST(ReferenceLinkerTest,AppsWithSamePackageButDifferentIdAreVisibleNonPublic)260 TEST(ReferenceLinkerTest, AppsWithSamePackageButDifferentIdAreVisibleNonPublic) {
261   NameMangler mangler(NameManglerPolicy{"com.app.test"});
262   SymbolTable table(&mangler);
263   table.AppendSource(test::StaticSymbolSourceBuilder()
264                          .AddSymbol("com.app.test:string/foo", ResourceId(0x7f010000))
265                          .Build());
266 
267   std::string error;
268   const CallSite call_site{"com.app.test"};
269   const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveSymbolCheckVisibility(
270       *test::BuildReference("com.app.test:string/foo"), call_site, &table, &error);
271   ASSERT_THAT(symbol, NotNull());
272   EXPECT_TRUE(error.empty());
273 }
274 
TEST(ReferenceLinkerTest,AppsWithDifferentPackageCanNotUseEachOthersAttribute)275 TEST(ReferenceLinkerTest, AppsWithDifferentPackageCanNotUseEachOthersAttribute) {
276   NameMangler mangler(NameManglerPolicy{"com.app.ext"});
277   SymbolTable table(&mangler);
278   table.AppendSource(test::StaticSymbolSourceBuilder()
279                          .AddSymbol("com.app.test:attr/foo", ResourceId(0x7f010000),
280                                     test::AttributeBuilder().Build())
281                          .AddPublicSymbol("com.app.test:attr/public_foo", ResourceId(0x7f010001),
282                                           test::AttributeBuilder().Build())
283                          .Build());
284 
285   std::string error;
286   const CallSite call_site{"com.app.ext"};
287 
288   EXPECT_FALSE(ReferenceLinker::CompileXmlAttribute(
289       *test::BuildReference("com.app.test:attr/foo"), call_site, &table, &error));
290   EXPECT_FALSE(error.empty());
291 
292   error = "";
293   ASSERT_TRUE(ReferenceLinker::CompileXmlAttribute(
294       *test::BuildReference("com.app.test:attr/public_foo"), call_site, &table, &error));
295   EXPECT_TRUE(error.empty());
296 }
297 
TEST(ReferenceLinkerTest,ReferenceWithNoPackageUsesCallSitePackage)298 TEST(ReferenceLinkerTest, ReferenceWithNoPackageUsesCallSitePackage) {
299   NameMangler mangler(NameManglerPolicy{"com.app.test"});
300   SymbolTable table(&mangler);
301   table.AppendSource(test::StaticSymbolSourceBuilder()
302                          .AddSymbol("com.app.test:string/foo", ResourceId(0x7f010000))
303                          .AddSymbol("com.app.lib:string/foo", ResourceId(0x7f010001))
304                          .Build());
305 
306   const SymbolTable::Symbol* s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
307                                                                 CallSite{"com.app.test"}, &table);
308   ASSERT_THAT(s, NotNull());
309   EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010000)));
310 
311   s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"},
312                                      &table);
313   ASSERT_THAT(s, NotNull());
314   EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010001)));
315 
316   EXPECT_THAT(ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
317                                              CallSite{"com.app.bad"}, &table),
318               IsNull());
319 }
320 
321 }  // namespace aapt
322