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