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