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 "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 
     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.
     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 
     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 
     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 
     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 
    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 
    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 
    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.
    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).
    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 
    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 
    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 
    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 
    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