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