xref: /aosp_15_r20/frameworks/base/tools/aapt2/link/ManifestFixer.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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 "ResourceUtils.h"
22 #include "android-base/logging.h"
23 #include "process/SymbolTable.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 
UpdateConfigChangesIfNeeded(xml::Element * el,IAaptContext * context)175 static bool UpdateConfigChangesIfNeeded(xml::Element* el, IAaptContext* context) {
176   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "configChanges");
177   if (attr == nullptr) {
178     return true;
179   }
180 
181   if (attr->value != "allKnown" && attr->value.find("allKnown") != std::string::npos) {
182     context->GetDiagnostics()->Error(
183         android::DiagMessage(el->line_number)
184         << "If you want to declare 'allKnown' in attribute 'android:configChanges' in <" << el->name
185         << ">, " << attr->value << " is not allowed', allKnown has to be used "
186         << "by itself, for example: 'android:configChanges=allKnown', it cannot be combined with "
187         << "the other flags");
188     return false;
189   }
190 
191   if (attr->value == "allKnown") {
192     SymbolTable* symbol_table = context->GetExternalSymbols();
193     const SymbolTable::Symbol* symbol =
194         symbol_table->FindByName(ResourceName("android", ResourceType::kAttr, "configChanges"));
195 
196     if (symbol == nullptr) {
197       context->GetDiagnostics()->Error(
198           android::DiagMessage(el->line_number)
199           << "Cannot find symbol for android:configChanges with min sdk: "
200           << context->GetMinSdkVersion());
201       return false;
202     }
203 
204     std::stringstream new_value;
205 
206     const auto& symbols = symbol->attribute->symbols;
207     for (auto it = symbols.begin(); it != symbols.end(); ++it) {
208       // Skip 'resourcesUnused' which is the flag to fully disable activity restart specifically
209       // for games.
210       if (it->symbol.name.value().entry == "resourcesUnused") {
211         continue;
212       }
213       if (it != symbols.begin()) {
214         new_value << "|";
215       }
216       new_value << it->symbol.name.value().entry;
217     }
218     const auto& old_value = attr->value;
219     auto new_value_str = new_value.str();
220     context->GetDiagnostics()->Note(android::DiagMessage(el->line_number)
221                                     << "Updating value of 'android:configChanges' from "
222                                     << old_value << " to " << new_value_str);
223     attr->value = std::move(new_value_str);
224   }
225   return true;
226 }
227 
RequiredNameIsJavaPackage(xml::Element * el,android::SourcePathDiagnostics * diag)228 static bool RequiredNameIsJavaPackage(xml::Element* el, android::SourcePathDiagnostics* diag) {
229   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
230   if (attr == nullptr) {
231     diag->Error(android::DiagMessage(el->line_number)
232                 << "<" << el->name << "> is missing attribute 'android:name'");
233     return false;
234   }
235 
236   if (!util::IsJavaPackageName(attr->value)) {
237     diag->Error(android::DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
238                                                       << "> tag must be a valid Java package name");
239     return false;
240   }
241   return true;
242 }
243 
RequiredAndroidAttribute(const std::string & attr)244 static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std::string& attr) {
245   return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
246     if (el->FindAttribute(xml::kSchemaAndroid, attr) == nullptr) {
247       diag->Error(android::DiagMessage(el->line_number)
248                   << "<" << el->name << "> is missing required attribute 'android:" << attr << "'");
249       return false;
250     }
251     return true;
252   };
253 }
254 
RequiredOneAndroidAttribute(const std::string & attrName1,const std::string & attrName2)255 static xml::XmlNodeAction::ActionFuncWithDiag RequiredOneAndroidAttribute(
256     const std::string& attrName1, const std::string& attrName2) {
257   return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
258     xml::Attribute* attr1 = el->FindAttribute(xml::kSchemaAndroid, attrName1);
259     xml::Attribute* attr2 = el->FindAttribute(xml::kSchemaAndroid, attrName2);
260     if (attr1 == nullptr && attr2 == nullptr) {
261       diag->Error(android::DiagMessage(el->line_number)
262                   << "<" << el->name << "> is missing required attribute 'android:" << attrName1
263                   << "' or 'android:" << attrName2 << "'");
264       return false;
265     }
266     if (attr1 != nullptr && attr2 != nullptr) {
267       diag->Error(android::DiagMessage(el->line_number)
268                   << "<" << el->name << "> can only specify one of attribute 'android:" << attrName1
269                   << "' or 'android:" << attrName2 << "'");
270       return false;
271     }
272     return true;
273   };
274 }
275 
AutoGenerateIsFeatureSplit(xml::Element * el,android::SourcePathDiagnostics * diag)276 static bool AutoGenerateIsFeatureSplit(xml::Element* el, android::SourcePathDiagnostics* diag) {
277   constexpr const char* kFeatureSplit = "featureSplit";
278   constexpr const char* kIsFeatureSplit = "isFeatureSplit";
279 
280   xml::Attribute* attr = el->FindAttribute({}, kFeatureSplit);
281   if (attr != nullptr) {
282     // Rewrite the featureSplit attribute to be "split". This is what the
283     // platform recognizes.
284     attr->name = "split";
285 
286     // Now inject the android:isFeatureSplit="true" attribute.
287     xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsFeatureSplit);
288     if (attr != nullptr) {
289       if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
290         // The isFeatureSplit attribute is false, which conflicts with the use
291         // of "featureSplit".
292         diag->Error(android::DiagMessage(el->line_number)
293                     << "attribute 'featureSplit' used in <manifest> but 'android:isFeatureSplit' "
294                        "is not 'true'");
295         return false;
296       }
297 
298       // The attribute is already there and set to true, nothing to do.
299     } else {
300       el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsFeatureSplit, "true"});
301     }
302   }
303   return true;
304 }
305 
AutoGenerateIsSplitRequired(xml::Element * el,android::SourcePathDiagnostics * diag)306 static bool AutoGenerateIsSplitRequired(xml::Element* el, android::SourcePathDiagnostics* diag) {
307   constexpr const char* kRequiredSplitTypes = "requiredSplitTypes";
308   constexpr const char* kIsSplitRequired = "isSplitRequired";
309 
310   xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kRequiredSplitTypes);
311   if (attr != nullptr) {
312     // Now inject the android:isSplitRequired="true" attribute.
313     xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsSplitRequired);
314     if (attr != nullptr) {
315       if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
316         // The isFeatureSplit attribute is false, which conflicts with the use
317         // of "featureSplit".
318         diag->Error(android::DiagMessage(el->line_number)
319                     << "attribute 'requiredSplitTypes' used in <manifest> but "
320                        "'android:isSplitRequired' is not 'true'");
321         return false;
322       }
323       // The attribute is already there and set to true, nothing to do.
324     } else {
325       el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsSplitRequired, "true"});
326     }
327   }
328   return true;
329 }
330 
VerifyManifest(xml::Element * el,xml::XmlActionExecutorPolicy policy,android::SourcePathDiagnostics * diag)331 static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy,
332                            android::SourcePathDiagnostics* diag) {
333   xml::Attribute* attr = el->FindAttribute({}, "package");
334   if (!attr) {
335     diag->Error(android::DiagMessage(el->line_number)
336                 << "<manifest> tag is missing 'package' attribute");
337     return false;
338   } else if (ResourceUtils::IsReference(attr->value)) {
339     diag->Error(android::DiagMessage(el->line_number)
340                 << "attribute 'package' in <manifest> tag must not be a reference");
341     return false;
342   } else if (!util::IsAndroidPackageName(attr->value)) {
343     android::DiagMessage error_msg(el->line_number);
344     error_msg << "attribute 'package' in <manifest> tag is not a valid Android package name: '"
345               << attr->value << "'";
346     if (policy == xml::XmlActionExecutorPolicy::kAllowListWarning) {
347       // Treat the error only as a warning.
348       diag->Warn(error_msg);
349     } else {
350       diag->Error(error_msg);
351       return false;
352     }
353   }
354 
355   attr = el->FindAttribute({}, "split");
356   if (attr) {
357     if (!util::IsJavaPackageName(attr->value)) {
358       diag->Error(android::DiagMessage(el->line_number)
359                   << "attribute 'split' in <manifest> tag is not a "
360                      "valid split name");
361       return false;
362     }
363   }
364   return true;
365 }
366 
367 // The coreApp attribute in <manifest> is not a regular AAPT attribute, so type
368 // checking on it is manual.
FixCoreAppAttribute(xml::Element * el,android::SourcePathDiagnostics * diag)369 static bool FixCoreAppAttribute(xml::Element* el, android::SourcePathDiagnostics* diag) {
370   if (xml::Attribute* attr = el->FindAttribute("", "coreApp")) {
371     std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseBool(attr->value);
372     if (!result) {
373       diag->Error(android::DiagMessage(el->line_number) << "attribute coreApp must be a boolean");
374       return false;
375     }
376     attr->compiled_value = std::move(result);
377   }
378   return true;
379 }
380 
381 // Checks that <uses-feature> has android:glEsVersion or android:name, not both (or neither).
VerifyUsesFeature(xml::Element * el,android::SourcePathDiagnostics * diag)382 static bool VerifyUsesFeature(xml::Element* el, android::SourcePathDiagnostics* diag) {
383   bool has_name = false;
384   if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
385     if (attr->value.empty()) {
386       diag->Error(android::DiagMessage(el->line_number)
387                   << "android:name in <uses-feature> must not be empty");
388       return false;
389     }
390     has_name = true;
391   }
392 
393   bool has_gl_es_version = false;
394   if (el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
395     if (has_name) {
396       diag->Error(android::DiagMessage(el->line_number)
397                   << "cannot define both android:name and android:glEsVersion in <uses-feature>");
398       return false;
399     }
400     has_gl_es_version = true;
401   }
402 
403   if (!has_name && !has_gl_es_version) {
404     diag->Error(android::DiagMessage(el->line_number)
405                 << "<uses-feature> must have either android:name or android:glEsVersion attribute");
406     return false;
407   }
408   return true;
409 }
410 
411 // Ensure that 'ns_decls' contains a declaration for 'uri', using 'prefix' as
412 // the xmlns prefix if possible.
EnsureNamespaceIsDeclared(const std::string & prefix,const std::string & uri,std::vector<xml::NamespaceDecl> * ns_decls)413 static void EnsureNamespaceIsDeclared(const std::string& prefix, const std::string& uri,
414                                       std::vector<xml::NamespaceDecl>* ns_decls) {
415   if (std::find_if(ns_decls->begin(), ns_decls->end(), [&](const xml::NamespaceDecl& ns_decl) {
416         return ns_decl.uri == uri;
417       }) != ns_decls->end()) {
418     return;
419   }
420 
421   std::set<std::string> used_prefixes;
422   for (const auto& ns_decl : *ns_decls) {
423     used_prefixes.insert(ns_decl.prefix);
424   }
425 
426   // Make multiple attempts in the unlikely event that 'prefix' is already taken.
427   std::string disambiguator;
428   for (int i = 0; i < used_prefixes.size() + 1; i++) {
429     std::string attempted_prefix = prefix + disambiguator;
430     if (used_prefixes.find(attempted_prefix) == used_prefixes.end()) {
431       ns_decls->push_back(xml::NamespaceDecl{attempted_prefix, uri});
432       return;
433     }
434     disambiguator = std::to_string(i);
435   }
436 }
437 
BuildRules(xml::XmlActionExecutor * executor,IAaptContext * context)438 bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, IAaptContext* context) {
439   // First verify some options.
440   android::IDiagnostics* diag = context->GetDiagnostics();
441   if (options_.rename_manifest_package) {
442     if (!util::IsJavaPackageName(options_.rename_manifest_package.value())) {
443       diag->Error(android::DiagMessage() << "invalid manifest package override '"
444                                          << options_.rename_manifest_package.value() << "'");
445       return false;
446     }
447   }
448 
449   if (options_.rename_instrumentation_target_package) {
450     if (!util::IsJavaPackageName(options_.rename_instrumentation_target_package.value())) {
451       diag->Error(android::DiagMessage()
452                   << "invalid instrumentation target package override '"
453                   << options_.rename_instrumentation_target_package.value() << "'");
454       return false;
455     }
456   }
457 
458   if (options_.rename_overlay_target_package) {
459     if (!util::IsJavaPackageName(options_.rename_overlay_target_package.value())) {
460       diag->Error(android::DiagMessage() << "invalid overlay target package override '"
461                                          << options_.rename_overlay_target_package.value() << "'");
462       return false;
463     }
464   }
465 
466   // Common <intent-filter> actions.
467   xml::XmlNodeAction intent_filter_action;
468   intent_filter_action.Action(VerifyDeepLinkIntentAction);
469   intent_filter_action["action"].Action(RequiredNameIsNotEmpty);
470   intent_filter_action["category"].Action(RequiredNameIsNotEmpty);
471   intent_filter_action["data"];
472   intent_filter_action["uri-relative-filter-group"];
473   intent_filter_action["uri-relative-filter-group"]["data"];
474 
475   // Common <meta-data> actions.
476   xml::XmlNodeAction meta_data_action;
477 
478   // Common <property> actions.
479   xml::XmlNodeAction property_action;
480   property_action.Action(RequiredOneAndroidAttribute("resource", "value"));
481 
482   // Common <uses-feature> actions.
483   xml::XmlNodeAction uses_feature_action;
484   uses_feature_action.Action(VerifyUsesFeature);
485 
486   // Common component actions.
487   xml::XmlNodeAction component_action;
488   component_action.Action(RequiredNameIsJavaClassName);
489   component_action.Action(
490       [context](xml::Element* el) -> bool { return UpdateConfigChangesIfNeeded(el, context); });
491   component_action["intent-filter"] = intent_filter_action;
492   component_action["preferred"] = intent_filter_action;
493   component_action["meta-data"] = meta_data_action;
494   component_action["property"] = property_action;
495 
496   // Manifest actions.
497   xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
498   manifest_action.Action(AutoGenerateIsFeatureSplit);
499   manifest_action.Action(AutoGenerateIsSplitRequired);
500   manifest_action.Action(VerifyManifest);
501   manifest_action.Action(FixCoreAppAttribute);
502   manifest_action.Action([this, diag](xml::Element* el) -> bool {
503     EnsureNamespaceIsDeclared("android", xml::kSchemaAndroid, &el->namespace_decls);
504 
505     if (options_.version_name_default) {
506       if (options_.replace_version) {
507         el->RemoveAttribute(xml::kSchemaAndroid, "versionName");
508       }
509       if (el->FindAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
510         el->attributes.push_back(
511             xml::Attribute{xml::kSchemaAndroid, "versionName",
512                            options_.version_name_default.value()});
513       }
514     }
515 
516     if (options_.version_code_default) {
517       if (options_.replace_version) {
518         el->RemoveAttribute(xml::kSchemaAndroid, "versionCode");
519       }
520       if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
521         el->attributes.push_back(
522             xml::Attribute{xml::kSchemaAndroid, "versionCode",
523                            options_.version_code_default.value()});
524       }
525     }
526 
527     if (options_.version_code_major_default) {
528       if (options_.replace_version) {
529         el->RemoveAttribute(xml::kSchemaAndroid, "versionCodeMajor");
530       }
531       if (el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor") == nullptr) {
532         el->attributes.push_back(
533             xml::Attribute{xml::kSchemaAndroid, "versionCodeMajor",
534                            options_.version_code_major_default.value()});
535       }
536     }
537 
538     if (options_.revision_code_default) {
539       if (options_.replace_version) {
540         el->RemoveAttribute(xml::kSchemaAndroid, "revisionCode");
541       }
542       if (el->FindAttribute(xml::kSchemaAndroid, "revisionCode") == nullptr) {
543         el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "revisionCode",
544                                                 options_.revision_code_default.value()});
545       }
546     }
547 
548     if (options_.non_updatable_system) {
549       if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
550         el->RemoveAttribute("", "updatableSystem");
551         el->attributes.push_back(xml::Attribute{"", "updatableSystem", "false"});
552       } else {
553         diag->Note(android::DiagMessage(el->line_number)
554                    << "Ignoring --non-updatable-system because the manifest has a versionCode");
555       }
556     }
557 
558     return true;
559   });
560 
561   // Meta tags.
562   manifest_action["eat-comment"];
563 
564   // Uses-sdk actions.
565   manifest_action["uses-sdk"].Action([this](xml::Element* el) -> bool {
566     if (options_.min_sdk_version_default &&
567         el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
568       // There was no minSdkVersion defined and we have a default to assign.
569       el->attributes.push_back(
570           xml::Attribute{xml::kSchemaAndroid, "minSdkVersion",
571                          options_.min_sdk_version_default.value()});
572     }
573 
574     if (options_.target_sdk_version_default &&
575         el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion") == nullptr) {
576       // There was no targetSdkVersion defined and we have a default to assign.
577       el->attributes.push_back(
578           xml::Attribute{xml::kSchemaAndroid, "targetSdkVersion",
579                          options_.target_sdk_version_default.value()});
580     }
581     return true;
582   });
583   manifest_action["uses-sdk"]["extension-sdk"];
584 
585   // Instrumentation actions.
586   manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
587   manifest_action["instrumentation"].Action([this](xml::Element* el) -> bool {
588     if (!options_.rename_instrumentation_target_package) {
589       return true;
590     }
591 
592     if (xml::Attribute* attr =
593             el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
594       attr->value = options_.rename_instrumentation_target_package.value();
595     }
596     return true;
597   });
598   manifest_action["instrumentation"]["meta-data"] = meta_data_action;
599 
600   manifest_action["attribution"];
601   manifest_action["attribution"]["inherit-from"];
602   manifest_action["original-package"];
603   manifest_action["overlay"].Action([this](xml::Element* el) -> bool {
604     if (options_.rename_overlay_target_package) {
605       if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
606         attr->value = options_.rename_overlay_target_package.value();
607       }
608     }
609     if (options_.rename_overlay_category) {
610       if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "category")) {
611         attr->value = options_.rename_overlay_category.value();
612       } else {
613         el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "category",
614                                                 options_.rename_overlay_category.value()});
615       }
616     }
617     return true;
618   });
619   manifest_action["protected-broadcast"];
620   manifest_action["adopt-permissions"];
621   manifest_action["uses-permission"];
622   manifest_action["uses-permission"]["required-feature"].Action(RequiredNameIsNotEmpty);
623   manifest_action["uses-permission"]["required-not-feature"].Action(RequiredNameIsNotEmpty);
624   manifest_action["uses-permission-sdk-23"];
625   manifest_action["permission"];
626   manifest_action["permission"]["meta-data"] = meta_data_action;
627   manifest_action["permission-tree"];
628   manifest_action["permission-group"];
629   manifest_action["uses-configuration"];
630   manifest_action["supports-screens"];
631   manifest_action["uses-feature"] = uses_feature_action;
632   manifest_action["feature-group"]["uses-feature"] = uses_feature_action;
633   manifest_action["compatible-screens"];
634   manifest_action["compatible-screens"]["screen"];
635   manifest_action["supports-gl-texture"];
636   manifest_action["restrict-update"];
637   manifest_action["install-constraints"]["fingerprint-prefix"];
638   manifest_action["package-verifier"];
639   manifest_action["meta-data"] = meta_data_action;
640   manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
641   manifest_action["queries"]["package"].Action(RequiredNameIsJavaPackage);
642   manifest_action["queries"]["intent"] = intent_filter_action;
643   manifest_action["queries"]["provider"].Action(RequiredAndroidAttribute("authorities"));
644   // TODO: more complicated component name tag
645 
646   manifest_action["key-sets"]["key-set"]["public-key"];
647   manifest_action["key-sets"]["upgrade-key-set"];
648 
649   // Application actions.
650   xml::XmlNodeAction& application_action = manifest_action["application"];
651   application_action.Action(OptionalNameIsJavaClassName);
652 
653   application_action["uses-library"].Action(RequiredNameIsNotEmpty);
654   application_action["uses-native-library"].Action(RequiredNameIsNotEmpty);
655   application_action["library"].Action(RequiredNameIsNotEmpty);
656   application_action["profileable"];
657   application_action["property"] = property_action;
658 
659   xml::XmlNodeAction& static_library_action = application_action["static-library"];
660   static_library_action.Action(RequiredNameIsJavaPackage);
661   static_library_action.Action(RequiredAndroidAttribute("version"));
662 
663   xml::XmlNodeAction& uses_static_library_action = application_action["uses-static-library"];
664   uses_static_library_action.Action(RequiredNameIsJavaPackage);
665   uses_static_library_action.Action(RequiredAndroidAttribute("version"));
666   uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
667   uses_static_library_action["additional-certificate"];
668 
669   xml::XmlNodeAction& sdk_library_action = application_action["sdk-library"];
670   sdk_library_action.Action(RequiredNameIsJavaPackage);
671   sdk_library_action.Action(RequiredAndroidAttribute("versionMajor"));
672 
673   xml::XmlNodeAction& uses_sdk_library_action = application_action["uses-sdk-library"];
674   uses_sdk_library_action.Action(RequiredNameIsJavaPackage);
675   uses_sdk_library_action.Action(RequiredAndroidAttribute("versionMajor"));
676   uses_sdk_library_action.Action(RequiredAndroidAttribute("certDigest"));
677   uses_sdk_library_action["additional-certificate"];
678 
679   xml::XmlNodeAction& uses_package_action = application_action["uses-package"];
680   uses_package_action.Action(RequiredNameIsJavaPackage);
681   uses_package_action["additional-certificate"];
682 
683   if (options_.debug_mode) {
684     application_action.Action([](xml::Element* el) -> bool {
685       xml::Attribute *attr = el->FindOrCreateAttribute(xml::kSchemaAndroid, "debuggable");
686       attr->value = "true";
687       return true;
688     });
689   }
690 
691   application_action["meta-data"] = meta_data_action;
692 
693   application_action["processes"];
694   application_action["processes"]["deny-permission"];
695   application_action["processes"]["allow-permission"];
696   application_action["processes"]["process"]["deny-permission"];
697   application_action["processes"]["process"]["allow-permission"];
698 
699   application_action["activity"] = component_action;
700   application_action["activity"]["layout"];
701 
702   application_action["activity-alias"] = component_action;
703   application_action["service"] = component_action;
704   application_action["receiver"] = component_action;
705   application_action["apex-system-service"] = component_action;
706 
707   // Provider actions.
708   application_action["provider"] = component_action;
709   application_action["provider"]["grant-uri-permission"];
710   application_action["provider"]["path-permission"];
711 
712   manifest_action["package"] = manifest_action;
713 
714   return true;
715 }
716 
FullyQualifyClassName(StringPiece package,StringPiece attr_ns,StringPiece attr_name,xml::Element * el)717 static void FullyQualifyClassName(StringPiece package, StringPiece attr_ns, StringPiece attr_name,
718                                   xml::Element* el) {
719   xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
720   if (attr != nullptr) {
721     if (std::optional<std::string> new_value =
722             util::GetFullyQualifiedClassName(package, attr->value)) {
723       attr->value = std::move(new_value.value());
724     }
725   }
726 }
727 
RenameManifestPackage(StringPiece package_override,xml::Element * manifest_el)728 static bool RenameManifestPackage(StringPiece package_override, xml::Element* manifest_el) {
729   xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
730 
731   // We've already verified that the manifest element is present, with a package
732   // name specified.
733   CHECK(attr != nullptr);
734 
735   std::string original_package = std::move(attr->value);
736   attr->value.assign(package_override);
737 
738   xml::Element* application_el = manifest_el->FindChild({}, "application");
739   if (application_el != nullptr) {
740     FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", application_el);
741     FullyQualifyClassName(original_package, xml::kSchemaAndroid, "backupAgent", application_el);
742 
743     for (xml::Element* child_el : application_el->GetChildElements()) {
744       if (child_el->namespace_uri.empty()) {
745         if (child_el->name == "activity" || child_el->name == "activity-alias" ||
746             child_el->name == "provider" || child_el->name == "receiver" ||
747             child_el->name == "service") {
748           FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", child_el);
749           continue;
750         }
751 
752         if (child_el->name == "activity-alias") {
753           FullyQualifyClassName(original_package, xml::kSchemaAndroid, "targetActivity", child_el);
754           continue;
755         }
756 
757         if (child_el->name == "processes") {
758           for (xml::Element* grand_child_el : child_el->GetChildElements()) {
759             if (grand_child_el->name == "process") {
760               FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", grand_child_el);
761             }
762           }
763           continue;
764         }
765       }
766     }
767   }
768   return true;
769 }
770 
Consume(IAaptContext * context,xml::XmlResource * doc)771 bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
772   TRACE_CALL();
773   xml::Element* root = xml::FindRootElement(doc->root.get());
774   if (!root || !root->namespace_uri.empty() || root->name != "manifest") {
775     context->GetDiagnostics()->Error(android::DiagMessage(doc->file.source)
776                                      << "root tag must be <manifest>");
777     return false;
778   }
779 
780   if ((options_.min_sdk_version_default || options_.target_sdk_version_default) &&
781       root->FindChild({}, "uses-sdk") == nullptr) {
782     // Auto insert a <uses-sdk> element. This must be inserted before the
783     // <application> tag. The device runtime PackageParser will make SDK version
784     // decisions while parsing <application>.
785     std::unique_ptr<xml::Element> uses_sdk = util::make_unique<xml::Element>();
786     uses_sdk->name = "uses-sdk";
787     root->InsertChild(0, std::move(uses_sdk));
788   }
789 
790   if (!options_.no_compile_sdk_metadata && options_.compile_sdk_version) {
791     xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion");
792 
793     // Make sure we un-compile the value if it was set to something else.
794     attr->compiled_value = {};
795     attr->value = options_.compile_sdk_version.value();
796 
797     attr = root->FindOrCreateAttribute("", "platformBuildVersionCode");
798 
799     // Make sure we un-compile the value if it was set to something else.
800     attr->compiled_value = {};
801     attr->value = options_.compile_sdk_version.value();
802   }
803 
804   if (!options_.no_compile_sdk_metadata && options_.compile_sdk_version_codename) {
805     xml::Attribute* attr =
806         root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
807 
808     // Make sure we un-compile the value if it was set to something else.
809     attr->compiled_value = {};
810     attr->value = options_.compile_sdk_version_codename.value();
811 
812     attr = root->FindOrCreateAttribute("", "platformBuildVersionName");
813 
814     // Make sure we un-compile the value if it was set to something else.
815     attr->compiled_value = {};
816     attr->value = options_.compile_sdk_version_codename.value();
817   }
818 
819   if (!options_.fingerprint_prefixes.empty()) {
820     xml::Element* install_constraints_el = root->FindChild({}, "install-constraints");
821     if (install_constraints_el == nullptr) {
822       std::unique_ptr<xml::Element> install_constraints = std::make_unique<xml::Element>();
823       install_constraints->name = "install-constraints";
824       install_constraints_el = install_constraints.get();
825       root->AppendChild(std::move(install_constraints));
826     }
827     for (const std::string& prefix : options_.fingerprint_prefixes) {
828       std::unique_ptr<xml::Element> prefix_el = std::make_unique<xml::Element>();
829       prefix_el->name = "fingerprint-prefix";
830       xml::Attribute* attr = prefix_el->FindOrCreateAttribute(xml::kSchemaAndroid, "value");
831       attr->value = prefix;
832       install_constraints_el->AppendChild(std::move(prefix_el));
833     }
834   }
835 
836   xml::XmlActionExecutor executor;
837   if (!BuildRules(&executor, context)) {
838     return false;
839   }
840 
841   xml::XmlActionExecutorPolicy policy = options_.warn_validation
842                                             ? xml::XmlActionExecutorPolicy::kAllowListWarning
843                                             : xml::XmlActionExecutorPolicy::kAllowList;
844   if (!executor.Execute(policy, context->GetDiagnostics(), doc)) {
845     return false;
846   }
847 
848   if (options_.rename_manifest_package) {
849     // Rename manifest package outside of the XmlActionExecutor.
850     // We need to extract the old package name and FullyQualify all class
851     // names.
852     if (!RenameManifestPackage(options_.rename_manifest_package.value(), root)) {
853       return false;
854     }
855   }
856   return true;
857 }
858 
859 }  // namespace aapt
860