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 // Meta tags. 140 manifestAction[u"eat-comment"]; 141 142 // Uses-sdk actions. 143 manifestAction[u"uses-sdk"].action([&](xml::Element* el) -> bool { 144 if (mOptions.minSdkVersionDefault && 145 el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion") == nullptr) { 146 // There was no minSdkVersion defined and we have a default to assign. 147 el->attributes.push_back(xml::Attribute{ 148 xml::kSchemaAndroid, u"minSdkVersion", 149 mOptions.minSdkVersionDefault.value() }); 150 } 151 152 if (mOptions.targetSdkVersionDefault && 153 el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion") == nullptr) { 154 // There was no targetSdkVersion defined and we have a default to assign. 155 el->attributes.push_back(xml::Attribute{ 156 xml::kSchemaAndroid, u"targetSdkVersion", 157 mOptions.targetSdkVersionDefault.value() }); 158 } 159 return true; 160 }); 161 162 // Instrumentation actions. 163 manifestAction[u"instrumentation"].action([&](xml::Element* el) -> bool { 164 if (!mOptions.renameInstrumentationTargetPackage) { 165 return true; 166 } 167 168 if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"targetPackage")) { 169 attr->value = mOptions.renameInstrumentationTargetPackage.value(); 170 } 171 return true; 172 }); 173 174 manifestAction[u"original-package"]; 175 manifestAction[u"protected-broadcast"]; 176 manifestAction[u"uses-permission"]; 177 manifestAction[u"permission"]; 178 manifestAction[u"permission-tree"]; 179 manifestAction[u"permission-group"]; 180 181 manifestAction[u"uses-configuration"]; 182 manifestAction[u"uses-feature"]; 183 manifestAction[u"uses-library"]; 184 manifestAction[u"supports-screens"]; 185 manifestAction[u"compatible-screens"]; 186 manifestAction[u"supports-gl-texture"]; 187 188 // Application actions. 189 xml::XmlNodeAction& applicationAction = (*executor)[u"manifest"][u"application"]; 190 applicationAction.action(optionalNameIsJavaClassName); 191 192 // Activity actions. 193 applicationAction[u"activity"].action(requiredNameIsJavaClassName); 194 applicationAction[u"activity"][u"intent-filter"] = intentFilterAction; 195 applicationAction[u"activity"][u"meta-data"] = metaDataAction; 196 197 // Activity alias actions. 198 applicationAction[u"activity-alias"][u"intent-filter"] = intentFilterAction; 199 applicationAction[u"activity-alias"][u"meta-data"] = metaDataAction; 200 201 // Service actions. 202 applicationAction[u"service"].action(requiredNameIsJavaClassName); 203 applicationAction[u"service"][u"intent-filter"] = intentFilterAction; 204 applicationAction[u"service"][u"meta-data"] = metaDataAction; 205 206 // Receiver actions. 207 applicationAction[u"receiver"].action(requiredNameIsJavaClassName); 208 applicationAction[u"receiver"][u"intent-filter"] = intentFilterAction; 209 applicationAction[u"receiver"][u"meta-data"] = metaDataAction; 210 211 // Provider actions. 212 applicationAction[u"provider"].action(requiredNameIsJavaClassName); 213 applicationAction[u"provider"][u"grant-uri-permissions"]; 214 applicationAction[u"provider"][u"meta-data"] = metaDataAction; 215 applicationAction[u"provider"][u"path-permissions"]; 216 return true; 217} 218 219class FullyQualifiedClassNameVisitor : public xml::Visitor { 220public: 221 using xml::Visitor::visit; 222 223 FullyQualifiedClassNameVisitor(const StringPiece16& package) : mPackage(package) { 224 } 225 226 void visit(xml::Element* el) override { 227 for (xml::Attribute& attr : el->attributes) { 228 if (Maybe<std::u16string> newValue = 229 util::getFullyQualifiedClassName(mPackage, attr.value)) { 230 attr.value = std::move(newValue.value()); 231 } 232 } 233 234 // Super implementation to iterate over the children. 235 xml::Visitor::visit(el); 236 } 237 238private: 239 StringPiece16 mPackage; 240}; 241 242static bool renameManifestPackage(const StringPiece16& packageOverride, xml::Element* manifestEl) { 243 xml::Attribute* attr = manifestEl->findAttribute({}, u"package"); 244 245 // We've already verified that the manifest element is present, with a package name specified. 246 assert(attr); 247 248 std::u16string originalPackage = std::move(attr->value); 249 attr->value = packageOverride.toString(); 250 251 FullyQualifiedClassNameVisitor visitor(originalPackage); 252 manifestEl->accept(&visitor); 253 return true; 254} 255 256bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) { 257 xml::Element* root = xml::findRootElement(doc->root.get()); 258 if (!root || !root->namespaceUri.empty() || root->name != u"manifest") { 259 context->getDiagnostics()->error(DiagMessage(doc->file.source) 260 << "root tag must be <manifest>"); 261 return false; 262 } 263 264 if ((mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault) 265 && root->findChild({}, u"uses-sdk") == nullptr) { 266 // Auto insert a <uses-sdk> element. 267 std::unique_ptr<xml::Element> usesSdk = util::make_unique<xml::Element>(); 268 usesSdk->name = u"uses-sdk"; 269 root->addChild(std::move(usesSdk)); 270 } 271 272 xml::XmlActionExecutor executor; 273 if (!buildRules(&executor, context->getDiagnostics())) { 274 return false; 275 } 276 277 if (!executor.execute(xml::XmlActionExecutorPolicy::Whitelist, context->getDiagnostics(), 278 doc)) { 279 return false; 280 } 281 282 if (mOptions.renameManifestPackage) { 283 // Rename manifest package outside of the XmlActionExecutor. 284 // We need to extract the old package name and FullyQualify all class names. 285 if (!renameManifestPackage(mOptions.renameManifestPackage.value(), root)) { 286 return false; 287 } 288 } 289 return true; 290} 291 292} // namespace aapt 293