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