blob: e7edcc5d549891cb3b313d7005af21cb0810051b [file] [log] [blame]
Adam Lesinski2ae4a872015-11-02 16:10:55 -08001/*
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"
Adam Lesinski2ae4a872015-11-02 16:10:55 -080018#include "link/ManifestFixer.h"
19#include "util/Util.h"
Adam Lesinskicc5609d2016-04-05 12:41:07 -070020#include "xml/XmlActionExecutor.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080021#include "xml/XmlDom.h"
Adam Lesinski2ae4a872015-11-02 16:10:55 -080022
Adam Lesinski71965e82016-07-07 17:12:12 -070023#include <unordered_set>
24
Adam Lesinski2ae4a872015-11-02 16:10:55 -080025namespace aapt {
26
Adam Lesinskicc5609d2016-04-05 12:41:07 -070027/**
28 * This is how PackageManager builds class names from AndroidManifest.xml entries.
29 */
30static bool nameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
31 SourcePathDiagnostics* diag) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -070032 // We allow unqualified class names (ie: .HelloActivity)
33 // Since we don't know the package name, we can just make a fake one here and
34 // the test will be identical as long as the real package name is valid too.
Adam Lesinskid0f116b2016-07-08 15:00:32 -070035 Maybe<std::string> fullyQualifiedClassName =
36 util::getFullyQualifiedClassName("a", attr->value);
Adam Lesinskicc5609d2016-04-05 12:41:07 -070037
Adam Lesinskid0f116b2016-07-08 15:00:32 -070038 StringPiece qualifiedClassName = fullyQualifiedClassName
Adam Lesinski71965e82016-07-07 17:12:12 -070039 ? fullyQualifiedClassName.value() : attr->value;
Adam Lesinskid0f116b2016-07-08 15:00:32 -070040
Adam Lesinskicc5609d2016-04-05 12:41:07 -070041 if (!util::isJavaClassName(qualifiedClassName)) {
42 diag->error(DiagMessage(el->lineNumber)
43 << "attribute 'android:name' in <"
44 << el->name << "> tag must be a valid Java class name");
45 return false;
46 }
47 return true;
48}
49
50static bool optionalNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -070051 if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, "name")) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -070052 return nameIsJavaClassName(el, attr, diag);
53 }
54 return true;
55}
56
57static bool requiredNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -070058 if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, "name")) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -070059 return nameIsJavaClassName(el, attr, diag);
60 }
61 diag->error(DiagMessage(el->lineNumber)
62 << "<" << el->name << "> is missing attribute 'android:name'");
Adam Lesinski52364f72016-01-11 13:10:24 -080063 return false;
64}
65
Adam Lesinskicc5609d2016-04-05 12:41:07 -070066static bool verifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -070067 xml::Attribute* attr = el->findAttribute({}, "package");
Adam Lesinskicc5609d2016-04-05 12:41:07 -070068 if (!attr) {
69 diag->error(DiagMessage(el->lineNumber) << "<manifest> tag is missing 'package' attribute");
70 return false;
71 } else if (ResourceUtils::isReference(attr->value)) {
72 diag->error(DiagMessage(el->lineNumber)
73 << "attribute 'package' in <manifest> tag must not be a reference");
74 return false;
75 } else if (!util::isJavaPackageName(attr->value)) {
76 diag->error(DiagMessage(el->lineNumber)
77 << "attribute 'package' in <manifest> tag is not a valid Java package name: '"
78 << attr->value << "'");
79 return false;
Adam Lesinski2ae4a872015-11-02 16:10:55 -080080 }
Adam Lesinski52364f72016-01-11 13:10:24 -080081 return true;
82}
83
Adam Lesinski6b17d2c2016-08-10 11:37:06 -070084/**
85 * The coreApp attribute in <manifest> is not a regular AAPT attribute, so type checking on it
86 * is manual.
87 */
88static bool fixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
89 if (xml::Attribute* attr = el->findAttribute("", "coreApp")) {
90 std::unique_ptr<BinaryPrimitive> result = ResourceUtils::tryParseBool(attr->value);
91 if (!result) {
92 diag->error(DiagMessage(el->lineNumber) << "attribute coreApp must be a boolean");
93 return false;
94 }
95 attr->compiledValue = std::move(result);
96 }
97 return true;
98}
99
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700100bool ManifestFixer::buildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag) {
101 // First verify some options.
102 if (mOptions.renameManifestPackage) {
103 if (!util::isJavaPackageName(mOptions.renameManifestPackage.value())) {
104 diag->error(DiagMessage() << "invalid manifest package override '"
105 << mOptions.renameManifestPackage.value() << "'");
106 return false;
107 }
108 }
109
110 if (mOptions.renameInstrumentationTargetPackage) {
111 if (!util::isJavaPackageName(mOptions.renameInstrumentationTargetPackage.value())) {
112 diag->error(DiagMessage() << "invalid instrumentation target package override '"
113 << mOptions.renameInstrumentationTargetPackage.value() << "'");
114 return false;
115 }
116 }
117
118 // Common intent-filter actions.
119 xml::XmlNodeAction intentFilterAction;
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700120 intentFilterAction["action"];
121 intentFilterAction["category"];
122 intentFilterAction["data"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700123
124 // Common meta-data actions.
125 xml::XmlNodeAction metaDataAction;
126
127 // Manifest actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700128 xml::XmlNodeAction& manifestAction = (*executor)["manifest"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700129 manifestAction.action(verifyManifest);
Adam Lesinski6b17d2c2016-08-10 11:37:06 -0700130 manifestAction.action(fixCoreAppAttribute);
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700131 manifestAction.action([&](xml::Element* el) -> bool {
132 if (mOptions.versionNameDefault) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700133 if (el->findAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700134 el->attributes.push_back(xml::Attribute{
135 xml::kSchemaAndroid,
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700136 "versionName",
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700137 mOptions.versionNameDefault.value() });
138 }
139 }
140
141 if (mOptions.versionCodeDefault) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700142 if (el->findAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700143 el->attributes.push_back(xml::Attribute{
144 xml::kSchemaAndroid,
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700145 "versionCode",
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700146 mOptions.versionCodeDefault.value() });
147 }
148 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800149 return true;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700150 });
Adam Lesinski52364f72016-01-11 13:10:24 -0800151
Adam Lesinski5ff3ad62016-04-13 20:30:45 -0700152 // Meta tags.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700153 manifestAction["eat-comment"];
Adam Lesinski5ff3ad62016-04-13 20:30:45 -0700154
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700155 // Uses-sdk actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700156 manifestAction["uses-sdk"].action([&](xml::Element* el) -> bool {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700157 if (mOptions.minSdkVersionDefault &&
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700158 el->findAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700159 // There was no minSdkVersion defined and we have a default to assign.
160 el->attributes.push_back(xml::Attribute{
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700161 xml::kSchemaAndroid, "minSdkVersion",
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700162 mOptions.minSdkVersionDefault.value() });
163 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800164
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700165 if (mOptions.targetSdkVersionDefault &&
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700166 el->findAttribute(xml::kSchemaAndroid, "targetSdkVersion") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700167 // There was no targetSdkVersion defined and we have a default to assign.
168 el->attributes.push_back(xml::Attribute{
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700169 xml::kSchemaAndroid, "targetSdkVersion",
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700170 mOptions.targetSdkVersionDefault.value() });
171 }
172 return true;
173 });
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800174
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700175 // Instrumentation actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700176 manifestAction["instrumentation"].action([&](xml::Element* el) -> bool {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700177 if (!mOptions.renameInstrumentationTargetPackage) {
178 return true;
179 }
180
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700181 if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, "targetPackage")) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700182 attr->value = mOptions.renameInstrumentationTargetPackage.value();
183 }
184 return true;
185 });
186
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700187 manifestAction["original-package"];
188 manifestAction["protected-broadcast"];
189 manifestAction["uses-permission"];
190 manifestAction["permission"];
191 manifestAction["permission-tree"];
192 manifestAction["permission-group"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700193
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700194 manifestAction["uses-configuration"];
195 manifestAction["uses-feature"];
196 manifestAction["supports-screens"];
197 manifestAction["compatible-screens"];
198 manifestAction["supports-gl-texture"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700199
200 // Application actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700201 xml::XmlNodeAction& applicationAction = manifestAction["application"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700202 applicationAction.action(optionalNameIsJavaClassName);
203
Adam Lesinskifee32d42016-05-31 15:07:20 -0700204 // Uses library actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700205 applicationAction["uses-library"];
Adam Lesinskifee32d42016-05-31 15:07:20 -0700206
Adam Lesinski5d84ad52016-06-23 13:18:16 -0700207 // Meta-data.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700208 applicationAction["meta-data"] = metaDataAction;
Adam Lesinski5d84ad52016-06-23 13:18:16 -0700209
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700210 // Activity actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700211 applicationAction["activity"].action(requiredNameIsJavaClassName);
212 applicationAction["activity"]["intent-filter"] = intentFilterAction;
213 applicationAction["activity"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700214
215 // Activity alias actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700216 applicationAction["activity-alias"]["intent-filter"] = intentFilterAction;
217 applicationAction["activity-alias"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700218
219 // Service actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700220 applicationAction["service"].action(requiredNameIsJavaClassName);
221 applicationAction["service"]["intent-filter"] = intentFilterAction;
222 applicationAction["service"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700223
224 // Receiver actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700225 applicationAction["receiver"].action(requiredNameIsJavaClassName);
226 applicationAction["receiver"]["intent-filter"] = intentFilterAction;
227 applicationAction["receiver"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700228
229 // Provider actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700230 applicationAction["provider"].action(requiredNameIsJavaClassName);
Adam Lesinskibb5a3902016-08-01 15:01:08 -0700231 applicationAction["provider"]["intent-filter"] = intentFilterAction;
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700232 applicationAction["provider"]["meta-data"] = metaDataAction;
Adam Lesinskibb5a3902016-08-01 15:01:08 -0700233 applicationAction["provider"]["grant-uri-permissions"];
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700234 applicationAction["provider"]["path-permissions"];
Adam Lesinskibb5a3902016-08-01 15:01:08 -0700235
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800236 return true;
237}
238
Adam Lesinski52364f72016-01-11 13:10:24 -0800239class FullyQualifiedClassNameVisitor : public xml::Visitor {
240public:
241 using xml::Visitor::visit;
242
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700243 explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : mPackage(package) {
Adam Lesinski52364f72016-01-11 13:10:24 -0800244 }
245
246 void visit(xml::Element* el) override {
247 for (xml::Attribute& attr : el->attributes) {
Adam Lesinski71965e82016-07-07 17:12:12 -0700248 if (attr.namespaceUri == xml::kSchemaAndroid
249 && mClassAttributes.find(attr.name) != mClassAttributes.end()) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700250 if (Maybe<std::string> newValue =
Adam Lesinski71965e82016-07-07 17:12:12 -0700251 util::getFullyQualifiedClassName(mPackage, attr.value)) {
252 attr.value = std::move(newValue.value());
253 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800254 }
255 }
256
257 // Super implementation to iterate over the children.
258 xml::Visitor::visit(el);
259 }
260
261private:
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700262 StringPiece mPackage;
263 std::unordered_set<StringPiece> mClassAttributes = { "name" };
Adam Lesinski52364f72016-01-11 13:10:24 -0800264};
265
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700266static bool renameManifestPackage(const StringPiece& packageOverride, xml::Element* manifestEl) {
267 xml::Attribute* attr = manifestEl->findAttribute({}, "package");
Adam Lesinski52364f72016-01-11 13:10:24 -0800268
269 // We've already verified that the manifest element is present, with a package name specified.
270 assert(attr);
271
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700272 std::string originalPackage = std::move(attr->value);
Adam Lesinski52364f72016-01-11 13:10:24 -0800273 attr->value = packageOverride.toString();
274
275 FullyQualifiedClassNameVisitor visitor(originalPackage);
276 manifestEl->accept(&visitor);
277 return true;
278}
279
Adam Lesinski467f1712015-11-16 17:35:44 -0800280bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) {
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800281 xml::Element* root = xml::findRootElement(doc->root.get());
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700282 if (!root || !root->namespaceUri.empty() || root->name != "manifest") {
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800283 context->getDiagnostics()->error(DiagMessage(doc->file.source)
284 << "root tag must be <manifest>");
285 return false;
286 }
287
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700288 if ((mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault)
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700289 && root->findChild({}, "uses-sdk") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700290 // Auto insert a <uses-sdk> element.
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800291 std::unique_ptr<xml::Element> usesSdk = util::make_unique<xml::Element>();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700292 usesSdk->name = "uses-sdk";
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800293 root->addChild(std::move(usesSdk));
294 }
295
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700296 xml::XmlActionExecutor executor;
297 if (!buildRules(&executor, context->getDiagnostics())) {
298 return false;
299 }
300
301 if (!executor.execute(xml::XmlActionExecutorPolicy::Whitelist, context->getDiagnostics(),
302 doc)) {
303 return false;
304 }
305
306 if (mOptions.renameManifestPackage) {
307 // Rename manifest package outside of the XmlActionExecutor.
308 // We need to extract the old package name and FullyQualify all class names.
309 if (!renameManifestPackage(mOptions.renameManifestPackage.value(), root)) {
310 return false;
311 }
312 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800313 return true;
314}
315
316} // namespace aapt