• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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