blob: 1203db7734eadca731deb5ae05d44f8de2e3ee95 [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 Lesinskicc5609d2016-04-05 12:41:07 -070084bool ManifestFixer::buildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag) {
85 // First verify some options.
86 if (mOptions.renameManifestPackage) {
87 if (!util::isJavaPackageName(mOptions.renameManifestPackage.value())) {
88 diag->error(DiagMessage() << "invalid manifest package override '"
89 << mOptions.renameManifestPackage.value() << "'");
90 return false;
91 }
92 }
93
94 if (mOptions.renameInstrumentationTargetPackage) {
95 if (!util::isJavaPackageName(mOptions.renameInstrumentationTargetPackage.value())) {
96 diag->error(DiagMessage() << "invalid instrumentation target package override '"
97 << mOptions.renameInstrumentationTargetPackage.value() << "'");
98 return false;
99 }
100 }
101
102 // Common intent-filter actions.
103 xml::XmlNodeAction intentFilterAction;
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700104 intentFilterAction["action"];
105 intentFilterAction["category"];
106 intentFilterAction["data"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700107
108 // Common meta-data actions.
109 xml::XmlNodeAction metaDataAction;
110
111 // Manifest actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700112 xml::XmlNodeAction& manifestAction = (*executor)["manifest"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700113 manifestAction.action(verifyManifest);
114 manifestAction.action([&](xml::Element* el) -> bool {
115 if (mOptions.versionNameDefault) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700116 if (el->findAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700117 el->attributes.push_back(xml::Attribute{
118 xml::kSchemaAndroid,
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700119 "versionName",
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700120 mOptions.versionNameDefault.value() });
121 }
122 }
123
124 if (mOptions.versionCodeDefault) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700125 if (el->findAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700126 el->attributes.push_back(xml::Attribute{
127 xml::kSchemaAndroid,
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700128 "versionCode",
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700129 mOptions.versionCodeDefault.value() });
130 }
131 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800132 return true;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700133 });
Adam Lesinski52364f72016-01-11 13:10:24 -0800134
Adam Lesinski5ff3ad62016-04-13 20:30:45 -0700135 // Meta tags.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700136 manifestAction["eat-comment"];
Adam Lesinski5ff3ad62016-04-13 20:30:45 -0700137
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700138 // Uses-sdk actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700139 manifestAction["uses-sdk"].action([&](xml::Element* el) -> bool {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700140 if (mOptions.minSdkVersionDefault &&
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700141 el->findAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700142 // There was no minSdkVersion defined and we have a default to assign.
143 el->attributes.push_back(xml::Attribute{
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700144 xml::kSchemaAndroid, "minSdkVersion",
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700145 mOptions.minSdkVersionDefault.value() });
146 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800147
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700148 if (mOptions.targetSdkVersionDefault &&
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700149 el->findAttribute(xml::kSchemaAndroid, "targetSdkVersion") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700150 // There was no targetSdkVersion defined and we have a default to assign.
151 el->attributes.push_back(xml::Attribute{
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700152 xml::kSchemaAndroid, "targetSdkVersion",
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700153 mOptions.targetSdkVersionDefault.value() });
154 }
155 return true;
156 });
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800157
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700158 // Instrumentation actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700159 manifestAction["instrumentation"].action([&](xml::Element* el) -> bool {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700160 if (!mOptions.renameInstrumentationTargetPackage) {
161 return true;
162 }
163
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700164 if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, "targetPackage")) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700165 attr->value = mOptions.renameInstrumentationTargetPackage.value();
166 }
167 return true;
168 });
169
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700170 manifestAction["original-package"];
171 manifestAction["protected-broadcast"];
172 manifestAction["uses-permission"];
173 manifestAction["permission"];
174 manifestAction["permission-tree"];
175 manifestAction["permission-group"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700176
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700177 manifestAction["uses-configuration"];
178 manifestAction["uses-feature"];
179 manifestAction["supports-screens"];
180 manifestAction["compatible-screens"];
181 manifestAction["supports-gl-texture"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700182
183 // Application actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700184 xml::XmlNodeAction& applicationAction = manifestAction["application"];
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700185 applicationAction.action(optionalNameIsJavaClassName);
186
Adam Lesinskifee32d42016-05-31 15:07:20 -0700187 // Uses library actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700188 applicationAction["uses-library"];
Adam Lesinskifee32d42016-05-31 15:07:20 -0700189
Adam Lesinski5d84ad52016-06-23 13:18:16 -0700190 // Meta-data.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700191 applicationAction["meta-data"] = metaDataAction;
Adam Lesinski5d84ad52016-06-23 13:18:16 -0700192
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700193 // Activity actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700194 applicationAction["activity"].action(requiredNameIsJavaClassName);
195 applicationAction["activity"]["intent-filter"] = intentFilterAction;
196 applicationAction["activity"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700197
198 // Activity alias actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700199 applicationAction["activity-alias"]["intent-filter"] = intentFilterAction;
200 applicationAction["activity-alias"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700201
202 // Service actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700203 applicationAction["service"].action(requiredNameIsJavaClassName);
204 applicationAction["service"]["intent-filter"] = intentFilterAction;
205 applicationAction["service"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700206
207 // Receiver actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700208 applicationAction["receiver"].action(requiredNameIsJavaClassName);
209 applicationAction["receiver"]["intent-filter"] = intentFilterAction;
210 applicationAction["receiver"]["meta-data"] = metaDataAction;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700211
212 // Provider actions.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700213 applicationAction["provider"].action(requiredNameIsJavaClassName);
Adam Lesinskibb5a3902016-08-01 15:01:08 -0700214 applicationAction["provider"]["intent-filter"] = intentFilterAction;
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700215 applicationAction["provider"]["meta-data"] = metaDataAction;
Adam Lesinskibb5a3902016-08-01 15:01:08 -0700216 applicationAction["provider"]["grant-uri-permissions"];
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700217 applicationAction["provider"]["path-permissions"];
Adam Lesinskibb5a3902016-08-01 15:01:08 -0700218
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800219 return true;
220}
221
Adam Lesinski52364f72016-01-11 13:10:24 -0800222class FullyQualifiedClassNameVisitor : public xml::Visitor {
223public:
224 using xml::Visitor::visit;
225
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700226 explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : mPackage(package) {
Adam Lesinski52364f72016-01-11 13:10:24 -0800227 }
228
229 void visit(xml::Element* el) override {
230 for (xml::Attribute& attr : el->attributes) {
Adam Lesinski71965e82016-07-07 17:12:12 -0700231 if (attr.namespaceUri == xml::kSchemaAndroid
232 && mClassAttributes.find(attr.name) != mClassAttributes.end()) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700233 if (Maybe<std::string> newValue =
Adam Lesinski71965e82016-07-07 17:12:12 -0700234 util::getFullyQualifiedClassName(mPackage, attr.value)) {
235 attr.value = std::move(newValue.value());
236 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800237 }
238 }
239
240 // Super implementation to iterate over the children.
241 xml::Visitor::visit(el);
242 }
243
244private:
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700245 StringPiece mPackage;
246 std::unordered_set<StringPiece> mClassAttributes = { "name" };
Adam Lesinski52364f72016-01-11 13:10:24 -0800247};
248
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700249static bool renameManifestPackage(const StringPiece& packageOverride, xml::Element* manifestEl) {
250 xml::Attribute* attr = manifestEl->findAttribute({}, "package");
Adam Lesinski52364f72016-01-11 13:10:24 -0800251
252 // We've already verified that the manifest element is present, with a package name specified.
253 assert(attr);
254
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700255 std::string originalPackage = std::move(attr->value);
Adam Lesinski52364f72016-01-11 13:10:24 -0800256 attr->value = packageOverride.toString();
257
258 FullyQualifiedClassNameVisitor visitor(originalPackage);
259 manifestEl->accept(&visitor);
260 return true;
261}
262
Adam Lesinski467f1712015-11-16 17:35:44 -0800263bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) {
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800264 xml::Element* root = xml::findRootElement(doc->root.get());
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700265 if (!root || !root->namespaceUri.empty() || root->name != "manifest") {
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800266 context->getDiagnostics()->error(DiagMessage(doc->file.source)
267 << "root tag must be <manifest>");
268 return false;
269 }
270
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700271 if ((mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault)
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700272 && root->findChild({}, "uses-sdk") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700273 // Auto insert a <uses-sdk> element.
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800274 std::unique_ptr<xml::Element> usesSdk = util::make_unique<xml::Element>();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700275 usesSdk->name = "uses-sdk";
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800276 root->addChild(std::move(usesSdk));
277 }
278
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700279 xml::XmlActionExecutor executor;
280 if (!buildRules(&executor, context->getDiagnostics())) {
281 return false;
282 }
283
284 if (!executor.execute(xml::XmlActionExecutorPolicy::Whitelist, context->getDiagnostics(),
285 doc)) {
286 return false;
287 }
288
289 if (mOptions.renameManifestPackage) {
290 // Rename manifest package outside of the XmlActionExecutor.
291 // We need to extract the old package name and FullyQualify all class names.
292 if (!renameManifestPackage(mOptions.renameManifestPackage.value(), root)) {
293 return false;
294 }
295 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800296 return true;
297}
298
299} // namespace aapt