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 
33 // This is to detect whether an <intent-filter> contains deeplink.
34 // See https://developer.android.com/training/app-links/deep-linking.
HasDeepLink(xml::Element * intent_filter_el)35 static bool HasDeepLink(xml::Element* intent_filter_el) {
36   xml::Element* action_el = intent_filter_el->FindChild({}, "action");
37   xml::Element* category_el = intent_filter_el->FindChild({}, "category");
38   xml::Element* data_el = intent_filter_el->FindChild({}, "data");
39   if (action_el == nullptr || category_el == nullptr || data_el == nullptr) {
40     return false;
41   }
42 
43   // Deeplinks must specify the ACTION_VIEW intent action.
44   constexpr const char* action_view = "android.intent.action.VIEW";
45   if (intent_filter_el->FindChildWithAttribute({}, "action", xml::kSchemaAndroid, "name",
46                                                action_view) == nullptr) {
47     return false;
48   }
49 
50   // Deeplinks must have scheme included in <data> tag.
51   xml::Attribute* data_scheme_attr = data_el->FindAttribute(xml::kSchemaAndroid, "scheme");
52   if (data_scheme_attr == nullptr || data_scheme_attr->value.empty()) {
53     return false;
54   }
55 
56   // Deeplinks must include BROWSABLE category.
57   constexpr const char* category_browsable = "android.intent.category.BROWSABLE";
58   if (intent_filter_el->FindChildWithAttribute({}, "category", xml::kSchemaAndroid, "name",
59                                                category_browsable) == nullptr) {
60     return false;
61   }
62   return true;
63 }
64 
VerifyDeeplinkPathAttribute(xml::Element * data_el,android::SourcePathDiagnostics * diag,const std::string & attr_name)65 static bool VerifyDeeplinkPathAttribute(xml::Element* data_el, android::SourcePathDiagnostics* diag,
66                                         const std::string& attr_name) {
67   xml::Attribute* attr = data_el->FindAttribute(xml::kSchemaAndroid, attr_name);
68   if (attr != nullptr && !attr->value.empty()) {
69     StringPiece attr_value = attr->value;
70     const char* startChar = attr_value.begin();
71     if (attr_name == "pathPattern") {
72       // pathPattern starts with '.' or '*' does not need leading slash.
73       // Reference starts with @ does not need leading slash.
74       if (*startChar == '/' || *startChar == '.' || *startChar == '*' || *startChar == '@') {
75         return true;
76       } else {
77         diag->Error(android::DiagMessage(data_el->line_number)
78                     << "attribute 'android:" << attr_name << "' in <" << data_el->name
79                     << "> tag has value of '" << attr_value
80                     << "', it must be in a pattern start with '.' or '*', otherwise must start "
81                        "with a leading slash '/'");
82         return false;
83       }
84     } else {
85       // Reference starts with @ does not need leading slash.
86       if (*startChar == '/' || *startChar == '@') {
87         return true;
88       } else {
89         diag->Error(android::DiagMessage(data_el->line_number)
90                     << "attribute 'android:" << attr_name << "' in <" << data_el->name
91                     << "> tag has value of '" << attr_value
92                     << "', it must start with a leading slash '/'");
93         return false;
94       }
95     }
96   }
97   return true;
98 }
99 
VerifyDeepLinkIntentAction(xml::Element * intent_filter_el,android::SourcePathDiagnostics * diag)100 static bool VerifyDeepLinkIntentAction(xml::Element* intent_filter_el,
101                                        android::SourcePathDiagnostics* diag) {
102   if (!HasDeepLink(intent_filter_el)) {
103     return true;
104   }
105 
106   xml::Element* data_el = intent_filter_el->FindChild({}, "data");
107   if (data_el != nullptr) {
108     if (!VerifyDeeplinkPathAttribute(data_el, diag, "path")) {
109       return false;
110     }
111     if (!VerifyDeeplinkPathAttribute(data_el, diag, "pathPrefix")) {
112       return false;
113     }
114     if (!VerifyDeeplinkPathAttribute(data_el, diag, "pathPattern")) {
115       return false;
116     }
117   }
118   return true;
119 }
120 
RequiredNameIsNotEmpty(xml::Element * el,android::SourcePathDiagnostics * diag)121 static bool RequiredNameIsNotEmpty(xml::Element* el, android::SourcePathDiagnostics* diag) {
122   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
123   if (attr == nullptr) {
124     diag->Error(android::DiagMessage(el->line_number)
125                 << "<" << el->name << "> is missing attribute 'android:name'");
126     return false;
127   }
128 
129   if (attr->value.empty()) {
130     diag->Error(android::DiagMessage(el->line_number)
131                 << "attribute 'android:name' in <" << el->name << "> tag must not be empty");
132     return false;
133   }
134   return true;
135 }
136 
137 // This is how PackageManager builds class names from AndroidManifest.xml entries.
NameIsJavaClassName(xml::Element * el,xml::Attribute * attr,android::SourcePathDiagnostics * diag)138 static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
139                                 android::SourcePathDiagnostics* diag) {
140   // We allow unqualified class names (ie: .HelloActivity)
141   // Since we don't know the package name, we can just make a fake one here and
142   // the test will be identical as long as the real package name is valid too.
143   std::optional<std::string> fully_qualified_class_name =
144       util::GetFullyQualifiedClassName("a", attr->value);
145 
146   StringPiece qualified_class_name = fully_qualified_class_name
147                                          ? fully_qualified_class_name.value()
148                                          : attr->value;
149 
150   if (!util::IsJavaClassName(qualified_class_name)) {
151     diag->Error(android::DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
152                                                       << "> tag must be a valid Java class name");
153     return false;
154   }
155   return true;
156 }
157 
OptionalNameIsJavaClassName(xml::Element * el,android::SourcePathDiagnostics * diag)158 static bool OptionalNameIsJavaClassName(xml::Element* el, android::SourcePathDiagnostics* diag) {
159   if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
160     return NameIsJavaClassName(el, attr, diag);
161   }
162   return true;
163 }
164 
RequiredNameIsJavaClassName(xml::Element * el,android::SourcePathDiagnostics * diag)165 static bool RequiredNameIsJavaClassName(xml::Element* el, android::SourcePathDiagnostics* diag) {
166   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
167   if (attr == nullptr) {
168     diag->Error(android::DiagMessage(el->line_number)
169                 << "<" << el->name << "> is missing attribute 'android:name'");
170     return false;
171   }
172   return NameIsJavaClassName(el, attr, diag);
173 }
174 
RequiredNameIsJavaPackage(xml::Element * el,android::SourcePathDiagnostics * diag)175 static bool RequiredNameIsJavaPackage(xml::Element* el, android::SourcePathDiagnostics* diag) {
176   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
177   if (attr == nullptr) {
178     diag->Error(android::DiagMessage(el->line_number)
179                 << "<" << el->name << "> is missing attribute 'android:name'");
180     return false;
181   }
182 
183   if (!util::IsJavaPackageName(attr->value)) {
184     diag->Error(android::DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
185                                                       << "> tag must be a valid Java package name");
186     return false;
187   }
188   return true;
189 }
190 
RequiredAndroidAttribute(const std::string & attr)191 static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std::string& attr) {
192   return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
193     if (el->FindAttribute(xml::kSchemaAndroid, attr) == nullptr) {
194       diag->Error(android::DiagMessage(el->line_number)
195                   << "<" << el->name << "> is missing required attribute 'android:" << attr << "'");
196       return false;
197     }
198     return true;
199   };
200 }
201 
RequiredOneAndroidAttribute(const std::string & attrName1,const std::string & attrName2)202 static xml::XmlNodeAction::ActionFuncWithDiag RequiredOneAndroidAttribute(
203     const std::string& attrName1, const std::string& attrName2) {
204   return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
205     xml::Attribute* attr1 = el->FindAttribute(xml::kSchemaAndroid, attrName1);
206     xml::Attribute* attr2 = el->FindAttribute(xml::kSchemaAndroid, attrName2);
207     if (attr1 == nullptr && attr2 == nullptr) {
208       diag->Error(android::DiagMessage(el->line_number)
209                   << "<" << el->name << "> is missing required attribute 'android:" << attrName1
210                   << "' or 'android:" << attrName2 << "'");
211       return false;
212     }
213     if (attr1 != nullptr && attr2 != nullptr) {
214       diag->Error(android::DiagMessage(el->line_number)
215                   << "<" << el->name << "> can only specify one of attribute 'android:" << attrName1
216                   << "' or 'android:" << attrName2 << "'");
217       return false;
218     }
219     return true;
220   };
221 }
222 
AutoGenerateIsFeatureSplit(xml::Element * el,android::SourcePathDiagnostics * diag)223 static bool AutoGenerateIsFeatureSplit(xml::Element* el, android::SourcePathDiagnostics* diag) {
224   constexpr const char* kFeatureSplit = "featureSplit";
225   constexpr const char* kIsFeatureSplit = "isFeatureSplit";
226 
227   xml::Attribute* attr = el->FindAttribute({}, kFeatureSplit);
228   if (attr != nullptr) {
229     // Rewrite the featureSplit attribute to be "split". This is what the
230     // platform recognizes.
231     attr->name = "split";
232 
233     // Now inject the android:isFeatureSplit="true" attribute.
234     xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsFeatureSplit);
235     if (attr != nullptr) {
236       if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
237         // The isFeatureSplit attribute is false, which conflicts with the use
238         // of "featureSplit".
239         diag->Error(android::DiagMessage(el->line_number)
240                     << "attribute 'featureSplit' used in <manifest> but 'android:isFeatureSplit' "
241                        "is not 'true'");
242         return false;
243       }
244 
245       // The attribute is already there and set to true, nothing to do.
246     } else {
247       el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsFeatureSplit, "true"});
248     }
249   }
250   return true;
251 }
252 
AutoGenerateIsSplitRequired(xml::Element * el,android::SourcePathDiagnostics * diag)253 static bool AutoGenerateIsSplitRequired(xml::Element* el, android::SourcePathDiagnostics* diag) {
254   constexpr const char* kRequiredSplitTypes = "requiredSplitTypes";
255   constexpr const char* kIsSplitRequired = "isSplitRequired";
256 
257   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kRequiredSplitTypes);
258   if (attr != nullptr) {
259     // Now inject the android:isSplitRequired="true" attribute.
260     xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsSplitRequired);
261     if (attr != nullptr) {
262       if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
263         // The isFeatureSplit attribute is false, which conflicts with the use
264         // of "featureSplit".
265         diag->Error(android::DiagMessage(el->line_number)
266                     << "attribute 'requiredSplitTypes' used in <manifest> but "
267                        "'android:isSplitRequired' is not 'true'");
268         return false;
269       }
270       // The attribute is already there and set to true, nothing to do.
271     } else {
272       el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsSplitRequired, "true"});
273     }
274   }
275   return true;
276 }
277 
VerifyManifest(xml::Element * el,xml::XmlActionExecutorPolicy policy,android::SourcePathDiagnostics * diag)278 static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy,
279                            android::SourcePathDiagnostics* diag) {
280   xml::Attribute* attr = el->FindAttribute({}, "package");
281   if (!attr) {
282     diag->Error(android::DiagMessage(el->line_number)
283                 << "<manifest> tag is missing 'package' attribute");
284     return false;
285   } else if (ResourceUtils::IsReference(attr->value)) {
286     diag->Error(android::DiagMessage(el->line_number)
287                 << "attribute 'package' in <manifest> tag must not be a reference");
288     return false;
289   } else if (!util::IsAndroidPackageName(attr->value)) {
290     android::DiagMessage error_msg(el->line_number);
291     error_msg << "attribute 'package' in <manifest> tag is not a valid Android package name: '"
292               << attr->value << "'";
293     if (policy == xml::XmlActionExecutorPolicy::kAllowListWarning) {
294       // Treat the error only as a warning.
295       diag->Warn(error_msg);
296     } else {
297       diag->Error(error_msg);
298       return false;
299     }
300   }
301 
302   attr = el->FindAttribute({}, "split");
303   if (attr) {
304     if (!util::IsJavaPackageName(attr->value)) {
305       diag->Error(android::DiagMessage(el->line_number)
306                   << "attribute 'split' in <manifest> tag is not a "
307                      "valid split name");
308       return false;
309     }
310   }
311   return true;
312 }
313 
314 // The coreApp attribute in <manifest> is not a regular AAPT attribute, so type
315 // checking on it is manual.
FixCoreAppAttribute(xml::Element * el,android::SourcePathDiagnostics * diag)316 static bool FixCoreAppAttribute(xml::Element* el, android::SourcePathDiagnostics* diag) {
317   if (xml::Attribute* attr = el->FindAttribute("", "coreApp")) {
318     std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseBool(attr->value);
319     if (!result) {
320       diag->Error(android::DiagMessage(el->line_number) << "attribute coreApp must be a boolean");
321       return false;
322     }
323     attr->compiled_value = std::move(result);
324   }
325   return true;
326 }
327 
328 // Checks that <uses-feature> has android:glEsVersion or android:name, not both (or neither).
VerifyUsesFeature(xml::Element * el,android::SourcePathDiagnostics * diag)329 static bool VerifyUsesFeature(xml::Element* el, android::SourcePathDiagnostics* diag) {
330   bool has_name = false;
331   if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
332     if (attr->value.empty()) {
333       diag->Error(android::DiagMessage(el->line_number)
334                   << "android:name in <uses-feature> must not be empty");
335       return false;
336     }
337     has_name = true;
338   }
339 
340   bool has_gl_es_version = false;
341   if (el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
342     if (has_name) {
343       diag->Error(android::DiagMessage(el->line_number)
344                   << "cannot define both android:name and android:glEsVersion in <uses-feature>");
345       return false;
346     }
347     has_gl_es_version = true;
348   }
349 
350   if (!has_name && !has_gl_es_version) {
351     diag->Error(android::DiagMessage(el->line_number)
352                 << "<uses-feature> must have either android:name or android:glEsVersion attribute");
353     return false;
354   }
355   return true;
356 }
357 
358 // Ensure that 'ns_decls' contains a declaration for 'uri', using 'prefix' as
359 // the xmlns prefix if possible.
EnsureNamespaceIsDeclared(const std::string & prefix,const std::string & uri,std::vector<xml::NamespaceDecl> * ns_decls)360 static void EnsureNamespaceIsDeclared(const std::string& prefix, const std::string& uri,
361                                       std::vector<xml::NamespaceDecl>* ns_decls) {
362   if (std::find_if(ns_decls->begin(), ns_decls->end(), [&](const xml::NamespaceDecl& ns_decl) {
363         return ns_decl.uri == uri;
364       }) != ns_decls->end()) {
365     return;
366   }
367 
368   std::set<std::string> used_prefixes;
369   for (const auto& ns_decl : *ns_decls) {
370     used_prefixes.insert(ns_decl.prefix);
371   }
372 
373   // Make multiple attempts in the unlikely event that 'prefix' is already taken.
374   std::string disambiguator;
375   for (int i = 0; i < used_prefixes.size() + 1; i++) {
376     std::string attempted_prefix = prefix + disambiguator;
377     if (used_prefixes.find(attempted_prefix) == used_prefixes.end()) {
378       ns_decls->push_back(xml::NamespaceDecl{attempted_prefix, uri});
379       return;
380     }
381     disambiguator = std::to_string(i);
382   }
383 }
384 
BuildRules(xml::XmlActionExecutor * executor,android::IDiagnostics * diag)385 bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag) {
386   // First verify some options.
387   if (options_.rename_manifest_package) {
388     if (!util::IsJavaPackageName(options_.rename_manifest_package.value())) {
389       diag->Error(android::DiagMessage() << "invalid manifest package override '"
390                                          << options_.rename_manifest_package.value() << "'");
391       return false;
392     }
393   }
394 
395   if (options_.rename_instrumentation_target_package) {
396     if (!util::IsJavaPackageName(options_.rename_instrumentation_target_package.value())) {
397       diag->Error(android::DiagMessage()
398                   << "invalid instrumentation target package override '"
399                   << options_.rename_instrumentation_target_package.value() << "'");
400       return false;
401     }
402   }
403 
404   if (options_.rename_overlay_target_package) {
405     if (!util::IsJavaPackageName(options_.rename_overlay_target_package.value())) {
406       diag->Error(android::DiagMessage() << "invalid overlay target package override '"
407                                          << options_.rename_overlay_target_package.value() << "'");
408       return false;
409     }
410   }
411 
412   // Common <intent-filter> actions.
413   xml::XmlNodeAction intent_filter_action;
414   intent_filter_action.Action(VerifyDeepLinkIntentAction);
415   intent_filter_action["action"].Action(RequiredNameIsNotEmpty);
416   intent_filter_action["category"].Action(RequiredNameIsNotEmpty);
417   intent_filter_action["data"];
418   intent_filter_action["uri-relative-filter-group"];
419   intent_filter_action["uri-relative-filter-group"]["data"];
420 
421   // Common <meta-data> actions.
422   xml::XmlNodeAction meta_data_action;
423 
424   // Common <property> actions.
425   xml::XmlNodeAction property_action;
426   property_action.Action(RequiredOneAndroidAttribute("resource", "value"));
427 
428   // Common <uses-feature> actions.
429   xml::XmlNodeAction uses_feature_action;
430   uses_feature_action.Action(VerifyUsesFeature);
431 
432   // Common component actions.
433   xml::XmlNodeAction component_action;
434   component_action.Action(RequiredNameIsJavaClassName);
435   component_action["intent-filter"] = intent_filter_action;
436   component_action["preferred"] = intent_filter_action;
437   component_action["meta-data"] = meta_data_action;
438   component_action["property"] = property_action;
439 
440   // Manifest actions.
441   xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
442   manifest_action.Action(AutoGenerateIsFeatureSplit);
443   manifest_action.Action(AutoGenerateIsSplitRequired);
444   manifest_action.Action(VerifyManifest);
445   manifest_action.Action(FixCoreAppAttribute);
446   manifest_action.Action([this, diag](xml::Element* el) -> bool {
447     EnsureNamespaceIsDeclared("android", xml::kSchemaAndroid, &el->namespace_decls);
448 
449     if (options_.version_name_default) {
450       if (options_.replace_version) {
451         el->RemoveAttribute(xml::kSchemaAndroid, "versionName");
452       }
453       if (el->FindAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
454         el->attributes.push_back(
455             xml::Attribute{xml::kSchemaAndroid, "versionName",
456                            options_.version_name_default.value()});
457       }
458     }
459 
460     if (options_.version_code_default) {
461       if (options_.replace_version) {
462         el->RemoveAttribute(xml::kSchemaAndroid, "versionCode");
463       }
464       if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
465         el->attributes.push_back(
466             xml::Attribute{xml::kSchemaAndroid, "versionCode",
467                            options_.version_code_default.value()});
468       }
469     }
470 
471     if (options_.version_code_major_default) {
472       if (options_.replace_version) {
473         el->RemoveAttribute(xml::kSchemaAndroid, "versionCodeMajor");
474       }
475       if (el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor") == nullptr) {
476         el->attributes.push_back(
477             xml::Attribute{xml::kSchemaAndroid, "versionCodeMajor",
478                            options_.version_code_major_default.value()});
479       }
480     }
481 
482     if (options_.revision_code_default) {
483       if (options_.replace_version) {
484         el->RemoveAttribute(xml::kSchemaAndroid, "revisionCode");
485       }
486       if (el->FindAttribute(xml::kSchemaAndroid, "revisionCode") == nullptr) {
487         el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "revisionCode",
488                                                 options_.revision_code_default.value()});
489       }
490     }
491 
492     if (options_.non_updatable_system) {
493       if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
494         el->RemoveAttribute("", "updatableSystem");
495         el->attributes.push_back(xml::Attribute{"", "updatableSystem", "false"});
496       } else {
497         diag->Note(android::DiagMessage(el->line_number)
498                    << "Ignoring --non-updatable-system because the manifest has a versionCode");
499       }
500     }
501 
502     return true;
503   });
504 
505   // Meta tags.
506   manifest_action["eat-comment"];
507 
508   // Uses-sdk actions.
509   manifest_action["uses-sdk"].Action([this](xml::Element* el) -> bool {
510     if (options_.min_sdk_version_default &&
511         el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
512       // There was no minSdkVersion defined and we have a default to assign.
513       el->attributes.push_back(
514           xml::Attribute{xml::kSchemaAndroid, "minSdkVersion",
515                          options_.min_sdk_version_default.value()});
516     }
517 
518     if (options_.target_sdk_version_default &&
519         el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion") == nullptr) {
520       // There was no targetSdkVersion defined and we have a default to assign.
521       el->attributes.push_back(
522           xml::Attribute{xml::kSchemaAndroid, "targetSdkVersion",
523                          options_.target_sdk_version_default.value()});
524     }
525     return true;
526   });
527   manifest_action["uses-sdk"]["extension-sdk"];
528 
529   // Instrumentation actions.
530   manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
531   manifest_action["instrumentation"].Action([this](xml::Element* el) -> bool {
532     if (!options_.rename_instrumentation_target_package) {
533       return true;
534     }
535 
536     if (xml::Attribute* attr =
537             el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
538       attr->value = options_.rename_instrumentation_target_package.value();
539     }
540     return true;
541   });
542   manifest_action["instrumentation"]["meta-data"] = meta_data_action;
543 
544   manifest_action["attribution"];
545   manifest_action["attribution"]["inherit-from"];
546   manifest_action["original-package"];
547   manifest_action["overlay"].Action([this](xml::Element* el) -> bool {
548     if (options_.rename_overlay_target_package) {
549       if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
550         attr->value = options_.rename_overlay_target_package.value();
551       }
552     }
553     if (options_.rename_overlay_category) {
554       if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "category")) {
555         attr->value = options_.rename_overlay_category.value();
556       } else {
557         el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "category",
558                                                 options_.rename_overlay_category.value()});
559       }
560     }
561     return true;
562   });
563   manifest_action["protected-broadcast"];
564   manifest_action["adopt-permissions"];
565   manifest_action["uses-permission"];
566   manifest_action["uses-permission"]["required-feature"].Action(RequiredNameIsNotEmpty);
567   manifest_action["uses-permission"]["required-not-feature"].Action(RequiredNameIsNotEmpty);
568   manifest_action["uses-permission-sdk-23"];
569   manifest_action["permission"];
570   manifest_action["permission"]["meta-data"] = meta_data_action;
571   manifest_action["permission-tree"];
572   manifest_action["permission-group"];
573   manifest_action["uses-configuration"];
574   manifest_action["supports-screens"];
575   manifest_action["uses-feature"] = uses_feature_action;
576   manifest_action["feature-group"]["uses-feature"] = uses_feature_action;
577   manifest_action["compatible-screens"];
578   manifest_action["compatible-screens"]["screen"];
579   manifest_action["supports-gl-texture"];
580   manifest_action["restrict-update"];
581   manifest_action["install-constraints"]["fingerprint-prefix"];
582   manifest_action["package-verifier"];
583   manifest_action["meta-data"] = meta_data_action;
584   manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
585   manifest_action["queries"]["package"].Action(RequiredNameIsJavaPackage);
586   manifest_action["queries"]["intent"] = intent_filter_action;
587   manifest_action["queries"]["provider"].Action(RequiredAndroidAttribute("authorities"));
588   // TODO: more complicated component name tag
589 
590   manifest_action["key-sets"]["key-set"]["public-key"];
591   manifest_action["key-sets"]["upgrade-key-set"];
592 
593   // Application actions.
594   xml::XmlNodeAction& application_action = manifest_action["application"];
595   application_action.Action(OptionalNameIsJavaClassName);
596 
597   application_action["uses-library"].Action(RequiredNameIsNotEmpty);
598   application_action["uses-native-library"].Action(RequiredNameIsNotEmpty);
599   application_action["library"].Action(RequiredNameIsNotEmpty);
600   application_action["profileable"];
601   application_action["property"] = property_action;
602 
603   xml::XmlNodeAction& static_library_action = application_action["static-library"];
604   static_library_action.Action(RequiredNameIsJavaPackage);
605   static_library_action.Action(RequiredAndroidAttribute("version"));
606 
607   xml::XmlNodeAction& uses_static_library_action = application_action["uses-static-library"];
608   uses_static_library_action.Action(RequiredNameIsJavaPackage);
609   uses_static_library_action.Action(RequiredAndroidAttribute("version"));
610   uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
611   uses_static_library_action["additional-certificate"];
612 
613   xml::XmlNodeAction& sdk_library_action = application_action["sdk-library"];
614   sdk_library_action.Action(RequiredNameIsJavaPackage);
615   sdk_library_action.Action(RequiredAndroidAttribute("versionMajor"));
616 
617   xml::XmlNodeAction& uses_sdk_library_action = application_action["uses-sdk-library"];
618   uses_sdk_library_action.Action(RequiredNameIsJavaPackage);
619   uses_sdk_library_action.Action(RequiredAndroidAttribute("versionMajor"));
620   uses_sdk_library_action.Action(RequiredAndroidAttribute("certDigest"));
621   uses_sdk_library_action["additional-certificate"];
622 
623   xml::XmlNodeAction& uses_package_action = application_action["uses-package"];
624   uses_package_action.Action(RequiredNameIsJavaPackage);
625   uses_package_action["additional-certificate"];
626 
627   if (options_.debug_mode) {
628     application_action.Action([](xml::Element* el) -> bool {
629       xml::Attribute *attr = el->FindOrCreateAttribute(xml::kSchemaAndroid, "debuggable");
630       attr->value = "true";
631       return true;
632     });
633   }
634 
635   application_action["meta-data"] = meta_data_action;
636 
637   application_action["processes"];
638   application_action["processes"]["deny-permission"];
639   application_action["processes"]["allow-permission"];
640   application_action["processes"]["process"]["deny-permission"];
641   application_action["processes"]["process"]["allow-permission"];
642 
643   application_action["activity"] = component_action;
644   application_action["activity"]["layout"];
645 
646   application_action["activity-alias"] = component_action;
647   application_action["service"] = component_action;
648   application_action["receiver"] = component_action;
649   application_action["apex-system-service"] = component_action;
650 
651   // Provider actions.
652   application_action["provider"] = component_action;
653   application_action["provider"]["grant-uri-permission"];
654   application_action["provider"]["path-permission"];
655 
656   manifest_action["package"] = manifest_action;
657 
658   return true;
659 }
660 
FullyQualifyClassName(StringPiece package,StringPiece attr_ns,StringPiece attr_name,xml::Element * el)661 static void FullyQualifyClassName(StringPiece package, StringPiece attr_ns, StringPiece attr_name,
662                                   xml::Element* el) {
663   xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
664   if (attr != nullptr) {
665     if (std::optional<std::string> new_value =
666             util::GetFullyQualifiedClassName(package, attr->value)) {
667       attr->value = std::move(new_value.value());
668     }
669   }
670 }
671 
RenameManifestPackage(StringPiece package_override,xml::Element * manifest_el)672 static bool RenameManifestPackage(StringPiece package_override, xml::Element* manifest_el) {
673   xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
674 
675   // We've already verified that the manifest element is present, with a package
676   // name specified.
677   CHECK(attr != nullptr);
678 
679   std::string original_package = std::move(attr->value);
680   attr->value.assign(package_override);
681 
682   xml::Element* application_el = manifest_el->FindChild({}, "application");
683   if (application_el != nullptr) {
684     FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", application_el);
685     FullyQualifyClassName(original_package, xml::kSchemaAndroid, "backupAgent", application_el);
686 
687     for (xml::Element* child_el : application_el->GetChildElements()) {
688       if (child_el->namespace_uri.empty()) {
689         if (child_el->name == "activity" || child_el->name == "activity-alias" ||
690             child_el->name == "provider" || child_el->name == "receiver" ||
691             child_el->name == "service") {
692           FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", child_el);
693           continue;
694         }
695 
696         if (child_el->name == "activity-alias") {
697           FullyQualifyClassName(original_package, xml::kSchemaAndroid, "targetActivity", child_el);
698           continue;
699         }
700 
701         if (child_el->name == "processes") {
702           for (xml::Element* grand_child_el : child_el->GetChildElements()) {
703             if (grand_child_el->name == "process") {
704               FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", grand_child_el);
705             }
706           }
707           continue;
708         }
709       }
710     }
711   }
712   return true;
713 }
714 
Consume(IAaptContext * context,xml::XmlResource * doc)715 bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
716   TRACE_CALL();
717   xml::Element* root = xml::FindRootElement(doc->root.get());
718   if (!root || !root->namespace_uri.empty() || root->name != "manifest") {
719     context->GetDiagnostics()->Error(android::DiagMessage(doc->file.source)
720                                      << "root tag must be <manifest>");
721     return false;
722   }
723 
724   if ((options_.min_sdk_version_default || options_.target_sdk_version_default) &&
725       root->FindChild({}, "uses-sdk") == nullptr) {
726     // Auto insert a <uses-sdk> element. This must be inserted before the
727     // <application> tag. The device runtime PackageParser will make SDK version
728     // decisions while parsing <application>.
729     std::unique_ptr<xml::Element> uses_sdk = util::make_unique<xml::Element>();
730     uses_sdk->name = "uses-sdk";
731     root->InsertChild(0, std::move(uses_sdk));
732   }
733 
734   if (!options_.no_compile_sdk_metadata && options_.compile_sdk_version) {
735     xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion");
736 
737     // Make sure we un-compile the value if it was set to something else.
738     attr->compiled_value = {};
739     attr->value = options_.compile_sdk_version.value();
740 
741     attr = root->FindOrCreateAttribute("", "platformBuildVersionCode");
742 
743     // Make sure we un-compile the value if it was set to something else.
744     attr->compiled_value = {};
745     attr->value = options_.compile_sdk_version.value();
746   }
747 
748   if (!options_.no_compile_sdk_metadata && options_.compile_sdk_version_codename) {
749     xml::Attribute* attr =
750         root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
751 
752     // Make sure we un-compile the value if it was set to something else.
753     attr->compiled_value = {};
754     attr->value = options_.compile_sdk_version_codename.value();
755 
756     attr = root->FindOrCreateAttribute("", "platformBuildVersionName");
757 
758     // Make sure we un-compile the value if it was set to something else.
759     attr->compiled_value = {};
760     attr->value = options_.compile_sdk_version_codename.value();
761   }
762 
763   if (!options_.fingerprint_prefixes.empty()) {
764     xml::Element* install_constraints_el = root->FindChild({}, "install-constraints");
765     if (install_constraints_el == nullptr) {
766       std::unique_ptr<xml::Element> install_constraints = std::make_unique<xml::Element>();
767       install_constraints->name = "install-constraints";
768       install_constraints_el = install_constraints.get();
769       root->AppendChild(std::move(install_constraints));
770     }
771     for (const std::string& prefix : options_.fingerprint_prefixes) {
772       std::unique_ptr<xml::Element> prefix_el = std::make_unique<xml::Element>();
773       prefix_el->name = "fingerprint-prefix";
774       xml::Attribute* attr = prefix_el->FindOrCreateAttribute(xml::kSchemaAndroid, "value");
775       attr->value = prefix;
776       install_constraints_el->AppendChild(std::move(prefix_el));
777     }
778   }
779 
780   xml::XmlActionExecutor executor;
781   if (!BuildRules(&executor, context->GetDiagnostics())) {
782     return false;
783   }
784 
785   xml::XmlActionExecutorPolicy policy = options_.warn_validation
786                                             ? xml::XmlActionExecutorPolicy::kAllowListWarning
787                                             : xml::XmlActionExecutorPolicy::kAllowList;
788   if (!executor.Execute(policy, context->GetDiagnostics(), doc)) {
789     return false;
790   }
791 
792   if (options_.rename_manifest_package) {
793     // Rename manifest package outside of the XmlActionExecutor.
794     // We need to extract the old package name and FullyQualify all class
795     // names.
796     if (!RenameManifestPackage(options_.rename_manifest_package.value(), root)) {
797       return false;
798     }
799   }
800   return true;
801 }
802 
803 }  // namespace aapt
804