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   // Common <intent-filter> actions.
240   xml::XmlNodeAction intent_filter_action;
241   intent_filter_action["action"].Action(RequiredNameIsNotEmpty);
242   intent_filter_action["category"].Action(RequiredNameIsNotEmpty);
243   intent_filter_action["data"];
244 
245   // Common <meta-data> actions.
246   xml::XmlNodeAction meta_data_action;
247 
248   // Common <uses-feature> actions.
249   xml::XmlNodeAction uses_feature_action;
250   uses_feature_action.Action(VerifyUsesFeature);
251 
252   // Common component actions.
253   xml::XmlNodeAction component_action;
254   component_action.Action(RequiredNameIsJavaClassName);
255   component_action["intent-filter"] = intent_filter_action;
256   component_action["preferred"] = intent_filter_action;
257   component_action["meta-data"] = meta_data_action;
258 
259   // Manifest actions.
260   xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
261   manifest_action.Action(AutoGenerateIsFeatureSplit);
262   manifest_action.Action(VerifyManifest);
263   manifest_action.Action(FixCoreAppAttribute);
264   manifest_action.Action([&](xml::Element* el) -> bool {
265     if (options_.version_name_default) {
266       if (options_.replace_version) {
267         el->RemoveAttribute(xml::kSchemaAndroid, "versionName");
268       }
269       if (el->FindAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
270         el->attributes.push_back(
271             xml::Attribute{xml::kSchemaAndroid, "versionName",
272                            options_.version_name_default.value()});
273       }
274     }
275 
276     if (options_.version_code_default) {
277       if (options_.replace_version) {
278         el->RemoveAttribute(xml::kSchemaAndroid, "versionCode");
279       }
280       if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
281         el->attributes.push_back(
282             xml::Attribute{xml::kSchemaAndroid, "versionCode",
283                            options_.version_code_default.value()});
284       }
285     }
286 
287     if (options_.version_code_major_default) {
288       if (options_.replace_version) {
289         el->RemoveAttribute(xml::kSchemaAndroid, "versionCodeMajor");
290       }
291       if (el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor") == nullptr) {
292         el->attributes.push_back(
293             xml::Attribute{xml::kSchemaAndroid, "versionCodeMajor",
294                            options_.version_code_major_default.value()});
295       }
296     }
297 
298     return true;
299   });
300 
301   // Meta tags.
302   manifest_action["eat-comment"];
303 
304   // Uses-sdk actions.
305   manifest_action["uses-sdk"].Action([&](xml::Element* el) -> bool {
306     if (options_.min_sdk_version_default &&
307         el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
308       // There was no minSdkVersion defined and we have a default to assign.
309       el->attributes.push_back(
310           xml::Attribute{xml::kSchemaAndroid, "minSdkVersion",
311                          options_.min_sdk_version_default.value()});
312     }
313 
314     if (options_.target_sdk_version_default &&
315         el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion") == nullptr) {
316       // There was no targetSdkVersion defined and we have a default to assign.
317       el->attributes.push_back(
318           xml::Attribute{xml::kSchemaAndroid, "targetSdkVersion",
319                          options_.target_sdk_version_default.value()});
320     }
321     return true;
322   });
323 
324   // Instrumentation actions.
325   manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
326   manifest_action["instrumentation"].Action([&](xml::Element* el) -> bool {
327     if (!options_.rename_instrumentation_target_package) {
328       return true;
329     }
330 
331     if (xml::Attribute* attr =
332             el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
333       attr->value = options_.rename_instrumentation_target_package.value();
334     }
335     return true;
336   });
337   manifest_action["instrumentation"]["meta-data"] = meta_data_action;
338 
339   manifest_action["original-package"];
340   manifest_action["overlay"];
341   manifest_action["protected-broadcast"];
342   manifest_action["adopt-permissions"];
343   manifest_action["uses-permission"];
344   manifest_action["uses-permission-sdk-23"];
345   manifest_action["permission"];
346   manifest_action["permission"]["meta-data"] = meta_data_action;
347   manifest_action["permission-tree"];
348   manifest_action["permission-group"];
349   manifest_action["uses-configuration"];
350   manifest_action["supports-screens"];
351   manifest_action["uses-feature"] = uses_feature_action;
352   manifest_action["feature-group"]["uses-feature"] = uses_feature_action;
353   manifest_action["compatible-screens"];
354   manifest_action["compatible-screens"]["screen"];
355   manifest_action["supports-gl-texture"];
356   manifest_action["restrict-update"];
357   manifest_action["package-verifier"];
358   manifest_action["meta-data"] = meta_data_action;
359   manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
360 
361   manifest_action["key-sets"]["key-set"]["public-key"];
362   manifest_action["key-sets"]["upgrade-key-set"];
363 
364   // Application actions.
365   xml::XmlNodeAction& application_action = manifest_action["application"];
366   application_action.Action(OptionalNameIsJavaClassName);
367 
368   application_action["uses-library"].Action(RequiredNameIsNotEmpty);
369   application_action["library"].Action(RequiredNameIsNotEmpty);
370   application_action["profileable"];
371 
372   xml::XmlNodeAction& static_library_action = application_action["static-library"];
373   static_library_action.Action(RequiredNameIsJavaPackage);
374   static_library_action.Action(RequiredAndroidAttribute("version"));
375 
376   xml::XmlNodeAction& uses_static_library_action = application_action["uses-static-library"];
377   uses_static_library_action.Action(RequiredNameIsJavaPackage);
378   uses_static_library_action.Action(RequiredAndroidAttribute("version"));
379   uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
380   uses_static_library_action["additional-certificate"];
381 
382   xml::XmlNodeAction& uses_package_action = application_action["uses-package"];
383   uses_package_action.Action(RequiredNameIsJavaPackage);
384   uses_package_action["additional-certificate"];
385 
386   if (options_.debug_mode) {
387     application_action.Action([&](xml::Element* el) -> bool {
388       xml::Attribute *attr = el->FindOrCreateAttribute(xml::kSchemaAndroid, "debuggable");
389       attr->value = "true";
390       return true;
391     });
392   }
393 
394   application_action["meta-data"] = meta_data_action;
395 
396   application_action["activity"] = component_action;
397   application_action["activity"]["layout"];
398 
399   application_action["activity-alias"] = component_action;
400   application_action["service"] = component_action;
401   application_action["receiver"] = component_action;
402 
403   // Provider actions.
404   application_action["provider"] = component_action;
405   application_action["provider"]["grant-uri-permission"];
406   application_action["provider"]["path-permission"];
407 
408   manifest_action["package"] = manifest_action;
409 
410   return true;
411 }
412 
FullyQualifyClassName(const StringPiece & package,const StringPiece & attr_ns,const StringPiece & attr_name,xml::Element * el)413 static void FullyQualifyClassName(const StringPiece& package, const StringPiece& attr_ns,
414                                   const StringPiece& attr_name, xml::Element* el) {
415   xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
416   if (attr != nullptr) {
417     if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package, attr->value)) {
418       attr->value = std::move(new_value.value());
419     }
420   }
421 }
422 
RenameManifestPackage(const StringPiece & package_override,xml::Element * manifest_el)423 static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) {
424   xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
425 
426   // We've already verified that the manifest element is present, with a package
427   // name specified.
428   CHECK(attr != nullptr);
429 
430   std::string original_package = std::move(attr->value);
431   attr->value = package_override.to_string();
432 
433   xml::Element* application_el = manifest_el->FindChild({}, "application");
434   if (application_el != nullptr) {
435     FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", application_el);
436     FullyQualifyClassName(original_package, xml::kSchemaAndroid, "backupAgent", application_el);
437 
438     for (xml::Element* child_el : application_el->GetChildElements()) {
439       if (child_el->namespace_uri.empty()) {
440         if (child_el->name == "activity" || child_el->name == "activity-alias" ||
441             child_el->name == "provider" || child_el->name == "receiver" ||
442             child_el->name == "service") {
443           FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", child_el);
444         }
445 
446         if (child_el->name == "activity-alias") {
447           FullyQualifyClassName(original_package, xml::kSchemaAndroid, "targetActivity", child_el);
448         }
449       }
450     }
451   }
452   return true;
453 }
454 
Consume(IAaptContext * context,xml::XmlResource * doc)455 bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
456   TRACE_CALL();
457   xml::Element* root = xml::FindRootElement(doc->root.get());
458   if (!root || !root->namespace_uri.empty() || root->name != "manifest") {
459     context->GetDiagnostics()->Error(DiagMessage(doc->file.source)
460                                      << "root tag must be <manifest>");
461     return false;
462   }
463 
464   if ((options_.min_sdk_version_default || options_.target_sdk_version_default) &&
465       root->FindChild({}, "uses-sdk") == nullptr) {
466     // Auto insert a <uses-sdk> element. This must be inserted before the
467     // <application> tag. The device runtime PackageParser will make SDK version
468     // decisions while parsing <application>.
469     std::unique_ptr<xml::Element> uses_sdk = util::make_unique<xml::Element>();
470     uses_sdk->name = "uses-sdk";
471     root->InsertChild(0, std::move(uses_sdk));
472   }
473 
474   if (options_.compile_sdk_version) {
475     xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion");
476 
477     // Make sure we un-compile the value if it was set to something else.
478     attr->compiled_value = {};
479     attr->value = options_.compile_sdk_version.value();
480 
481     attr = root->FindOrCreateAttribute("", "platformBuildVersionCode");
482 
483     // Make sure we un-compile the value if it was set to something else.
484     attr->compiled_value = {};
485     attr->value = options_.compile_sdk_version.value();
486 
487   }
488 
489   if (options_.compile_sdk_version_codename) {
490     xml::Attribute* attr =
491         root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
492 
493     // Make sure we un-compile the value if it was set to something else.
494     attr->compiled_value = {};
495     attr->value = options_.compile_sdk_version_codename.value();
496 
497     attr = root->FindOrCreateAttribute("", "platformBuildVersionName");
498 
499     // Make sure we un-compile the value if it was set to something else.
500     attr->compiled_value = {};
501     attr->value = options_.compile_sdk_version_codename.value();
502   }
503 
504   xml::XmlActionExecutor executor;
505   if (!BuildRules(&executor, context->GetDiagnostics())) {
506     return false;
507   }
508 
509   xml::XmlActionExecutorPolicy policy = options_.warn_validation
510                                             ? xml::XmlActionExecutorPolicy::kWhitelistWarning
511                                             : xml::XmlActionExecutorPolicy::kWhitelist;
512   if (!executor.Execute(policy, context->GetDiagnostics(), doc)) {
513     return false;
514   }
515 
516   if (options_.rename_manifest_package) {
517     // Rename manifest package outside of the XmlActionExecutor.
518     // We need to extract the old package name and FullyQualify all class
519     // names.
520     if (!RenameManifestPackage(options_.rename_manifest_package.value(), root)) {
521       return false;
522     }
523   }
524   return true;
525 }
526 
527 }  // namespace aapt
528