blob: 5cee17e5f3f9c2f09a486ffbfdef80fdd89ce70d [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"
Fabien Sanglard2d34e762019-02-21 15:13:29 -080024#include "trace/TraceBuffer.h"
Adam Lesinski2ae4a872015-11-02 16:10:55 -080025#include "util/Util.h"
Adam Lesinskicc5609d2016-04-05 12:41:07 -070026#include "xml/XmlActionExecutor.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080027#include "xml/XmlDom.h"
Adam Lesinski2ae4a872015-11-02 16:10:55 -080028
Adam Lesinskid5083f62017-01-16 15:07:21 -080029using android::StringPiece;
30
Adam Lesinski2ae4a872015-11-02 16:10:55 -080031namespace aapt {
32
Jeremy Meyer56f36e82022-05-20 20:35:42 +000033static bool RequiredNameIsNotEmpty(xml::Element* el, android::SourcePathDiagnostics* diag) {
Adam Lesinskifca5e422017-12-20 15:03:36 -080034 xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
35 if (attr == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +000036 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinskifca5e422017-12-20 15:03:36 -080037 << "<" << el->name << "> is missing attribute 'android:name'");
38 return false;
39 }
40
41 if (attr->value.empty()) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +000042 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinskifca5e422017-12-20 15:03:36 -080043 << "attribute 'android:name' in <" << el->name << "> tag must not be empty");
44 return false;
45 }
46 return true;
47}
48
Adam Lesinskib0c47ef2017-03-06 20:05:57 -080049// This is how PackageManager builds class names from AndroidManifest.xml entries.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070050static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
Jeremy Meyer56f36e82022-05-20 20:35:42 +000051 android::SourcePathDiagnostics* diag) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070052 // We allow unqualified class names (ie: .HelloActivity)
53 // Since we don't know the package name, we can just make a fake one here and
54 // the test will be identical as long as the real package name is valid too.
Ryan Mitchell4382e442021-07-14 12:53:01 -070055 std::optional<std::string> fully_qualified_class_name =
Adam Lesinskice5e56e2016-10-21 17:56:45 -070056 util::GetFullyQualifiedClassName("a", attr->value);
Adam Lesinskicc5609d2016-04-05 12:41:07 -070057
Adam Lesinskice5e56e2016-10-21 17:56:45 -070058 StringPiece qualified_class_name = fully_qualified_class_name
59 ? fully_qualified_class_name.value()
60 : attr->value;
Adam Lesinskid0f116b2016-07-08 15:00:32 -070061
Adam Lesinskice5e56e2016-10-21 17:56:45 -070062 if (!util::IsJavaClassName(qualified_class_name)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +000063 diag->Error(android::DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
64 << "> tag must be a valid Java class name");
Adam Lesinski52364f72016-01-11 13:10:24 -080065 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070066 }
67 return true;
68}
69
Jeremy Meyer56f36e82022-05-20 20:35:42 +000070static bool OptionalNameIsJavaClassName(xml::Element* el, android::SourcePathDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070071 if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
72 return NameIsJavaClassName(el, attr, diag);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 }
74 return true;
75}
76
Jeremy Meyer56f36e82022-05-20 20:35:42 +000077static bool RequiredNameIsJavaClassName(xml::Element* el, android::SourcePathDiagnostics* diag) {
Adam Lesinskifca5e422017-12-20 15:03:36 -080078 xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
79 if (attr == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +000080 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinskifca5e422017-12-20 15:03:36 -080081 << "<" << el->name << "> is missing attribute 'android:name'");
82 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070083 }
Adam Lesinskifca5e422017-12-20 15:03:36 -080084 return NameIsJavaClassName(el, attr, diag);
Adam Lesinski52364f72016-01-11 13:10:24 -080085}
86
Jeremy Meyer56f36e82022-05-20 20:35:42 +000087static bool RequiredNameIsJavaPackage(xml::Element* el, android::SourcePathDiagnostics* diag) {
Adam Lesinskifca5e422017-12-20 15:03:36 -080088 xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
89 if (attr == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +000090 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinskifca5e422017-12-20 15:03:36 -080091 << "<" << el->name << "> is missing attribute 'android:name'");
92 return false;
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080093 }
Adam Lesinskifca5e422017-12-20 15:03:36 -080094
95 if (!util::IsJavaPackageName(attr->value)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +000096 diag->Error(android::DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
97 << "> tag must be a valid Java package name");
Adam Lesinskifca5e422017-12-20 15:03:36 -080098 return false;
99 }
100 return true;
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800101}
102
Adam Lesinskib5dc4bd2017-02-22 19:29:29 -0800103static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std::string& attr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000104 return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
Adam Lesinskib5dc4bd2017-02-22 19:29:29 -0800105 if (el->FindAttribute(xml::kSchemaAndroid, attr) == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000106 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinskib5dc4bd2017-02-22 19:29:29 -0800107 << "<" << el->name << "> is missing required attribute 'android:" << attr << "'");
108 return false;
109 }
110 return true;
111 };
112}
113
Todd Kennedyce3e1292020-10-29 17:14:24 -0700114static xml::XmlNodeAction::ActionFuncWithDiag RequiredOneAndroidAttribute(
115 const std::string& attrName1, const std::string& attrName2) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000116 return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
Todd Kennedyce3e1292020-10-29 17:14:24 -0700117 xml::Attribute* attr1 = el->FindAttribute(xml::kSchemaAndroid, attrName1);
118 xml::Attribute* attr2 = el->FindAttribute(xml::kSchemaAndroid, attrName2);
119 if (attr1 == nullptr && attr2 == nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000120 diag->Error(android::DiagMessage(el->line_number)
Todd Kennedyce3e1292020-10-29 17:14:24 -0700121 << "<" << el->name << "> is missing required attribute 'android:" << attrName1
122 << "' or 'android:" << attrName2 << "'");
123 return false;
124 }
125 if (attr1 != nullptr && attr2 != nullptr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000126 diag->Error(android::DiagMessage(el->line_number)
Todd Kennedyce3e1292020-10-29 17:14:24 -0700127 << "<" << el->name << "> can only specify one of attribute 'android:" << attrName1
128 << "' or 'android:" << attrName2 << "'");
129 return false;
130 }
131 return true;
132 };
133}
134
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000135static bool AutoGenerateIsFeatureSplit(xml::Element* el, android::SourcePathDiagnostics* diag) {
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800136 constexpr const char* kFeatureSplit = "featureSplit";
137 constexpr const char* kIsFeatureSplit = "isFeatureSplit";
138
139 xml::Attribute* attr = el->FindAttribute({}, kFeatureSplit);
140 if (attr != nullptr) {
141 // Rewrite the featureSplit attribute to be "split". This is what the
142 // platform recognizes.
143 attr->name = "split";
144
145 // Now inject the android:isFeatureSplit="true" attribute.
146 xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsFeatureSplit);
147 if (attr != nullptr) {
Ryan Mitchell4382e442021-07-14 12:53:01 -0700148 if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800149 // The isFeatureSplit attribute is false, which conflicts with the use
150 // of "featureSplit".
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000151 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800152 << "attribute 'featureSplit' used in <manifest> but 'android:isFeatureSplit' "
153 "is not 'true'");
154 return false;
155 }
156
157 // The attribute is already there and set to true, nothing to do.
158 } else {
159 el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsFeatureSplit, "true"});
160 }
161 }
162 return true;
163}
164
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000165static bool AutoGenerateIsSplitRequired(xml::Element* el, android::SourcePathDiagnostics* diag) {
Jackal Guo0c01abb2021-07-30 22:17:43 +0800166 constexpr const char* kRequiredSplitTypes = "requiredSplitTypes";
167 constexpr const char* kIsSplitRequired = "isSplitRequired";
168
169 xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kRequiredSplitTypes);
170 if (attr != nullptr) {
171 // Now inject the android:isSplitRequired="true" attribute.
172 xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsSplitRequired);
173 if (attr != nullptr) {
174 if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
175 // The isFeatureSplit attribute is false, which conflicts with the use
176 // of "featureSplit".
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000177 diag->Error(android::DiagMessage(el->line_number)
Jackal Guo0c01abb2021-07-30 22:17:43 +0800178 << "attribute 'requiredSplitTypes' used in <manifest> but "
179 "'android:isSplitRequired' is not 'true'");
180 return false;
181 }
182 // The attribute is already there and set to true, nothing to do.
183 } else {
184 el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsSplitRequired, "true"});
185 }
186 }
187 return true;
188}
189
Rhed Jao2c434422020-11-12 10:48:03 +0800190static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy,
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000191 android::SourcePathDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700192 xml::Attribute* attr = el->FindAttribute({}, "package");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700193 if (!attr) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000194 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700195 << "<manifest> tag is missing 'package' attribute");
196 return false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700197 } else if (ResourceUtils::IsReference(attr->value)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000198 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800199 << "attribute 'package' in <manifest> tag must not be a reference");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700200 return false;
Adam Lesinski96ea08f2017-11-06 10:44:46 -0800201 } else if (!util::IsAndroidPackageName(attr->value)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000202 android::DiagMessage error_msg(el->line_number);
Rhed Jao2c434422020-11-12 10:48:03 +0800203 error_msg << "attribute 'package' in <manifest> tag is not a valid Android package name: '"
204 << attr->value << "'";
205 if (policy == xml::XmlActionExecutorPolicy::kAllowListWarning) {
206 // Treat the error only as a warning.
207 diag->Warn(error_msg);
208 } else {
209 diag->Error(error_msg);
210 return false;
211 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700212 }
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800213
214 attr = el->FindAttribute({}, "split");
215 if (attr) {
216 if (!util::IsJavaPackageName(attr->value)) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000217 diag->Error(android::DiagMessage(el->line_number)
218 << "attribute 'split' in <manifest> tag is not a "
219 "valid split name");
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800220 return false;
221 }
222 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700223 return true;
Adam Lesinski52364f72016-01-11 13:10:24 -0800224}
225
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800226// The coreApp attribute in <manifest> is not a regular AAPT attribute, so type
227// checking on it is manual.
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000228static bool FixCoreAppAttribute(xml::Element* el, android::SourcePathDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700229 if (xml::Attribute* attr = el->FindAttribute("", "coreApp")) {
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800230 std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseBool(attr->value);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700231 if (!result) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000232 diag->Error(android::DiagMessage(el->line_number) << "attribute coreApp must be a boolean");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700233 return false;
Adam Lesinski6b17d2c2016-08-10 11:37:06 -0700234 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700235 attr->compiled_value = std::move(result);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700236 }
237 return true;
Adam Lesinski6b17d2c2016-08-10 11:37:06 -0700238}
239
Adam Lesinski86d67df2017-01-31 13:47:27 -0800240// Checks that <uses-feature> has android:glEsVersion or android:name, not both (or neither).
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000241static bool VerifyUsesFeature(xml::Element* el, android::SourcePathDiagnostics* diag) {
Adam Lesinski86d67df2017-01-31 13:47:27 -0800242 bool has_name = false;
243 if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
244 if (attr->value.empty()) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000245 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinski86d67df2017-01-31 13:47:27 -0800246 << "android:name in <uses-feature> must not be empty");
247 return false;
248 }
249 has_name = true;
250 }
251
252 bool has_gl_es_version = false;
253 if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
254 if (has_name) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000255 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinski86d67df2017-01-31 13:47:27 -0800256 << "cannot define both android:name and android:glEsVersion in <uses-feature>");
257 return false;
258 }
259 has_gl_es_version = true;
260 }
261
262 if (!has_name && !has_gl_es_version) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000263 diag->Error(android::DiagMessage(el->line_number)
Adam Lesinski86d67df2017-01-31 13:47:27 -0800264 << "<uses-feature> must have either android:name or android:glEsVersion attribute");
265 return false;
266 }
267 return true;
268}
269
Donald Chai6e497352019-05-19 21:07:50 -0700270// Ensure that 'ns_decls' contains a declaration for 'uri', using 'prefix' as
271// the xmlns prefix if possible.
272static void EnsureNamespaceIsDeclared(const std::string& prefix, const std::string& uri,
273 std::vector<xml::NamespaceDecl>* ns_decls) {
274 if (std::find_if(ns_decls->begin(), ns_decls->end(), [&](const xml::NamespaceDecl& ns_decl) {
275 return ns_decl.uri == uri;
276 }) != ns_decls->end()) {
277 return;
278 }
279
280 std::set<std::string> used_prefixes;
281 for (const auto& ns_decl : *ns_decls) {
282 used_prefixes.insert(ns_decl.prefix);
283 }
284
285 // Make multiple attempts in the unlikely event that 'prefix' is already taken.
286 std::string disambiguator;
287 for (int i = 0; i < used_prefixes.size() + 1; i++) {
288 std::string attempted_prefix = prefix + disambiguator;
289 if (used_prefixes.find(attempted_prefix) == used_prefixes.end()) {
290 ns_decls->push_back(xml::NamespaceDecl{attempted_prefix, uri});
291 return;
292 }
293 disambiguator = std::to_string(i);
294 }
295}
296
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000297bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700298 // First verify some options.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700299 if (options_.rename_manifest_package) {
300 if (!util::IsJavaPackageName(options_.rename_manifest_package.value())) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000301 diag->Error(android::DiagMessage() << "invalid manifest package override '"
302 << options_.rename_manifest_package.value() << "'");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700303 return false;
304 }
305 }
306
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700307 if (options_.rename_instrumentation_target_package) {
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800308 if (!util::IsJavaPackageName(options_.rename_instrumentation_target_package.value())) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000309 diag->Error(android::DiagMessage()
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700310 << "invalid instrumentation target package override '"
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000311 << options_.rename_instrumentation_target_package.value() << "'");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700312 return false;
313 }
314 }
315
Roshan Piusae12ce42020-04-25 16:08:55 -0700316 if (options_.rename_overlay_target_package) {
317 if (!util::IsJavaPackageName(options_.rename_overlay_target_package.value())) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000318 diag->Error(android::DiagMessage() << "invalid overlay target package override '"
319 << options_.rename_overlay_target_package.value() << "'");
Roshan Piusae12ce42020-04-25 16:08:55 -0700320 return false;
321 }
322 }
323
Adam Lesinski86d67df2017-01-31 13:47:27 -0800324 // Common <intent-filter> actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700325 xml::XmlNodeAction intent_filter_action;
Adam Lesinskifca5e422017-12-20 15:03:36 -0800326 intent_filter_action["action"].Action(RequiredNameIsNotEmpty);
327 intent_filter_action["category"].Action(RequiredNameIsNotEmpty);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700328 intent_filter_action["data"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700329
Adam Lesinski86d67df2017-01-31 13:47:27 -0800330 // Common <meta-data> actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700331 xml::XmlNodeAction meta_data_action;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700332
Todd Kennedyce3e1292020-10-29 17:14:24 -0700333 // Common <property> actions.
334 xml::XmlNodeAction property_action;
335 property_action.Action(RequiredOneAndroidAttribute("resource", "value"));
336
Adam Lesinski86d67df2017-01-31 13:47:27 -0800337 // Common <uses-feature> actions.
338 xml::XmlNodeAction uses_feature_action;
339 uses_feature_action.Action(VerifyUsesFeature);
340
341 // Common component actions.
342 xml::XmlNodeAction component_action;
343 component_action.Action(RequiredNameIsJavaClassName);
344 component_action["intent-filter"] = intent_filter_action;
Ryan Mitchell28afe682018-09-07 14:33:14 -0700345 component_action["preferred"] = intent_filter_action;
Adam Lesinski86d67df2017-01-31 13:47:27 -0800346 component_action["meta-data"] = meta_data_action;
Todd Kennedyce3e1292020-10-29 17:14:24 -0700347 component_action["property"] = property_action;
Adam Lesinski86d67df2017-01-31 13:47:27 -0800348
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700349 // Manifest actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700350 xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800351 manifest_action.Action(AutoGenerateIsFeatureSplit);
Jackal Guo0c01abb2021-07-30 22:17:43 +0800352 manifest_action.Action(AutoGenerateIsSplitRequired);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700353 manifest_action.Action(VerifyManifest);
354 manifest_action.Action(FixCoreAppAttribute);
355 manifest_action.Action([&](xml::Element* el) -> bool {
Donald Chai6e497352019-05-19 21:07:50 -0700356 EnsureNamespaceIsDeclared("android", xml::kSchemaAndroid, &el->namespace_decls);
357
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700358 if (options_.version_name_default) {
Colin Crossdcd58c42018-05-25 22:46:35 -0700359 if (options_.replace_version) {
360 el->RemoveAttribute(xml::kSchemaAndroid, "versionName");
361 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700362 if (el->FindAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700363 el->attributes.push_back(
364 xml::Attribute{xml::kSchemaAndroid, "versionName",
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700365 options_.version_name_default.value()});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700366 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700367 }
368
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700369 if (options_.version_code_default) {
Colin Crossdcd58c42018-05-25 22:46:35 -0700370 if (options_.replace_version) {
371 el->RemoveAttribute(xml::kSchemaAndroid, "versionCode");
372 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700373 if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700374 el->attributes.push_back(
375 xml::Attribute{xml::kSchemaAndroid, "versionCode",
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700376 options_.version_code_default.value()});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700377 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700378 }
Ryan Mitchell7cb82a82018-05-10 15:35:31 -0700379
Ryan Mitchell704090e2018-07-31 14:59:25 -0700380 if (options_.version_code_major_default) {
381 if (options_.replace_version) {
382 el->RemoveAttribute(xml::kSchemaAndroid, "versionCodeMajor");
383 }
384 if (el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor") == nullptr) {
385 el->attributes.push_back(
386 xml::Attribute{xml::kSchemaAndroid, "versionCodeMajor",
387 options_.version_code_major_default.value()});
388 }
389 }
390
Rhed Jaob9ccb8a42020-11-30 21:42:16 +0800391 if (options_.revision_code_default) {
392 if (options_.replace_version) {
393 el->RemoveAttribute(xml::kSchemaAndroid, "revisionCode");
394 }
395 if (el->FindAttribute(xml::kSchemaAndroid, "revisionCode") == nullptr) {
396 el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "revisionCode",
397 options_.revision_code_default.value()});
398 }
399 }
400
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800401 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700402 });
403
404 // Meta tags.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700405 manifest_action["eat-comment"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700406
407 // Uses-sdk actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700408 manifest_action["uses-sdk"].Action([&](xml::Element* el) -> bool {
409 if (options_.min_sdk_version_default &&
410 el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700411 // There was no minSdkVersion defined and we have a default to assign.
412 el->attributes.push_back(
413 xml::Attribute{xml::kSchemaAndroid, "minSdkVersion",
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700414 options_.min_sdk_version_default.value()});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700415 }
416
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700417 if (options_.target_sdk_version_default &&
418 el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion") == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700419 // There was no targetSdkVersion defined and we have a default to assign.
420 el->attributes.push_back(
421 xml::Attribute{xml::kSchemaAndroid, "targetSdkVersion",
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700422 options_.target_sdk_version_default.value()});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700423 }
424 return true;
425 });
Anton Hanssonb2f709d2020-01-09 10:25:23 +0000426 manifest_action["uses-sdk"]["extension-sdk"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700427
428 // Instrumentation actions.
Adam Lesinski86d67df2017-01-31 13:47:27 -0800429 manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700430 manifest_action["instrumentation"].Action([&](xml::Element* el) -> bool {
431 if (!options_.rename_instrumentation_target_package) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700432 return true;
433 }
434
435 if (xml::Attribute* attr =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700436 el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
437 attr->value = options_.rename_instrumentation_target_package.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700438 }
439 return true;
440 });
Adam Lesinski86d67df2017-01-31 13:47:27 -0800441 manifest_action["instrumentation"]["meta-data"] = meta_data_action;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700442
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800443 manifest_action["attribution"];
444 manifest_action["attribution"]["inherit-from"];
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700445 manifest_action["original-package"];
Roshan Piusae12ce42020-04-25 16:08:55 -0700446 manifest_action["overlay"].Action([&](xml::Element* el) -> bool {
Jeremy Meyer6b05b7d2022-09-30 22:22:24 +0000447 if (options_.rename_overlay_target_package) {
448 if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
449 attr->value = options_.rename_overlay_target_package.value();
450 }
Roshan Piusae12ce42020-04-25 16:08:55 -0700451 }
Jeremy Meyer6b05b7d2022-09-30 22:22:24 +0000452 if (options_.rename_overlay_category) {
453 if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "category")) {
454 attr->value = options_.rename_overlay_category.value();
455 } else {
456 el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "category",
457 options_.rename_overlay_category.value()});
458 }
Roshan Piusae12ce42020-04-25 16:08:55 -0700459 }
460 return true;
461 });
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700462 manifest_action["protected-broadcast"];
Alan Viverettecf5326f2018-01-05 16:03:50 -0500463 manifest_action["adopt-permissions"];
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700464 manifest_action["uses-permission"];
Sergey Nikolaienkov65f90992020-09-30 08:17:09 +0000465 manifest_action["uses-permission"]["required-feature"].Action(RequiredNameIsNotEmpty);
466 manifest_action["uses-permission"]["required-not-feature"].Action(RequiredNameIsNotEmpty);
Adam Lesinski4b585db2017-05-12 15:25:50 -0700467 manifest_action["uses-permission-sdk-23"];
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700468 manifest_action["permission"];
Ryan Mitchell66f6cfb2018-07-25 16:15:17 -0700469 manifest_action["permission"]["meta-data"] = meta_data_action;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700470 manifest_action["permission-tree"];
471 manifest_action["permission-group"];
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700472 manifest_action["uses-configuration"];
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700473 manifest_action["supports-screens"];
Adam Lesinski86d67df2017-01-31 13:47:27 -0800474 manifest_action["uses-feature"] = uses_feature_action;
475 manifest_action["feature-group"]["uses-feature"] = uses_feature_action;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700476 manifest_action["compatible-screens"];
477 manifest_action["compatible-screens"]["screen"];
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700478 manifest_action["supports-gl-texture"];
Ryan Mitchell66f6cfb2018-07-25 16:15:17 -0700479 manifest_action["restrict-update"];
MÃ¥rten Kongstadb0502bb2022-05-16 15:23:40 +0200480 manifest_action["install-constraints"]["fingerprint-prefix"];
Ryan Mitchell66f6cfb2018-07-25 16:15:17 -0700481 manifest_action["package-verifier"];
Adam Lesinski5119e512016-12-05 19:48:20 -0800482 manifest_action["meta-data"] = meta_data_action;
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800483 manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
Patrick Baumanna4ffb452019-06-24 15:01:49 -0700484 manifest_action["queries"]["package"].Action(RequiredNameIsJavaPackage);
485 manifest_action["queries"]["intent"] = intent_filter_action;
Patrick Baumann99181232020-01-28 10:55:25 -0800486 manifest_action["queries"]["provider"].Action(RequiredAndroidAttribute("authorities"));
Patrick Baumanna4ffb452019-06-24 15:01:49 -0700487 // TODO: more complicated component name tag
Adam Lesinski5119e512016-12-05 19:48:20 -0800488
Adam Lesinski87f1e0f2017-06-27 16:21:58 -0700489 manifest_action["key-sets"]["key-set"]["public-key"];
490 manifest_action["key-sets"]["upgrade-key-set"];
491
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700492 // Application actions.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700493 xml::XmlNodeAction& application_action = manifest_action["application"];
494 application_action.Action(OptionalNameIsJavaClassName);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700495
Adam Lesinskifca5e422017-12-20 15:03:36 -0800496 application_action["uses-library"].Action(RequiredNameIsNotEmpty);
Jiyong Park6a5b8b12020-06-30 13:23:36 +0900497 application_action["uses-native-library"].Action(RequiredNameIsNotEmpty);
Adam Lesinskifca5e422017-12-20 15:03:36 -0800498 application_action["library"].Action(RequiredNameIsNotEmpty);
Chris Craik335b5652019-04-04 12:46:47 -0700499 application_action["profileable"];
Todd Kennedyce3e1292020-10-29 17:14:24 -0700500 application_action["property"] = property_action;
Adam Lesinskib5dc4bd2017-02-22 19:29:29 -0800501
502 xml::XmlNodeAction& static_library_action = application_action["static-library"];
503 static_library_action.Action(RequiredNameIsJavaPackage);
504 static_library_action.Action(RequiredAndroidAttribute("version"));
505
506 xml::XmlNodeAction& uses_static_library_action = application_action["uses-static-library"];
507 uses_static_library_action.Action(RequiredNameIsJavaPackage);
508 uses_static_library_action.Action(RequiredAndroidAttribute("version"));
509 uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
Ryan Mitchell66f6cfb2018-07-25 16:15:17 -0700510 uses_static_library_action["additional-certificate"];
Adam Lesinskib5dc4bd2017-02-22 19:29:29 -0800511
Alex Buynytskyya16137052021-12-02 13:26:54 +0000512 xml::XmlNodeAction& sdk_library_action = application_action["sdk-library"];
513 sdk_library_action.Action(RequiredNameIsJavaPackage);
514 sdk_library_action.Action(RequiredAndroidAttribute("versionMajor"));
515
516 xml::XmlNodeAction& uses_sdk_library_action = application_action["uses-sdk-library"];
517 uses_sdk_library_action.Action(RequiredNameIsJavaPackage);
518 uses_sdk_library_action.Action(RequiredAndroidAttribute("versionMajor"));
519 uses_sdk_library_action.Action(RequiredAndroidAttribute("certDigest"));
520 uses_sdk_library_action["additional-certificate"];
521
Dianne Hackborn813d7502018-10-02 16:59:46 -0700522 xml::XmlNodeAction& uses_package_action = application_action["uses-package"];
523 uses_package_action.Action(RequiredNameIsJavaPackage);
524 uses_package_action["additional-certificate"];
525
Ryan Mitchelle5b38a62018-03-23 13:35:00 -0700526 if (options_.debug_mode) {
527 application_action.Action([&](xml::Element* el) -> bool {
528 xml::Attribute *attr = el->FindOrCreateAttribute(xml::kSchemaAndroid, "debuggable");
529 attr->value = "true";
530 return true;
531 });
532 }
533
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700534 application_action["meta-data"] = meta_data_action;
Adam Lesinski7a917a22017-06-02 12:55:24 -0700535
Dianne Hackbornfc0839a2020-01-31 11:02:28 -0800536 application_action["processes"];
537 application_action["processes"]["deny-permission"];
538 application_action["processes"]["allow-permission"];
539 application_action["processes"]["process"]["deny-permission"];
540 application_action["processes"]["process"]["allow-permission"];
541
Adam Lesinski86d67df2017-01-31 13:47:27 -0800542 application_action["activity"] = component_action;
Adam Lesinski7a917a22017-06-02 12:55:24 -0700543 application_action["activity"]["layout"];
544
Adam Lesinski86d67df2017-01-31 13:47:27 -0800545 application_action["activity-alias"] = component_action;
546 application_action["service"] = component_action;
547 application_action["receiver"] = component_action;
Gavin Corkeryad5d4ba2021-10-26 12:24:43 +0100548 application_action["apex-system-service"] = component_action;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700549
550 // Provider actions.
Adam Lesinski86d67df2017-01-31 13:47:27 -0800551 application_action["provider"] = component_action;
Adam Lesinskic10c0d02017-04-28 12:54:08 -0700552 application_action["provider"]["grant-uri-permission"];
Adam Lesinski25783ca2017-04-24 13:33:47 -0700553 application_action["provider"]["path-permission"];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700554
Ryan Mitchell28afe682018-09-07 14:33:14 -0700555 manifest_action["package"] = manifest_action;
556
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700557 return true;
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800558}
559
Adam Lesinski23034b92017-11-29 16:27:44 -0800560static void FullyQualifyClassName(const StringPiece& package, const StringPiece& attr_ns,
561 const StringPiece& attr_name, xml::Element* el) {
562 xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
563 if (attr != nullptr) {
Ryan Mitchell4382e442021-07-14 12:53:01 -0700564 if (std::optional<std::string> new_value =
565 util::GetFullyQualifiedClassName(package, attr->value)) {
Adam Lesinski23034b92017-11-29 16:27:44 -0800566 attr->value = std::move(new_value.value());
Adam Lesinski52364f72016-01-11 13:10:24 -0800567 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700568 }
Adam Lesinski23034b92017-11-29 16:27:44 -0800569}
Adam Lesinski52364f72016-01-11 13:10:24 -0800570
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800571static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700572 xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
Adam Lesinski52364f72016-01-11 13:10:24 -0800573
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700574 // We've already verified that the manifest element is present, with a package
575 // name specified.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700576 CHECK(attr != nullptr);
Adam Lesinski52364f72016-01-11 13:10:24 -0800577
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700578 std::string original_package = std::move(attr->value);
Adam Lesinskid5083f62017-01-16 15:07:21 -0800579 attr->value = package_override.to_string();
Adam Lesinski52364f72016-01-11 13:10:24 -0800580
Adam Lesinski23034b92017-11-29 16:27:44 -0800581 xml::Element* application_el = manifest_el->FindChild({}, "application");
582 if (application_el != nullptr) {
583 FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", application_el);
584 FullyQualifyClassName(original_package, xml::kSchemaAndroid, "backupAgent", application_el);
585
586 for (xml::Element* child_el : application_el->GetChildElements()) {
587 if (child_el->namespace_uri.empty()) {
588 if (child_el->name == "activity" || child_el->name == "activity-alias" ||
589 child_el->name == "provider" || child_el->name == "receiver" ||
590 child_el->name == "service") {
591 FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", child_el);
Makoto Onuki808fd192021-12-10 09:40:54 -0800592 continue;
Adam Lesinski23034b92017-11-29 16:27:44 -0800593 }
594
595 if (child_el->name == "activity-alias") {
596 FullyQualifyClassName(original_package, xml::kSchemaAndroid, "targetActivity", child_el);
Makoto Onuki808fd192021-12-10 09:40:54 -0800597 continue;
598 }
599
600 if (child_el->name == "processes") {
601 for (xml::Element* grand_child_el : child_el->GetChildElements()) {
602 if (grand_child_el->name == "process") {
603 FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", grand_child_el);
604 }
605 }
606 continue;
Adam Lesinski23034b92017-11-29 16:27:44 -0800607 }
608 }
609 }
610 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700611 return true;
Adam Lesinski52364f72016-01-11 13:10:24 -0800612}
613
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700614bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
Fabien Sanglard2d34e762019-02-21 15:13:29 -0800615 TRACE_CALL();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700616 xml::Element* root = xml::FindRootElement(doc->root.get());
617 if (!root || !root->namespace_uri.empty() || root->name != "manifest") {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000618 context->GetDiagnostics()->Error(android::DiagMessage(doc->file.source)
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700619 << "root tag must be <manifest>");
620 return false;
621 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800622
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800623 if ((options_.min_sdk_version_default || options_.target_sdk_version_default) &&
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700624 root->FindChild({}, "uses-sdk") == nullptr) {
Adam Lesinskie343eb12016-10-27 16:31:58 -0700625 // Auto insert a <uses-sdk> element. This must be inserted before the
626 // <application> tag. The device runtime PackageParser will make SDK version
627 // decisions while parsing <application>.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700628 std::unique_ptr<xml::Element> uses_sdk = util::make_unique<xml::Element>();
629 uses_sdk->name = "uses-sdk";
Adam Lesinskie343eb12016-10-27 16:31:58 -0700630 root->InsertChild(0, std::move(uses_sdk));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700631 }
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800632
Adam Lesinskic6284372017-12-04 13:46:23 -0800633 if (options_.compile_sdk_version) {
634 xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion");
635
636 // Make sure we un-compile the value if it was set to something else.
637 attr->compiled_value = {};
Adam Lesinskic6284372017-12-04 13:46:23 -0800638 attr->value = options_.compile_sdk_version.value();
Ryan Mitchellaada89c2019-02-12 08:06:26 -0800639
640 attr = root->FindOrCreateAttribute("", "platformBuildVersionCode");
641
642 // Make sure we un-compile the value if it was set to something else.
643 attr->compiled_value = {};
644 attr->value = options_.compile_sdk_version.value();
645
Adam Lesinskic6284372017-12-04 13:46:23 -0800646 }
647
648 if (options_.compile_sdk_version_codename) {
649 xml::Attribute* attr =
650 root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
651
652 // Make sure we un-compile the value if it was set to something else.
653 attr->compiled_value = {};
Ryan Mitchellaada89c2019-02-12 08:06:26 -0800654 attr->value = options_.compile_sdk_version_codename.value();
Adam Lesinskic6284372017-12-04 13:46:23 -0800655
Ryan Mitchellaada89c2019-02-12 08:06:26 -0800656 attr = root->FindOrCreateAttribute("", "platformBuildVersionName");
657
658 // Make sure we un-compile the value if it was set to something else.
659 attr->compiled_value = {};
Adam Lesinskic6284372017-12-04 13:46:23 -0800660 attr->value = options_.compile_sdk_version_codename.value();
661 }
662
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700663 xml::XmlActionExecutor executor;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700664 if (!BuildRules(&executor, context->GetDiagnostics())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700665 return false;
666 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700667
Izabela Orlowskaad9e1322017-12-19 16:22:42 +0000668 xml::XmlActionExecutorPolicy policy = options_.warn_validation
Ryan Mitchell4ea90752020-07-31 08:21:43 -0700669 ? xml::XmlActionExecutorPolicy::kAllowListWarning
670 : xml::XmlActionExecutorPolicy::kAllowList;
Izabela Orlowskaad9e1322017-12-19 16:22:42 +0000671 if (!executor.Execute(policy, context->GetDiagnostics(), doc)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700672 return false;
673 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700674
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700675 if (options_.rename_manifest_package) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700676 // Rename manifest package outside of the XmlActionExecutor.
Adam Lesinskie343eb12016-10-27 16:31:58 -0700677 // We need to extract the old package name and FullyQualify all class
678 // names.
Adam Lesinskib0c47ef2017-03-06 20:05:57 -0800679 if (!RenameManifestPackage(options_.rename_manifest_package.value(), root)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700680 return false;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700681 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700682 }
683 return true;
Adam Lesinski2ae4a872015-11-02 16:10:55 -0800684}
685
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700686} // namespace aapt