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