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