ManifestFixer.cpp revision c728c3daba5754467ef0c42a83247fdb4be1a4db
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 "ResourceUtils.h" 18#include "link/ManifestFixer.h" 19#include "util/Util.h" 20#include "xml/XmlActionExecutor.h" 21#include "xml/XmlDom.h" 22 23namespace aapt { 24 25/** 26 * This is how PackageManager builds class names from AndroidManifest.xml entries. 27 */ 28static bool nameIsJavaClassName(xml::Element* el, xml::Attribute* attr, 29 SourcePathDiagnostics* diag) { 30 std::u16string className = attr->value; 31 if (className.find(u'.') == std::u16string::npos) { 32 // There is no '.', so add one to the beginning. 33 className = u"."; 34 className += attr->value; 35 } 36 37 // We allow unqualified class names (ie: .HelloActivity) 38 // Since we don't know the package name, we can just make a fake one here and 39 // the test will be identical as long as the real package name is valid too. 40 Maybe<std::u16string> fullyQualifiedClassName = 41 util::getFullyQualifiedClassName(u"a", className); 42 43 StringPiece16 qualifiedClassName = fullyQualifiedClassName 44 ? fullyQualifiedClassName.value() : className; 45 if (!util::isJavaClassName(qualifiedClassName)) { 46 diag->error(DiagMessage(el->lineNumber) 47 << "attribute 'android:name' in <" 48 << el->name << "> tag must be a valid Java class name"); 49 return false; 50 } 51 return true; 52} 53 54static bool optionalNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) { 55 if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name")) { 56 return nameIsJavaClassName(el, attr, diag); 57 } 58 return true; 59} 60 61static bool requiredNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) { 62 if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name")) { 63 return nameIsJavaClassName(el, attr, diag); 64 } 65 diag->error(DiagMessage(el->lineNumber) 66 << "<" << el->name << "> is missing attribute 'android:name'"); 67 return false; 68} 69 70static bool verifyManifest(xml::Element* el, SourcePathDiagnostics* diag) { 71 xml::Attribute* attr = el->findAttribute({}, u"package"); 72 if (!attr) { 73 diag->error(DiagMessage(el->lineNumber) << "<manifest> tag is missing 'package' attribute"); 74 return false; 75 } else if (ResourceUtils::isReference(attr->value)) { 76 diag->error(DiagMessage(el->lineNumber) 77 << "attribute 'package' in <manifest> tag must not be a reference"); 78 return false; 79 } else if (!util::isJavaPackageName(attr->value)) { 80 diag->error(DiagMessage(el->lineNumber) 81 << "attribute 'package' in <manifest> tag is not a valid Java package name: '" 82 << attr->value << "'"); 83 return false; 84 } 85 return true; 86} 87 88bool ManifestFixer::buildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag) { 89 // First verify some options. 90 if (mOptions.renameManifestPackage) { 91 if (!util::isJavaPackageName(mOptions.renameManifestPackage.value())) { 92 diag->error(DiagMessage() << "invalid manifest package override '" 93 << mOptions.renameManifestPackage.value() << "'"); 94 return false; 95 } 96 } 97 98 if (mOptions.renameInstrumentationTargetPackage) { 99 if (!util::isJavaPackageName(mOptions.renameInstrumentationTargetPackage.value())) { 100 diag->error(DiagMessage() << "invalid instrumentation target package override '" 101 << mOptions.renameInstrumentationTargetPackage.value() << "'"); 102 return false; 103 } 104 } 105 106 // Common intent-filter actions. 107 xml::XmlNodeAction intentFilterAction; 108 intentFilterAction[u"action"]; 109 intentFilterAction[u"category"]; 110 intentFilterAction[u"data"]; 111 112 // Common meta-data actions. 113 xml::XmlNodeAction metaDataAction; 114 115 // Manifest actions. 116 xml::XmlNodeAction& manifestAction = (*executor)[u"manifest"]; 117 manifestAction.action(verifyManifest); 118 manifestAction.action([&](xml::Element* el) -> bool { 119 if (mOptions.versionNameDefault) { 120 if (el->findAttribute(xml::kSchemaAndroid, u"versionName") == nullptr) { 121 el->attributes.push_back(xml::Attribute{ 122 xml::kSchemaAndroid, 123 u"versionName", 124 mOptions.versionNameDefault.value() }); 125 } 126 } 127 128 if (mOptions.versionCodeDefault) { 129 if (el->findAttribute(xml::kSchemaAndroid, u"versionCode") == nullptr) { 130 el->attributes.push_back(xml::Attribute{ 131 xml::kSchemaAndroid, 132 u"versionCode", 133 mOptions.versionCodeDefault.value() }); 134 } 135 } 136 return true; 137 }); 138 139 // Uses-sdk actions. 140 manifestAction[u"uses-sdk"].action([&](xml::Element* el) -> bool { 141 if (mOptions.minSdkVersionDefault && 142 el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion") == nullptr) { 143 // There was no minSdkVersion defined and we have a default to assign. 144 el->attributes.push_back(xml::Attribute{ 145 xml::kSchemaAndroid, u"minSdkVersion", 146 mOptions.minSdkVersionDefault.value() }); 147 } 148 149 if (mOptions.targetSdkVersionDefault && 150 el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion") == nullptr) { 151 // There was no targetSdkVersion defined and we have a default to assign. 152 el->attributes.push_back(xml::Attribute{ 153 xml::kSchemaAndroid, u"targetSdkVersion", 154 mOptions.targetSdkVersionDefault.value() }); 155 } 156 return true; 157 }); 158 159 // Instrumentation actions. 160 manifestAction[u"instrumentation"].action([&](xml::Element* el) -> bool { 161 if (!mOptions.renameInstrumentationTargetPackage) { 162 return true; 163 } 164 165 if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"targetPackage")) { 166 attr->value = mOptions.renameInstrumentationTargetPackage.value(); 167 } 168 return true; 169 }); 170 171 manifestAction[u"eat-comment"]; 172 manifestAction[u"protected-broadcast"]; 173 manifestAction[u"uses-permission"]; 174 manifestAction[u"permission"]; 175 manifestAction[u"permission-tree"]; 176 manifestAction[u"permission-group"]; 177 178 manifestAction[u"uses-configuration"]; 179 manifestAction[u"uses-feature"]; 180 manifestAction[u"uses-library"]; 181 manifestAction[u"supports-screens"]; 182 manifestAction[u"compatible-screens"]; 183 manifestAction[u"supports-gl-texture"]; 184 185 // Application actions. 186 xml::XmlNodeAction& applicationAction = (*executor)[u"manifest"][u"application"]; 187 applicationAction.action(optionalNameIsJavaClassName); 188 189 // Activity actions. 190 applicationAction[u"activity"].action(requiredNameIsJavaClassName); 191 applicationAction[u"activity"][u"intent-filter"] = intentFilterAction; 192 applicationAction[u"activity"][u"meta-data"] = metaDataAction; 193 194 // Activity alias actions. 195 applicationAction[u"activity-alias"][u"intent-filter"] = intentFilterAction; 196 applicationAction[u"activity-alias"][u"meta-data"] = metaDataAction; 197 198 // Service actions. 199 applicationAction[u"service"].action(requiredNameIsJavaClassName); 200 applicationAction[u"service"][u"intent-filter"] = intentFilterAction; 201 applicationAction[u"service"][u"meta-data"] = metaDataAction; 202 203 // Receiver actions. 204 applicationAction[u"receiver"].action(requiredNameIsJavaClassName); 205 applicationAction[u"receiver"][u"intent-filter"] = intentFilterAction; 206 applicationAction[u"receiver"][u"meta-data"] = metaDataAction; 207 208 // Provider actions. 209 applicationAction[u"provider"].action(requiredNameIsJavaClassName); 210 applicationAction[u"provider"][u"grant-uri-permissions"]; 211 applicationAction[u"provider"][u"meta-data"] = metaDataAction; 212 applicationAction[u"provider"][u"path-permissions"]; 213 return true; 214} 215 216class FullyQualifiedClassNameVisitor : public xml::Visitor { 217public: 218 using xml::Visitor::visit; 219 220 FullyQualifiedClassNameVisitor(const StringPiece16& package) : mPackage(package) { 221 } 222 223 void visit(xml::Element* el) override { 224 for (xml::Attribute& attr : el->attributes) { 225 if (Maybe<std::u16string> newValue = 226 util::getFullyQualifiedClassName(mPackage, attr.value)) { 227 attr.value = std::move(newValue.value()); 228 } 229 } 230 231 // Super implementation to iterate over the children. 232 xml::Visitor::visit(el); 233 } 234 235private: 236 StringPiece16 mPackage; 237}; 238 239static bool renameManifestPackage(const StringPiece16& packageOverride, xml::Element* manifestEl) { 240 xml::Attribute* attr = manifestEl->findAttribute({}, u"package"); 241 242 // We've already verified that the manifest element is present, with a package name specified. 243 assert(attr); 244 245 std::u16string originalPackage = std::move(attr->value); 246 attr->value = packageOverride.toString(); 247 248 FullyQualifiedClassNameVisitor visitor(originalPackage); 249 manifestEl->accept(&visitor); 250 return true; 251} 252 253bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) { 254 xml::Element* root = xml::findRootElement(doc->root.get()); 255 if (!root || !root->namespaceUri.empty() || root->name != u"manifest") { 256 context->getDiagnostics()->error(DiagMessage(doc->file.source) 257 << "root tag must be <manifest>"); 258 return false; 259 } 260 261 if ((mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault) 262 && root->findChild({}, u"uses-sdk") == nullptr) { 263 // Auto insert a <uses-sdk> element. 264 std::unique_ptr<xml::Element> usesSdk = util::make_unique<xml::Element>(); 265 usesSdk->name = u"uses-sdk"; 266 root->addChild(std::move(usesSdk)); 267 } 268 269 xml::XmlActionExecutor executor; 270 if (!buildRules(&executor, context->getDiagnostics())) { 271 return false; 272 } 273 274 if (!executor.execute(xml::XmlActionExecutorPolicy::Whitelist, context->getDiagnostics(), 275 doc)) { 276 return false; 277 } 278 279 if (mOptions.renameManifestPackage) { 280 // Rename manifest package outside of the XmlActionExecutor. 281 // We need to extract the old package name and FullyQualify all class names. 282 if (!renameManifestPackage(mOptions.renameManifestPackage.value(), root)) { 283 return false; 284 } 285 } 286 return true; 287} 288 289} // namespace aapt 290