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 <unordered_set>
20 
21 #include "android-base/logging.h"
22 
23 #include "ResourceUtils.h"
24 #include "trace/TraceBuffer.h"
25 #include "util/Util.h"
26 #include "xml/XmlActionExecutor.h"
27 #include "xml/XmlDom.h"
28 
29 using android::StringPiece;
30 
31 namespace aapt {
32 
RequiredNameIsNotEmpty(xml::Element * el,SourcePathDiagnostics * diag)33 static bool RequiredNameIsNotEmpty(xml::Element* el, SourcePathDiagnostics* diag) {
34   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
35   if (attr == nullptr) {
36     diag->Error(DiagMessage(el->line_number)
37                 << "<" << el->name << "> is missing attribute 'android:name'");
38     return false;
39   }
40 
41   if (attr->value.empty()) {
42     diag->Error(DiagMessage(el->line_number)
43                 << "attribute 'android:name' in <" << el->name << "> tag must not be empty");
44     return false;
45   }
46   return true;
47 }
48 
49 // This is how PackageManager builds class names from AndroidManifest.xml entries.
NameIsJavaClassName(xml::Element * el,xml::Attribute * attr,SourcePathDiagnostics * diag)50 static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
51                                 SourcePathDiagnostics* diag) {
52   // We allow unqualified class names (ie: .HelloActivity)
53   // Since we don't know the package name, we can just make a fake one here and
54   // the test will be identical as long as the real package name is valid too.
55   Maybe<std::string> fully_qualified_class_name =
56       util::GetFullyQualifiedClassName("a", attr->value);
57 
58   StringPiece qualified_class_name = fully_qualified_class_name
59                                          ? fully_qualified_class_name.value()
60                                          : attr->value;
61 
62   if (!util::IsJavaClassName(qualified_class_name)) {
63     diag->Error(DiagMessage(el->line_number)
64                 << "attribute 'android:name' in <" << el->name
65                 << "> tag must be a valid Java class name");
66     return false;
67   }
68   return true;
69 }
70 
OptionalNameIsJavaClassName(xml::Element * el,SourcePathDiagnostics * diag)71 static bool OptionalNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
72   if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
73     return NameIsJavaClassName(el, attr, diag);
74   }
75   return true;
76 }
77 
RequiredNameIsJavaClassName(xml::Element * el,SourcePathDiagnostics * diag)78 static bool RequiredNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
79   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
80   if (attr == nullptr) {
81     diag->Error(DiagMessage(el->line_number)
82                 << "<" << el->name << "> is missing attribute 'android:name'");
83     return false;
84   }
85   return NameIsJavaClassName(el, attr, diag);
86 }
87 
RequiredNameIsJavaPackage(xml::Element * el,SourcePathDiagnostics * diag)88 static bool RequiredNameIsJavaPackage(xml::Element* el, SourcePathDiagnostics* diag) {
89   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
90   if (attr == nullptr) {
91     diag->Error(DiagMessage(el->line_number)
92                 << "<" << el->name << "> is missing attribute 'android:name'");
93     return false;
94   }
95 
96   if (!util::IsJavaPackageName(attr->value)) {
97     diag->Error(DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
98                                              << "> tag must be a valid Java package name");
99     return false;
100   }
101   return true;
102 }
103 
RequiredAndroidAttribute(const std::string & attr)104 static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std::string& attr) {
105   return [=](xml::Element* el, SourcePathDiagnostics* diag) -> bool {
106     if (el->FindAttribute(xml::kSchemaAndroid, attr) == nullptr) {
107       diag->Error(DiagMessage(el->line_number)
108                   << "<" << el->name << "> is missing required attribute 'android:" << attr << "'");
109       return false;
110     }
111     return true;
112   };
113 }
114 
AutoGenerateIsFeatureSplit(xml::Element * el,SourcePathDiagnostics * diag)115 static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics* diag) {
116   constexpr const char* kFeatureSplit = "featureSplit";
117   constexpr const char* kIsFeatureSplit = "isFeatureSplit";
118 
119   xml::Attribute* attr = el->FindAttribute({}, kFeatureSplit);
120   if (attr != nullptr) {
121     // Rewrite the featureSplit attribute to be "split". This is what the
122     // platform recognizes.
123     attr->name = "split";
124 
125     // Now inject the android:isFeatureSplit="true" attribute.
126     xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsFeatureSplit);
127     if (attr != nullptr) {
128       if (!ResourceUtils::ParseBool(attr->value).value_or_default(false)) {
129         // The isFeatureSplit attribute is false, which conflicts with the use
130         // of "featureSplit".
131         diag->Error(DiagMessage(el->line_number)
132                     << "attribute 'featureSplit' used in <manifest> but 'android:isFeatureSplit' "
133                        "is not 'true'");
134         return false;
135       }
136 
137       // The attribute is already there and set to true, nothing to do.
138     } else {
139       el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsFeatureSplit, "true"});
140     }
141   }
142   return true;
143 }
144 
VerifyManifest(xml::Element * el,SourcePathDiagnostics * diag)145 static bool VerifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
146   xml::Attribute* attr = el->FindAttribute({}, "package");
147   if (!attr) {
148     diag->Error(DiagMessage(el->line_number)
149                 << "<manifest> tag is missing 'package' attribute");
150     return false;
151   } else if (ResourceUtils::IsReference(attr->value)) {
152     diag->Error(DiagMessage(el->line_number)
153                 << "attribute 'package' in <manifest> tag must not be a reference");
154     return false;
155   } else if (!util::IsAndroidPackageName(attr->value)) {
156     diag->Error(DiagMessage(el->line_number)
157                 << "attribute 'package' in <manifest> tag is not a valid Android package name: '"
158                 << attr->value << "'");
159     return false;
160   }
161 
162   attr = el->FindAttribute({}, "split");
163   if (attr) {
164     if (!util::IsJavaPackageName(attr->value)) {
165       diag->Error(DiagMessage(el->line_number) << "attribute 'split' in <manifest> tag is not a "
166                                                   "valid split name");
167       return false;
168     }
169   }
170   return true;
171 }
172 
173 // The coreApp attribute in <manifest> is not a regular AAPT attribute, so type
174 // checking on it is manual.
FixCoreAppAttribute(xml::Element * el,SourcePathDiagnostics * diag)175 static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
176   if (xml::Attribute* attr = el->FindAttribute("", "coreApp")) {
177     std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseBool(attr->value);
178     if (!result) {
179       diag->Error(DiagMessage(el->line_number) << "attribute coreApp must be a boolean");
180       return false;
181     }
182     attr->compiled_value = std::move(result);
183   }
184   return true;
185 }
186 
187 // Checks that <uses-feature> has android:glEsVersion or android:name, not both (or neither).
VerifyUsesFeature(xml::Element * el,SourcePathDiagnostics * diag)188 static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
189   bool has_name = false;
190   if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
191     if (attr->value.empty()) {
192       diag->Error(DiagMessage(el->line_number)
193                   << "android:name in <uses-feature> must not be empty");
194       return false;
195     }
196     has_name = true;
197   }
198 
199   bool has_gl_es_version = false;
200   if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
201     if (has_name) {
202       diag->Error(DiagMessage(el->line_number)
203                   << "cannot define both android:name and android:glEsVersion in <uses-feature>");
204       return false;
205     }
206     has_gl_es_version = true;
207   }
208 
209   if (!has_name && !has_gl_es_version) {
210     diag->Error(DiagMessage(el->line_number)
211                 << "<uses-feature> must have either android:name or android:glEsVersion attribute");
212     return false;
213   }
214   return true;
215 }
216 
BuildRules(xml::XmlActionExecutor * executor,IDiagnostics * diag)217 bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
218                                IDiagnostics* diag) {
219   // First verify some options.
220   if (options_.rename_manifest_package) {
221     if (!util::IsJavaPackageName(options_.rename_manifest_package.value())) {
222       diag->Error(DiagMessage() << "invalid manifest package override '"
223                                 << options_.rename_manifest_package.value()
224                                 << "'");
225       return false;
226     }
227   }
228 
229   if (options_.rename_instrumentation_target_package) {
230     if (!util::IsJavaPackageName(options_.rename_instrumentation_target_package.value())) {
231       diag->Error(DiagMessage()
232                   << "invalid instrumentation target package override '"
233                   << options_.rename_instrumentation_target_package.value()
234                   << "'");
235       return false;
236     }
237   }
238 
239   if (options_.rename_overlay_target_package) {
240     if (!util::IsJavaPackageName(options_.rename_overlay_target_package.value())) {
241       diag->Error(DiagMessage()
242                   << "invalid overlay target package override '"
243                   << options_.rename_overlay_target_package.value()
244                   << "'");
245       return false;
246     }
247   }
248 
249   // Common <intent-filter> actions.
250   xml::XmlNodeAction intent_filter_action;
251   intent_filter_action["action"].Action(RequiredNameIsNotEmpty);
252   intent_filter_action["category"].Action(RequiredNameIsNotEmpty);
253   intent_filter_action["data"];
254 
255   // Common <meta-data> actions.
256   xml::XmlNodeAction meta_data_action;
257 
258   // Common <uses-feature> actions.
259   xml::XmlNodeAction uses_feature_action;
260   uses_feature_action.Action(VerifyUsesFeature);
261 
262   // Common component actions.
263   xml::XmlNodeAction component_action;
264   component_action.Action(RequiredNameIsJavaClassName);
265   component_action["intent-filter"] = intent_filter_action;
266   component_action["preferred"] = intent_filter_action;
267   component_action["meta-data"] = meta_data_action;
268 
269   // Manifest actions.
270   xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
271   manifest_action.Action(AutoGenerateIsFeatureSplit);
272   manifest_action.Action(VerifyManifest);
273   manifest_action.Action(FixCoreAppAttribute);
274   manifest_action.Action([&](xml::Element* el) -> bool {
275     if (options_.version_name_default) {
276       if (options_.replace_version) {
277         el->RemoveAttribute(xml::kSchemaAndroid, "versionName");
278       }
279       if (el->FindAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
280         el->attributes.push_back(
281             xml::Attribute{xml::kSchemaAndroid, "versionName",
282                            options_.version_name_default.value()});
283       }
284     }
285 
286     if (options_.version_code_default) {
287       if (options_.replace_version) {
288         el->RemoveAttribute(xml::kSchemaAndroid, "versionCode");
289       }
290       if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
291         el->attributes.push_back(
292             xml::Attribute{xml::kSchemaAndroid, "versionCode",
293                            options_.version_code_default.value()});
294       }
295     }
296 
297     if (options_.version_code_major_default) {
298       if (options_.replace_version) {
299         el->RemoveAttribute(xml::kSchemaAndroid, "versionCodeMajor");
300       }
301       if (el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor") == nullptr) {
302         el->attributes.push_back(
303             xml::Attribute{xml::kSchemaAndroid, "versionCodeMajor",
304                            options_.version_code_major_default.value()});
305       }
306     }
307 
308     return true;
309   });
310 
311   // Meta tags.
312   manifest_action["eat-comment"];
313 
314   // Uses-sdk actions.
315   manifest_action["uses-sdk"].Action([&](xml::Element* el) -> bool {
316     if (options_.min_sdk_version_default &&
317         el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
318       // There was no minSdkVersion defined and we have a default to assign.
319       el->attributes.push_back(
320           xml::Attribute{xml::kSchemaAndroid, "minSdkVersion",
321                          options_.min_sdk_version_default.value()});
322     }
323 
324     if (options_.target_sdk_version_default &&
325         el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion") == nullptr) {
326       // There was no targetSdkVersion defined and we have a default to assign.
327       el->attributes.push_back(
328           xml::Attribute{xml::kSchemaAndroid, "targetSdkVersion",
329                          options_.target_sdk_version_default.value()});
330     }
331     return true;
332   });
333 
334   // Instrumentation actions.
335   manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
336   manifest_action["instrumentation"].Action([&](xml::Element* el) -> bool {
337     if (!options_.rename_instrumentation_target_package) {
338       return true;
339     }
340 
341     if (xml::Attribute* attr =
342             el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
343       attr->value = options_.rename_instrumentation_target_package.value();
344     }
345     return true;
346   });
347   manifest_action["instrumentation"]["meta-data"] = meta_data_action;
348 
349   manifest_action["original-package"];
350   manifest_action["overlay"].Action([&](xml::Element* el) -> bool {
351     if (!options_.rename_overlay_target_package) {
352       return true;
353     }
354 
355     if (xml::Attribute* attr =
356             el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
357       attr->value = options_.rename_overlay_target_package.value();
358     }
359     return true;
360   });
361   manifest_action["protected-broadcast"];
362   manifest_action["adopt-permissions"];
363   manifest_action["uses-permission"];
364   manifest_action["uses-permission-sdk-23"];
365   manifest_action["permission"];
366   manifest_action["permission"]["meta-data"] = meta_data_action;
367   manifest_action["permission-tree"];
368   manifest_action["permission-group"];
369   manifest_action["uses-configuration"];
370   manifest_action["supports-screens"];
371   manifest_action["uses-feature"] = uses_feature_action;
372   manifest_action["feature-group"]["uses-feature"] = uses_feature_action;
373   manifest_action["compatible-screens"];
374   manifest_action["compatible-screens"]["screen"];
375   manifest_action["supports-gl-texture"];
376   manifest_action["restrict-update"];
377   manifest_action["package-verifier"];
378   manifest_action["meta-data"] = meta_data_action;
379   manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
380 
381   manifest_action["key-sets"]["key-set"]["public-key"];
382   manifest_action["key-sets"]["upgrade-key-set"];
383 
384   // Application actions.
385   xml::XmlNodeAction& application_action = manifest_action["application"];
386   application_action.Action(OptionalNameIsJavaClassName);
387 
388   application_action["uses-library"].Action(RequiredNameIsNotEmpty);
389   application_action["library"].Action(RequiredNameIsNotEmpty);
390   application_action["profileable"];
391 
392   xml::XmlNodeAction& static_library_action = application_action["static-library"];
393   static_library_action.Action(RequiredNameIsJavaPackage);
394   static_library_action.Action(RequiredAndroidAttribute("version"));
395 
396   xml::XmlNodeAction& uses_static_library_action = application_action["uses-static-library"];
397   uses_static_library_action.Action(RequiredNameIsJavaPackage);
398   uses_static_library_action.Action(RequiredAndroidAttribute("version"));
399   uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
400   uses_static_library_action["additional-certificate"];
401 
402   xml::XmlNodeAction& uses_package_action = application_action["uses-package"];
403   uses_package_action.Action(RequiredNameIsJavaPackage);
404   uses_package_action["additional-certificate"];
405 
406   if (options_.debug_mode) {
407     application_action.Action([&](xml::Element* el) -> bool {
408       xml::Attribute *attr = el->FindOrCreateAttribute(xml::kSchemaAndroid, "debuggable");
409       attr->value = "true";
410       return true;
411     });
412   }
413 
414   application_action["meta-data"] = meta_data_action;
415 
416   application_action["activity"] = component_action;
417   application_action["activity"]["layout"];
418 
419   application_action["activity-alias"] = component_action;
420   application_action["service"] = component_action;
421   application_action["receiver"] = component_action;
422 
423   // Provider actions.
424   application_action["provider"] = component_action;
425   application_action["provider"]["grant-uri-permission"];
426   application_action["provider"]["path-permission"];
427 
428   manifest_action["package"] = manifest_action;
429 
430   return true;
431 }
432 
FullyQualifyClassName(const StringPiece & package,const StringPiece & attr_ns,const StringPiece & attr_name,xml::Element * el)433 static void FullyQualifyClassName(const StringPiece& package, const StringPiece& attr_ns,
434                                   const StringPiece& attr_name, xml::Element* el) {
435   xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
436   if (attr != nullptr) {
437     if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package, attr->value)) {
438       attr->value = std::move(new_value.value());
439     }
440   }
441 }
442 
RenameManifestPackage(const StringPiece & package_override,xml::Element * manifest_el)443 static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) {
444   xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
445 
446   // We've already verified that the manifest element is present, with a package
447   // name specified.
448   CHECK(attr != nullptr);
449 
450   std::string original_package = std::move(attr->value);
451   attr->value = package_override.to_string();
452 
453   xml::Element* application_el = manifest_el->FindChild({}, "application");
454   if (application_el != nullptr) {
455     FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", application_el);
456     FullyQualifyClassName(original_package, xml::kSchemaAndroid, "backupAgent", application_el);
457 
458     for (xml::Element* child_el : application_el->GetChildElements()) {
459       if (child_el->namespace_uri.empty()) {
460         if (child_el->name == "activity" || child_el->name == "activity-alias" ||
461             child_el->name == "provider" || child_el->name == "receiver" ||
462             child_el->name == "service") {
463           FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", child_el);
464         }
465 
466         if (child_el->name == "activity-alias") {
467           FullyQualifyClassName(original_package, xml::kSchemaAndroid, "targetActivity", child_el);
468         }
469       }
470     }
471   }
472   return true;
473 }
474 
Consume(IAaptContext * context,xml::XmlResource * doc)475 bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
476   TRACE_CALL();
477   xml::Element* root = xml::FindRootElement(doc->root.get());
478   if (!root || !root->namespace_uri.empty() || root->name != "manifest") {
479     context->GetDiagnostics()->Error(DiagMessage(doc->file.source)
480                                      << "root tag must be <manifest>");
481     return false;
482   }
483 
484   if ((options_.min_sdk_version_default || options_.target_sdk_version_default) &&
485       root->FindChild({}, "uses-sdk") == nullptr) {
486     // Auto insert a <uses-sdk> element. This must be inserted before the
487     // <application> tag. The device runtime PackageParser will make SDK version
488     // decisions while parsing <application>.
489     std::unique_ptr<xml::Element> uses_sdk = util::make_unique<xml::Element>();
490     uses_sdk->name = "uses-sdk";
491     root->InsertChild(0, std::move(uses_sdk));
492   }
493 
494   if (options_.compile_sdk_version) {
495     xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion");
496 
497     // Make sure we un-compile the value if it was set to something else.
498     attr->compiled_value = {};
499     attr->value = options_.compile_sdk_version.value();
500 
501     attr = root->FindOrCreateAttribute("", "platformBuildVersionCode");
502 
503     // Make sure we un-compile the value if it was set to something else.
504     attr->compiled_value = {};
505     attr->value = options_.compile_sdk_version.value();
506 
507   }
508 
509   if (options_.compile_sdk_version_codename) {
510     xml::Attribute* attr =
511         root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
512 
513     // Make sure we un-compile the value if it was set to something else.
514     attr->compiled_value = {};
515     attr->value = options_.compile_sdk_version_codename.value();
516 
517     attr = root->FindOrCreateAttribute("", "platformBuildVersionName");
518 
519     // Make sure we un-compile the value if it was set to something else.
520     attr->compiled_value = {};
521     attr->value = options_.compile_sdk_version_codename.value();
522   }
523 
524   xml::XmlActionExecutor executor;
525   if (!BuildRules(&executor, context->GetDiagnostics())) {
526     return false;
527   }
528 
529   xml::XmlActionExecutorPolicy policy = options_.warn_validation
530                                             ? xml::XmlActionExecutorPolicy::kWhitelistWarning
531                                             : xml::XmlActionExecutorPolicy::kWhitelist;
532   if (!executor.Execute(policy, context->GetDiagnostics(), doc)) {
533     return false;
534   }
535 
536   if (options_.rename_manifest_package) {
537     // Rename manifest package outside of the XmlActionExecutor.
538     // We need to extract the old package name and FullyQualify all class
539     // names.
540     if (!RenameManifestPackage(options_.rename_manifest_package.value(), root)) {
541       return false;
542     }
543   }
544   return true;
545 }
546 
547 }  // namespace aapt
548