blob: 36a34941347fbc43d89082b72d1918eb0ba61f81 [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
Adam Lesinski2ae4a872015-11-02 16:10:55 -080017#include "link/ManifestFixer.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070018
19#include <unordered_set>
20
21#include "android-base/logging.h"
22
Adam Lesinskicacb28f2016-10-19 12:18:14 -070023#include "ResourceUtils.h"
Adam Lesinski2ae4a872015-11-02 16:10:55 -080024#include "util/Util.h"
Adam Lesinskicc5609d2016-04-05 12:41:07 -070025#include "xml/XmlActionExecutor.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080026#include "xml/XmlDom.h"
Adam Lesinski2ae4a872015-11-02 16:10:55 -080027
28namespace aapt {
29
Adam Lesinskicc5609d2016-04-05 12:41:07 -070030/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -070031 * This is how PackageManager builds class names from AndroidManifest.xml
32 * entries.
Adam Lesinskicc5609d2016-04-05 12:41:07 -070033 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -070034static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
Adam Lesinskicc5609d2016-04-05 12:41:07 -070035 SourcePathDiagnostics* diag) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070036 // We allow unqualified class names (ie: .HelloActivity)
37 // Since we don't know the package name, we can just make a fake one here and
38 // the test will be identical as long as the real package name is valid too.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070039 Maybe<std::string> fully_qualified_class_name =
40 util::GetFullyQualifiedClassName("a", attr->value);
Adam Lesinskicc5609d2016-04-05 12:41:07 -070041
Adam Lesinskice5e56e2016-10-21 17:56:45 -070042 StringPiece qualified_class_name = fully_qualified_class_name
43 ? fully_qualified_class_name.value()
44 : attr->value;
Adam Lesinskid0f116b2016-07-08 15:00:32 -070045
Adam Lesinskice5e56e2016-10-21 17:56:45 -070046 if (!util::IsJavaClassName(qualified_class_name)) {
47 diag->Error(DiagMessage(el->line_number)
Adam Lesinskicacb28f2016-10-19 12:18:14 -070048 << "attribute 'android:name' in <" << el->name
49 << "> tag must be a valid Java class name");
Adam Lesinski52364f72016-01-11 13:10:24 -080050 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070051 }
52 return true;
53}
54
Adam Lesinskice5e56e2016-10-21 17:56:45 -070055static bool OptionalNameIsJavaClassName(xml::Element* el,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070056 SourcePathDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070057 if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
58 return NameIsJavaClassName(el, attr, diag);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070059 }
60 return true;
61}
62
Adam Lesinskice5e56e2016-10-21 17:56:45 -070063static bool RequiredNameIsJavaClassName(xml::Element* el,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 SourcePathDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070065 if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
66 return NameIsJavaClassName(el, attr, diag);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070067 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070068 diag->Error(DiagMessage(el->line_number)
Adam Lesinskicacb28f2016-10-19 12:18:14 -070069 << "<" << el->name << "> is missing attribute 'android:name'");
70 return false;
Adam Lesinski52364f72016-01-11 13:10:24 -080071}
72
Adam Lesinskice5e56e2016-10-21 17:56:45 -070073static bool VerifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
74 xml::Attribute* attr = el->FindAttribute({}, "package");
Adam Lesinskicacb28f2016-10-19 12:18:14 -070075 if (!attr) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070076 diag->Error(DiagMessage(el->line_number)
Adam Lesinskicacb28f2016-10-19 12:18:14 -070077 << "<manifest> tag is missing 'package' attribute");
78 return false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070079 } else if (ResourceUtils::IsReference(attr->value)) {
80 diag->Error(
81 DiagMessage(el->line_number)
Adam Lesinskicacb28f2016-10-19 12:18:14 -070082 << "attribute 'package' in <manifest> tag must not be a reference");
83 return false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070084 } else if (!util::IsJavaPackageName(attr->value)) {
85 diag->Error(DiagMessage(el->line_number)
Adam Lesinskicacb28f2016-10-19 12:18:14 -070086 << "attribute 'package' in <manifest> tag is not a valid Java "
87 "package name: '"
88 << attr->value << "'");
89 return false;
90 }
91 return true;
Adam Lesinski52364f72016-01-11 13:10:24 -080092}
93
Adam Lesinski6b17d2c2016-08-10 11:37:06 -070094/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -070095 * The coreApp attribute in <manifest> is not a regular AAPT attribute, so type
Adam Lesinskice5e56e2016-10-21 17:56:45 -070096 * checking on it is manual.
Adam Lesinski6b17d2c2016-08-10 11:37:06 -070097 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -070098static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
99 if (xml::Attribute* attr = el->FindAttribute("", "coreApp")) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700100 std::unique_ptr<BinaryPrimitive> result =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700101 ResourceUtils::TryParseBool(attr->value);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700102 if (!result) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700103 diag->Error(DiagMessage(el->line_number)
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700104 << "attribute coreApp must be a boolean");
105 return false;
Adam Lesinski6b17d2c2016-08-10 11:37:06 -0700106 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700107 attr->compiled_value = std::move(result);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700108 }
109 return true;
Adam Lesinski6b17d2c2016-08-10 11:37:06 -0700110}
111
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700112bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700113 IDiagnostics* diag) {
114 // First verify some options.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700115 if (options_.rename_manifest_package) {
116 if (!util::IsJavaPackageName(options_.rename_manifest_package.value())) {
117 diag->Error(DiagMessage() << "invalid manifest package override '"
118 << options_.rename_manifest_package.value()
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700119 << "'");
120 return false;
121 }
122 }
123
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700124 if (options_.rename_instrumentation_target_package) {
125 if (!util::IsJavaPackageName(
126 options_.rename_instrumentation_target_package.value())) {
127 diag->Error(DiagMessage()
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700128 << "invalid instrumentation target package override '"
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700129 << options_.rename_instrumentation_target_package.value()
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700130 << "'");
131 return false;
132 }
133 }
134
135 // Common intent-filter actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700136 xml::XmlNodeAction intent_filter_action;
137 intent_filter_action["action"];
138 intent_filter_action["category"];
139 intent_filter_action["data"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700140
141 // Common meta-data actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700142 xml::XmlNodeAction meta_data_action;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143
144 // Manifest actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700145 xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
146 manifest_action.Action(VerifyManifest);
147 manifest_action.Action(FixCoreAppAttribute);
148 manifest_action.Action([&](xml::Element* el) -> bool {
149 if (options_.version_name_default) {
150 if (el->FindAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700151 el->attributes.push_back(
152 xml::Attribute{xml::kSchemaAndroid, "versionName",
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700153 options_.version_name_default.value()});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700154 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700155 }
156
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700157 if (options_.version_code_default) {
158 if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700159 el->attributes.push_back(
160 xml::Attribute{xml::kSchemaAndroid, "versionCode",
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700161 options_.version_code_default.value()});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700162 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700163 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800164 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700165 });
166
167 // Meta tags.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700168 manifest_action["eat-comment"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700169
170 // Uses-sdk actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700171 manifest_action["uses-sdk"].Action([&](xml::Element* el) -> bool {
172 if (options_.min_sdk_version_default &&
173 el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700174 // There was no minSdkVersion defined and we have a default to assign.
175 el->attributes.push_back(
176 xml::Attribute{xml::kSchemaAndroid, "minSdkVersion",
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700177 options_.min_sdk_version_default.value()});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700178 }
179
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700180 if (options_.target_sdk_version_default &&
181 el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion") == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700182 // There was no targetSdkVersion defined and we have a default to assign.
183 el->attributes.push_back(
184 xml::Attribute{xml::kSchemaAndroid, "targetSdkVersion",
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700185 options_.target_sdk_version_default.value()});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700186 }
187 return true;
188 });
189
190 // Instrumentation actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700191 manifest_action["instrumentation"].Action([&](xml::Element* el) -> bool {
192 if (!options_.rename_instrumentation_target_package) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700193 return true;
194 }
195
196 if (xml::Attribute* attr =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700197 el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
198 attr->value = options_.rename_instrumentation_target_package.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700199 }
200 return true;
201 });
202
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700203 manifest_action["original-package"];
204 manifest_action["protected-broadcast"];
205 manifest_action["uses-permission"];
206 manifest_action["permission"];
207 manifest_action["permission-tree"];
208 manifest_action["permission-group"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700209
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700210 manifest_action["uses-configuration"];
211 manifest_action["uses-feature"];
212 manifest_action["supports-screens"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700213
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700214 manifest_action["compatible-screens"];
215 manifest_action["compatible-screens"]["screen"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700216
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700217 manifest_action["supports-gl-texture"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700218
219 // Application actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 xml::XmlNodeAction& application_action = manifest_action["application"];
221 application_action.Action(OptionalNameIsJavaClassName);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700222
223 // Uses library actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700224 application_action["uses-library"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700225
226 // Meta-data.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700227 application_action["meta-data"] = meta_data_action;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700228
229 // Activity actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700230 application_action["activity"].Action(RequiredNameIsJavaClassName);
231 application_action["activity"]["intent-filter"] = intent_filter_action;
232 application_action["activity"]["meta-data"] = meta_data_action;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700233
234 // Activity alias actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700235 application_action["activity-alias"]["intent-filter"] = intent_filter_action;
236 application_action["activity-alias"]["meta-data"] = meta_data_action;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700237
238 // Service actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700239 application_action["service"].Action(RequiredNameIsJavaClassName);
240 application_action["service"]["intent-filter"] = intent_filter_action;
241 application_action["service"]["meta-data"] = meta_data_action;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700242
243 // Receiver actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700244 application_action["receiver"].Action(RequiredNameIsJavaClassName);
245 application_action["receiver"]["intent-filter"] = intent_filter_action;
246 application_action["receiver"]["meta-data"] = meta_data_action;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700247
248 // Provider actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700249 application_action["provider"].Action(RequiredNameIsJavaClassName);
250 application_action["provider"]["intent-filter"] = intent_filter_action;
251 application_action["provider"]["meta-data"] = meta_data_action;
252 application_action["provider"]["grant-uri-permissions"];
253 application_action["provider"]["path-permissions"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700254
255 return true;
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800256}
257
Adam Lesinski52364f72016-01-11 13:10:24 -0800258class FullyQualifiedClassNameVisitor : public xml::Visitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700259 public:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700260 using xml::Visitor::Visit;
Adam Lesinski52364f72016-01-11 13:10:24 -0800261
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700262 explicit FullyQualifiedClassNameVisitor(const StringPiece& package)
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700263 : package_(package) {}
Adam Lesinski52364f72016-01-11 13:10:24 -0800264
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700265 void Visit(xml::Element* el) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700266 for (xml::Attribute& attr : el->attributes) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700267 if (attr.namespace_uri == xml::kSchemaAndroid &&
268 class_attributes_.find(attr.name) != class_attributes_.end()) {
269 if (Maybe<std::string> new_value =
270 util::GetFullyQualifiedClassName(package_, attr.value)) {
271 attr.value = std::move(new_value.value());
Adam Lesinski52364f72016-01-11 13:10:24 -0800272 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700273 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800274 }
275
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700276 // Super implementation to iterate over the children.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700277 xml::Visitor::Visit(el);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700278 }
279
280 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700281 StringPiece package_;
282 std::unordered_set<StringPiece> class_attributes_ = {"name"};
Adam Lesinski52364f72016-01-11 13:10:24 -0800283};
284
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700285static bool RenameManifestPackage(const StringPiece& package_override,
286 xml::Element* manifest_el) {
287 xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
Adam Lesinski52364f72016-01-11 13:10:24 -0800288
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700289 // We've already verified that the manifest element is present, with a package
290 // name specified.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700291 CHECK(attr != nullptr);
Adam Lesinski52364f72016-01-11 13:10:24 -0800292
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700293 std::string original_package = std::move(attr->value);
294 attr->value = package_override.ToString();
Adam Lesinski52364f72016-01-11 13:10:24 -0800295
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700296 FullyQualifiedClassNameVisitor visitor(original_package);
297 manifest_el->Accept(&visitor);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700298 return true;
Adam Lesinski52364f72016-01-11 13:10:24 -0800299}
300
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700301bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
302 xml::Element* root = xml::FindRootElement(doc->root.get());
303 if (!root || !root->namespace_uri.empty() || root->name != "manifest") {
304 context->GetDiagnostics()->Error(DiagMessage(doc->file.source)
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700305 << "root tag must be <manifest>");
306 return false;
307 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800308
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700309 if ((options_.min_sdk_version_default ||
310 options_.target_sdk_version_default) &&
311 root->FindChild({}, "uses-sdk") == nullptr) {
Adam Lesinskie343eb12016-10-27 16:31:58 -0700312 // Auto insert a <uses-sdk> element. This must be inserted before the
313 // <application> tag. The device runtime PackageParser will make SDK version
314 // decisions while parsing <application>.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700315 std::unique_ptr<xml::Element> uses_sdk = util::make_unique<xml::Element>();
316 uses_sdk->name = "uses-sdk";
Adam Lesinskie343eb12016-10-27 16:31:58 -0700317 root->InsertChild(0, std::move(uses_sdk));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700318 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800319
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700320 xml::XmlActionExecutor executor;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700321 if (!BuildRules(&executor, context->GetDiagnostics())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700322 return false;
323 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700324
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700325 if (!executor.Execute(xml::XmlActionExecutorPolicy::kWhitelist,
326 context->GetDiagnostics(), doc)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700327 return false;
328 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700329
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700330 if (options_.rename_manifest_package) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700331 // Rename manifest package outside of the XmlActionExecutor.
Adam Lesinskie343eb12016-10-27 16:31:58 -0700332 // We need to extract the old package name and FullyQualify all class
333 // names.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700334 if (!RenameManifestPackage(options_.rename_manifest_package.value(),
335 root)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700336 return false;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700337 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700338 }
339 return true;
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800340}
341
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700342} // namespace aapt