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