blob: ef095357d9e627d56ec2f1d65dd81252d10e9d00 [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);
214 applicationAction["provider"]["grant-uri-permissions"];
215 applicationAction["provider"]["meta-data"] = metaDataAction;
216 applicationAction["provider"]["path-permissions"];
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800217 return true;
218}
219
Adam Lesinski52364f72016-01-11 13:10:24 -0800220class FullyQualifiedClassNameVisitor : public xml::Visitor {
221public:
222 using xml::Visitor::visit;
223
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700224 explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : mPackage(package) {
Adam Lesinski52364f72016-01-11 13:10:24 -0800225 }
226
227 void visit(xml::Element* el) override {
228 for (xml::Attribute& attr : el->attributes) {
Adam Lesinski71965e82016-07-07 17:12:12 -0700229 if (attr.namespaceUri == xml::kSchemaAndroid
230 && mClassAttributes.find(attr.name) != mClassAttributes.end()) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700231 if (Maybe<std::string> newValue =
Adam Lesinski71965e82016-07-07 17:12:12 -0700232 util::getFullyQualifiedClassName(mPackage, attr.value)) {
233 attr.value = std::move(newValue.value());
234 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800235 }
236 }
237
238 // Super implementation to iterate over the children.
239 xml::Visitor::visit(el);
240 }
241
242private:
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700243 StringPiece mPackage;
244 std::unordered_set<StringPiece> mClassAttributes = { "name" };
Adam Lesinski52364f72016-01-11 13:10:24 -0800245};
246
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700247static bool renameManifestPackage(const StringPiece& packageOverride, xml::Element* manifestEl) {
248 xml::Attribute* attr = manifestEl->findAttribute({}, "package");
Adam Lesinski52364f72016-01-11 13:10:24 -0800249
250 // We've already verified that the manifest element is present, with a package name specified.
251 assert(attr);
252
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700253 std::string originalPackage = std::move(attr->value);
Adam Lesinski52364f72016-01-11 13:10:24 -0800254 attr->value = packageOverride.toString();
255
256 FullyQualifiedClassNameVisitor visitor(originalPackage);
257 manifestEl->accept(&visitor);
258 return true;
259}
260
Adam Lesinski467f1712015-11-16 17:35:44 -0800261bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) {
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800262 xml::Element* root = xml::findRootElement(doc->root.get());
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700263 if (!root || !root->namespaceUri.empty() || root->name != "manifest") {
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800264 context->getDiagnostics()->error(DiagMessage(doc->file.source)
265 << "root tag must be <manifest>");
266 return false;
267 }
268
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700269 if ((mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault)
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700270 && root->findChild({}, "uses-sdk") == nullptr) {
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700271 // Auto insert a <uses-sdk> element.
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800272 std::unique_ptr<xml::Element> usesSdk = util::make_unique<xml::Element>();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700273 usesSdk->name = "uses-sdk";
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800274 root->addChild(std::move(usesSdk));
275 }
276
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700277 xml::XmlActionExecutor executor;
278 if (!buildRules(&executor, context->getDiagnostics())) {
279 return false;
280 }
281
282 if (!executor.execute(xml::XmlActionExecutorPolicy::Whitelist, context->getDiagnostics(),
283 doc)) {
284 return false;
285 }
286
287 if (mOptions.renameManifestPackage) {
288 // Rename manifest package outside of the XmlActionExecutor.
289 // We need to extract the old package name and FullyQualify all class names.
290 if (!renameManifestPackage(mOptions.renameManifestPackage.value(), root)) {
291 return false;
292 }
293 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800294 return true;
295}
296
297} // namespace aapt