blob: 45f5acdc54bc292ed73e289a754896bc2c70171d [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"];
Adam Lesinskia0b929d2016-09-19 09:50:45 -0700197
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700198 manifestAction["compatible-screens"];
Adam Lesinskia0b929d2016-09-19 09:50:45 -0700199 manifestAction["compatible-screens"]["screen"];
200
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700201 manifestAction["supports-gl-texture"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700202
203 // Application actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700204 xml::XmlNodeAction& applicationAction = manifestAction["application"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700205 applicationAction.action(optionalNameIsJavaClassName);
206
Adam Lesinskifee32d42016-05-31 15:07:20 -0700207 // Uses library actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700208 applicationAction["uses-library"];
Adam Lesinskifee32d42016-05-31 15:07:20 -0700209
Adam Lesinski5d84ad52016-06-23 13:18:16 -0700210 // Meta-data.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700211 applicationAction["meta-data"] = metaDataAction;
Adam Lesinski5d84ad52016-06-23 13:18:16 -0700212
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700213 // Activity actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700214 applicationAction["activity"].action(requiredNameIsJavaClassName);
215 applicationAction["activity"]["intent-filter"] = intentFilterAction;
216 applicationAction["activity"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700217
218 // Activity alias actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700219 applicationAction["activity-alias"]["intent-filter"] = intentFilterAction;
220 applicationAction["activity-alias"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700221
222 // Service actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700223 applicationAction["service"].action(requiredNameIsJavaClassName);
224 applicationAction["service"]["intent-filter"] = intentFilterAction;
225 applicationAction["service"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700226
227 // Receiver actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700228 applicationAction["receiver"].action(requiredNameIsJavaClassName);
229 applicationAction["receiver"]["intent-filter"] = intentFilterAction;
230 applicationAction["receiver"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700231
232 // Provider actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700233 applicationAction["provider"].action(requiredNameIsJavaClassName);
Adam Lesinskibb5a3902016-08-01 15:01:08 -0700234 applicationAction["provider"]["intent-filter"] = intentFilterAction;
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700235 applicationAction["provider"]["meta-data"] = metaDataAction;
Adam Lesinskibb5a3902016-08-01 15:01:08 -0700236 applicationAction["provider"]["grant-uri-permissions"];
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700237 applicationAction["provider"]["path-permissions"];
Adam Lesinskibb5a3902016-08-01 15:01:08 -0700238
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800239 return true;
240}
241
Adam Lesinski52364f72016-01-11 13:10:24 -0800242class FullyQualifiedClassNameVisitor : public xml::Visitor {
243public:
244 using xml::Visitor::visit;
245
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700246 explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : mPackage(package) {
Adam Lesinski52364f72016-01-11 13:10:24 -0800247 }
248
249 void visit(xml::Element* el) override {
250 for (xml::Attribute& attr : el->attributes) {
Adam Lesinski71965e82016-07-07 17:12:12 -0700251 if (attr.namespaceUri == xml::kSchemaAndroid
252 && mClassAttributes.find(attr.name) != mClassAttributes.end()) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700253 if (Maybe<std::string> newValue =
Adam Lesinski71965e82016-07-07 17:12:12 -0700254 util::getFullyQualifiedClassName(mPackage, attr.value)) {
255 attr.value = std::move(newValue.value());
256 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800257 }
258 }
259
260 // Super implementation to iterate over the children.
261 xml::Visitor::visit(el);
262 }
263
264private:
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700265 StringPiece mPackage;
266 std::unordered_set<StringPiece> mClassAttributes = { "name" };
Adam Lesinski52364f72016-01-11 13:10:24 -0800267};
268
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700269static bool renameManifestPackage(const StringPiece& packageOverride, xml::Element* manifestEl) {
270 xml::Attribute* attr = manifestEl->findAttribute({}, "package");
Adam Lesinski52364f72016-01-11 13:10:24 -0800271
272 // We've already verified that the manifest element is present, with a package name specified.
273 assert(attr);
274
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700275 std::string originalPackage = std::move(attr->value);
Adam Lesinski52364f72016-01-11 13:10:24 -0800276 attr->value = packageOverride.toString();
277
278 FullyQualifiedClassNameVisitor visitor(originalPackage);
279 manifestEl->accept(&visitor);
280 return true;
281}
282
Adam Lesinski467f1712015-11-16 17:35:44 -0800283bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) {
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800284 xml::Element* root = xml::findRootElement(doc->root.get());
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700285 if (!root || !root->namespaceUri.empty() || root->name != "manifest") {
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800286 context->getDiagnostics()->error(DiagMessage(doc->file.source)
287 << "root tag must be <manifest>");
288 return false;
289 }
290
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700291 if ((mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault)
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700292 && root->findChild({}, "uses-sdk") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700293 // Auto insert a <uses-sdk> element.
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800294 std::unique_ptr<xml::Element> usesSdk = util::make_unique<xml::Element>();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700295 usesSdk->name = "uses-sdk";
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800296 root->addChild(std::move(usesSdk));
297 }
298
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700299 xml::XmlActionExecutor executor;
300 if (!buildRules(&executor, context->getDiagnostics())) {
301 return false;
302 }
303
304 if (!executor.execute(xml::XmlActionExecutorPolicy::Whitelist, context->getDiagnostics(),
305 doc)) {
306 return false;
307 }
308
309 if (mOptions.renameManifestPackage) {
310 // Rename manifest package outside of the XmlActionExecutor.
311 // We need to extract the old package name and FullyQualify all class names.
312 if (!renameManifestPackage(mOptions.renameManifestPackage.value(), root)) {
313 return false;
314 }
315 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800316 return true;
317}
318
319} // namespace aapt