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/ManifestFixer.h"
18
19 #include "test/Test.h"
20
21 using ::android::StringPiece;
22 using ::testing::NotNull;
23
24 namespace aapt {
25
26 struct ManifestFixerTest : public ::testing::Test {
27 std::unique_ptr<IAaptContext> mContext;
28
SetUpaapt::ManifestFixerTest29 void SetUp() override {
30 mContext =
31 test::ContextBuilder()
32 .SetCompilationPackage("android")
33 .SetPackageId(0x01)
34 .SetNameManglerPolicy(NameManglerPolicy{"android"})
35 .AddSymbolSource(
36 test::StaticSymbolSourceBuilder()
37 .AddSymbol(
38 "android:attr/package", ResourceId(0x01010000),
39 test::AttributeBuilder()
40 .SetTypeMask(android::ResTable_map::TYPE_STRING)
41 .Build())
42 .AddSymbol(
43 "android:attr/minSdkVersion", ResourceId(0x01010001),
44 test::AttributeBuilder()
45 .SetTypeMask(android::ResTable_map::TYPE_STRING |
46 android::ResTable_map::TYPE_INTEGER)
47 .Build())
48 .AddSymbol(
49 "android:attr/targetSdkVersion", ResourceId(0x01010002),
50 test::AttributeBuilder()
51 .SetTypeMask(android::ResTable_map::TYPE_STRING |
52 android::ResTable_map::TYPE_INTEGER)
53 .Build())
54 .AddSymbol("android:string/str", ResourceId(0x01060000))
55 .Build())
56 .Build();
57 }
58
Verifyaapt::ManifestFixerTest59 std::unique_ptr<xml::XmlResource> Verify(const StringPiece& str) {
60 return VerifyWithOptions(str, {});
61 }
62
VerifyWithOptionsaapt::ManifestFixerTest63 std::unique_ptr<xml::XmlResource> VerifyWithOptions(
64 const StringPiece& str, const ManifestFixerOptions& options) {
65 std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(str);
66 ManifestFixer fixer(options);
67 if (fixer.Consume(mContext.get(), doc.get())) {
68 return doc;
69 }
70 return {};
71 }
72 };
73
TEST_F(ManifestFixerTest,EnsureManifestIsRootTag)74 TEST_F(ManifestFixerTest, EnsureManifestIsRootTag) {
75 EXPECT_EQ(nullptr, Verify("<other-tag />"));
76 EXPECT_EQ(nullptr, Verify("<ns:manifest xmlns:ns=\"com\" />"));
77 EXPECT_NE(nullptr, Verify("<manifest package=\"android\"></manifest>"));
78 }
79
TEST_F(ManifestFixerTest,EnsureManifestHasPackage)80 TEST_F(ManifestFixerTest, EnsureManifestHasPackage) {
81 EXPECT_NE(nullptr, Verify("<manifest package=\"android\" />"));
82 EXPECT_NE(nullptr, Verify("<manifest package=\"com.android\" />"));
83 EXPECT_NE(nullptr, Verify("<manifest package=\"com.android.google\" />"));
84 EXPECT_EQ(nullptr,
85 Verify("<manifest package=\"com.android.google.Class$1\" />"));
86 EXPECT_EQ(nullptr, Verify("<manifest "
87 "xmlns:android=\"http://schemas.android.com/apk/"
88 "res/android\" "
89 "android:package=\"com.android\" />"));
90 EXPECT_EQ(nullptr, Verify("<manifest package=\"@string/str\" />"));
91 }
92
TEST_F(ManifestFixerTest,AllowMetaData)93 TEST_F(ManifestFixerTest, AllowMetaData) {
94 auto doc = Verify(R"EOF(
95 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
96 package="android">
97 <meta-data />
98 <application>
99 <meta-data />
100 <activity android:name=".Hi"><meta-data /></activity>
101 <activity-alias android:name=".Ho"><meta-data /></activity-alias>
102 <receiver android:name=".OffTo"><meta-data /></receiver>
103 <provider android:name=".Work"><meta-data /></provider>
104 <service android:name=".We"><meta-data /></service>
105 </application>
106 <instrumentation android:name=".Go"><meta-data /></instrumentation>
107 </manifest>)EOF");
108 ASSERT_NE(nullptr, doc);
109 }
110
111 TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
112 ManifestFixerOptions options = {std::string("8"), std::string("22")};
113
114 std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
115 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
116 package="android">
117 <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
118 </manifest>)EOF",
119 options);
120 ASSERT_NE(nullptr, doc);
121
122 xml::Element* el;
123 xml::Attribute* attr;
124
125 el = doc->root.get();
126 ASSERT_NE(nullptr, el);
127 el = el->FindChild({}, "uses-sdk");
128 ASSERT_NE(nullptr, el);
129 attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
130 ASSERT_NE(nullptr, attr);
131 EXPECT_EQ("7", attr->value);
132 attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
133 ASSERT_NE(nullptr, attr);
134 EXPECT_EQ("21", attr->value);
135
136 doc = VerifyWithOptions(R"EOF(
137 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
138 package="android">
139 <uses-sdk android:targetSdkVersion="21" />
140 </manifest>)EOF",
141 options);
142 ASSERT_NE(nullptr, doc);
143
144 el = doc->root.get();
145 ASSERT_NE(nullptr, el);
146 el = el->FindChild({}, "uses-sdk");
147 ASSERT_NE(nullptr, el);
148 attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
149 ASSERT_NE(nullptr, attr);
150 EXPECT_EQ("8", attr->value);
151 attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
152 ASSERT_NE(nullptr, attr);
153 EXPECT_EQ("21", attr->value);
154
155 doc = VerifyWithOptions(R"EOF(
156 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
157 package="android">
158 <uses-sdk />
159 </manifest>)EOF",
160 options);
161 ASSERT_NE(nullptr, doc);
162
163 el = doc->root.get();
164 ASSERT_NE(nullptr, el);
165 el = el->FindChild({}, "uses-sdk");
166 ASSERT_NE(nullptr, el);
167 attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
168 ASSERT_NE(nullptr, attr);
169 EXPECT_EQ("8", attr->value);
170 attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
171 ASSERT_NE(nullptr, attr);
172 EXPECT_EQ("22", attr->value);
173
174 doc = VerifyWithOptions(R"EOF(
175 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
176 package="android" />)EOF",
177 options);
178 ASSERT_NE(nullptr, doc);
179
180 el = doc->root.get();
181 ASSERT_NE(nullptr, el);
182 el = el->FindChild({}, "uses-sdk");
183 ASSERT_NE(nullptr, el);
184 attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
185 ASSERT_NE(nullptr, attr);
186 EXPECT_EQ("8", attr->value);
187 attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
188 ASSERT_NE(nullptr, attr);
189 EXPECT_EQ("22", attr->value);
190 }
191
192 TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) {
193 ManifestFixerOptions options = {std::string("8"), std::string("22")};
194 std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
195 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
196 package="android">
197 <application android:name=".MainApplication" />
198 </manifest>)EOF",
199 options);
200 ASSERT_NE(nullptr, doc);
201
202 xml::Element* manifest_el = doc->root.get();
203 ASSERT_NE(nullptr, manifest_el);
204 ASSERT_EQ("manifest", manifest_el->name);
205
206 xml::Element* application_el = manifest_el->FindChild("", "application");
207 ASSERT_NE(nullptr, application_el);
208
209 xml::Element* uses_sdk_el = manifest_el->FindChild("", "uses-sdk");
210 ASSERT_NE(nullptr, uses_sdk_el);
211
212 // Check that the uses_sdk_el comes before application_el in the children
213 // vector.
214 // Since there are no namespaces here, these children are direct descendants
215 // of manifest.
216 auto uses_sdk_iter =
217 std::find_if(manifest_el->children.begin(), manifest_el->children.end(),
218 [&](const std::unique_ptr<xml::Node>& child) {
219 return child.get() == uses_sdk_el;
220 });
221
222 auto application_iter =
223 std::find_if(manifest_el->children.begin(), manifest_el->children.end(),
224 [&](const std::unique_ptr<xml::Node>& child) {
225 return child.get() == application_el;
226 });
227
228 ASSERT_NE(manifest_el->children.end(), uses_sdk_iter);
229 ASSERT_NE(manifest_el->children.end(), application_iter);
230
231 // The distance should be positive, meaning uses_sdk_iter comes before
232 // application_iter.
233 EXPECT_GT(std::distance(uses_sdk_iter, application_iter), 0);
234 }
235
236 TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
237 ManifestFixerOptions options;
238 options.rename_manifest_package = std::string("com.android");
239
240 std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
241 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
242 package="android">
243 <application android:name=".MainApplication" text="hello">
244 <activity android:name=".activity.Start" />
245 <receiver android:name="com.google.android.Receiver" />
246 </application>
247 </manifest>)EOF",
248 options);
249 ASSERT_NE(nullptr, doc);
250
251 xml::Element* manifestEl = doc->root.get();
252 ASSERT_NE(nullptr, manifestEl);
253
254 xml::Attribute* attr = nullptr;
255
256 attr = manifestEl->FindAttribute({}, "package");
257 ASSERT_NE(nullptr, attr);
258 EXPECT_EQ(std::string("com.android"), attr->value);
259
260 xml::Element* applicationEl = manifestEl->FindChild({}, "application");
261 ASSERT_NE(nullptr, applicationEl);
262
263 attr = applicationEl->FindAttribute(xml::kSchemaAndroid, "name");
264 ASSERT_NE(nullptr, attr);
265 EXPECT_EQ(std::string("android.MainApplication"), attr->value);
266
267 attr = applicationEl->FindAttribute({}, "text");
268 ASSERT_NE(nullptr, attr);
269 EXPECT_EQ(std::string("hello"), attr->value);
270
271 xml::Element* el;
272 el = applicationEl->FindChild({}, "activity");
273 ASSERT_NE(nullptr, el);
274
275 attr = el->FindAttribute(xml::kSchemaAndroid, "name");
276 ASSERT_NE(nullptr, el);
277 EXPECT_EQ(std::string("android.activity.Start"), attr->value);
278
279 el = applicationEl->FindChild({}, "receiver");
280 ASSERT_NE(nullptr, el);
281
282 attr = el->FindAttribute(xml::kSchemaAndroid, "name");
283 ASSERT_NE(nullptr, el);
284 EXPECT_EQ(std::string("com.google.android.Receiver"), attr->value);
285 }
286
287 TEST_F(ManifestFixerTest,
288 RenameManifestInstrumentationPackageAndFullyQualifyTarget) {
289 ManifestFixerOptions options;
290 options.rename_instrumentation_target_package = std::string("com.android");
291
292 std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
293 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
294 package="android">
295 <instrumentation android:name=".TestRunner" android:targetPackage="android" />
296 </manifest>)EOF",
297 options);
298 ASSERT_NE(nullptr, doc);
299
300 xml::Element* manifest_el = doc->root.get();
301 ASSERT_NE(nullptr, manifest_el);
302
303 xml::Element* instrumentation_el =
304 manifest_el->FindChild({}, "instrumentation");
305 ASSERT_NE(nullptr, instrumentation_el);
306
307 xml::Attribute* attr =
308 instrumentation_el->FindAttribute(xml::kSchemaAndroid, "targetPackage");
309 ASSERT_NE(nullptr, attr);
310 EXPECT_EQ(std::string("com.android"), attr->value);
311 }
312
313 TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
314 ManifestFixerOptions options;
315 options.version_name_default = std::string("Beta");
316 options.version_code_default = std::string("0x10000000");
317
318 std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
319 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
320 package="android" />)EOF",
321 options);
322 ASSERT_NE(nullptr, doc);
323
324 xml::Element* manifest_el = doc->root.get();
325 ASSERT_NE(nullptr, manifest_el);
326
327 xml::Attribute* attr =
328 manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
329 ASSERT_NE(nullptr, attr);
330 EXPECT_EQ(std::string("Beta"), attr->value);
331
332 attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
333 ASSERT_NE(nullptr, attr);
334 EXPECT_EQ(std::string("0x10000000"), attr->value);
335 }
336
337 TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
338 EXPECT_EQ(nullptr,
339 Verify("<manifest package=\"android\" coreApp=\"hello\" />"));
340 EXPECT_EQ(nullptr,
341 Verify("<manifest package=\"android\" coreApp=\"1dp\" />"));
342
343 std::unique_ptr<xml::XmlResource> doc =
344 Verify("<manifest package=\"android\" coreApp=\"true\" />");
345 ASSERT_NE(nullptr, doc);
346
347 xml::Element* el = doc->root.get();
348 ASSERT_NE(nullptr, el);
349
350 EXPECT_EQ("manifest", el->name);
351
352 xml::Attribute* attr = el->FindAttribute("", "coreApp");
353 ASSERT_NE(nullptr, attr);
354
355 EXPECT_NE(nullptr, attr->compiled_value);
356 EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(attr->compiled_value.get()));
357 }
358
TEST_F(ManifestFixerTest,UsesFeatureMustHaveNameOrGlEsVersion)359 TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
360 std::string input = R"EOF(
361 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
362 package="android">
363 <uses-feature android:name="feature" />
364 <uses-feature android:glEsVersion="1" />
365 <feature-group />
366 <feature-group>
367 <uses-feature android:name="feature_in_group" />
368 <uses-feature android:glEsVersion="2" />
369 </feature-group>
370 </manifest>)EOF";
371 EXPECT_NE(nullptr, Verify(input));
372
373 input = R"EOF(
374 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
375 package="android">
376 <uses-feature android:name="feature" android:glEsVersion="1" />
377 </manifest>)EOF";
378 EXPECT_EQ(nullptr, Verify(input));
379
380 input = R"EOF(
381 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
382 package="android">
383 <uses-feature />
384 </manifest>)EOF";
385 EXPECT_EQ(nullptr, Verify(input));
386
387 input = R"EOF(
388 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
389 package="android">
390 <feature-group>
391 <uses-feature android:name="feature" android:glEsVersion="1" />
392 </feature-group>
393 </manifest>)EOF";
394 EXPECT_EQ(nullptr, Verify(input));
395
396 input = R"EOF(
397 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
398 package="android">
399 <feature-group>
400 <uses-feature />
401 </feature-group>
402 </manifest>)EOF";
403 EXPECT_EQ(nullptr, Verify(input));
404 }
405
406 TEST_F(ManifestFixerTest, IgnoreNamespacedElements) {
407 std::string input = R"EOF(
408 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
409 package="android">
410 <special:tag whoo="true" xmlns:special="http://google.com" />
411 </manifest>)EOF";
412 EXPECT_NE(nullptr, Verify(input));
413 }
414
415 TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) {
416 std::string input = R"EOF(
417 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
418 package="android">
419 <tag whoo="true" />
420 </manifest>)EOF";
421 EXPECT_EQ(nullptr, Verify(input));
422 }
423
424 TEST_F(ManifestFixerTest, SupportKeySets) {
425 std::string input = R"(
426 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
427 package="android">
428 <key-sets>
429 <key-set android:name="old-set">
430 <public-key android:name="old-key" android:value="some+old+key" />
431 </key-set>
432 <key-set android:name="new-set">
433 <public-key android:name="new-key" android:value="some+new+key" />
434 </key-set>
435 <upgrade-key-set android:name="old-set" />
436 <upgrade-key-set android:name="new-set" />
437 </key-sets>
438 </manifest>)";
439 EXPECT_THAT(Verify(input), NotNull());
440 }
441
442 } // namespace aapt
443