blob: ea68b61f89c41559ab5fab4df6dae0605b8a02db [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
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 Lesinskice5e56e2016-10-21 17:56:45 -070017#include "link/ReferenceLinker.h"
18
19#include "android-base/logging.h"
20#include "androidfw/ResourceTypes.h"
21
Adam Lesinskicacb28f2016-10-19 12:18:14 -070022#include "Diagnostics.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070023#include "ResourceTable.h"
24#include "ResourceUtils.h"
25#include "ResourceValues.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070026#include "ValueVisitor.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070027#include "link/Linkers.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070028#include "process/IResourceTableConsumer.h"
29#include "process/SymbolTable.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080030#include "util/Util.h"
31#include "xml/XmlUtil.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070032
Adam Lesinskid5083f62017-01-16 15:07:21 -080033using android::StringPiece;
34
Adam Lesinski1ab598f2015-08-14 14:26:04 -070035namespace aapt {
36
37namespace {
38
39/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -070040 * The ReferenceLinkerVisitor will follow all references and make sure they
41 * point
42 * to resources that actually exist, either in the local resource table, or as
43 * external
44 * symbols. Once the target resource has been found, the ID of the resource will
45 * be assigned
Adam Lesinski1ab598f2015-08-14 14:26:04 -070046 * to the reference object.
47 *
48 * NOTE: All of the entries in the ResourceTable must be assigned IDs.
49 */
Adam Lesinski467f1712015-11-16 17:35:44 -080050class ReferenceLinkerVisitor : public ValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070051 public:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070052 using ValueVisitor::Visit;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070053
Adam Lesinskicacb28f2016-10-19 12:18:14 -070054 ReferenceLinkerVisitor(IAaptContext* context, SymbolTable* symbols,
Adam Lesinskice5e56e2016-10-21 17:56:45 -070055 StringPool* string_pool, xml::IPackageDeclStack* decl,
56 CallSite* callsite)
57 : context_(context),
58 symbols_(symbols),
59 package_decls_(decl),
60 string_pool_(string_pool),
61 callsite_(callsite) {}
Adam Lesinskicacb28f2016-10-19 12:18:14 -070062
Adam Lesinskice5e56e2016-10-21 17:56:45 -070063 void Visit(Reference* ref) override {
64 if (!ReferenceLinker::LinkReference(ref, context_, symbols_, package_decls_,
65 callsite_)) {
66 error_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070067 }
68 }
69
70 /**
71 * We visit the Style specially because during this phase, values of
72 * attributes are
73 * all RawString values. Now that we are expected to resolve all symbols, we
74 * can
75 * lookup the attributes to find out which types are allowed for the
76 * attributes' values.
77 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078 void Visit(Style* style) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070079 if (style->parent) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070080 Visit(&style->parent.value());
Adam Lesinski1ab598f2015-08-14 14:26:04 -070081 }
82
Adam Lesinskicacb28f2016-10-19 12:18:14 -070083 for (Style::Entry& entry : style->entries) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070084 std::string err_str;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070085
Adam Lesinskicacb28f2016-10-19 12:18:14 -070086 // Transform the attribute reference so that it is using the fully
87 // qualified package
88 // name. This will also mark the reference as being able to see private
89 // resources if
90 // there was a '*' in the reference or if the package came from the
91 // private namespace.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092 Reference transformed_reference = entry.key;
93 TransformReferenceFromNamespace(package_decls_,
94 context_->GetCompilationPackage(),
95 &transformed_reference);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070096
97 // Find the attribute in the symbol table and check if it is visible from
98 // this callsite.
99 const SymbolTable::Symbol* symbol =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100 ReferenceLinker::ResolveAttributeCheckVisibility(
101 transformed_reference, context_->GetNameMangler(), symbols_,
102 callsite_, &err_str);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700103 if (symbol) {
104 // Assign our style key the correct ID.
105 // The ID may not exist.
106 entry.key.id = symbol->id;
107
108 // Try to convert the value to a more specific, typed value based on the
109 // attribute it is set to.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700110 entry.value = ParseValueWithAttribute(std::move(entry.value),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700111 symbol->attribute.get());
112
113 // Link/resolve the final value (mostly if it's a reference).
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700114 entry.value->Accept(this);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700115
116 // Now verify that the type of this item is compatible with the
117 // attribute it
118 // is defined for. We pass `nullptr` as the DiagMessage so that this
119 // check is
120 // fast and we avoid creating a DiagMessage when the match is
121 // successful.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700122 if (!symbol->attribute->Matches(entry.value.get(), nullptr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700123 // The actual type of this item is incompatible with the attribute.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700124 DiagMessage msg(entry.key.GetSource());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700125
126 // Call the matches method again, this time with a DiagMessage so we
127 // fill
128 // in the actual error message.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700129 symbol->attribute->Matches(entry.value.get(), &msg);
130 context_->GetDiagnostics()->Error(msg);
131 error_ = true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700132 }
133
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700134 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700135 DiagMessage msg(entry.key.GetSource());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700136 msg << "style attribute '";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700137 ReferenceLinker::WriteResourceName(&msg, entry.key,
138 transformed_reference);
139 msg << "' " << err_str;
140 context_->GetDiagnostics()->Error(msg);
141 error_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700142 }
143 }
144 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800145
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700146 bool HasError() { return error_; }
Adam Lesinski467f1712015-11-16 17:35:44 -0800147
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700148 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700149 DISALLOW_COPY_AND_ASSIGN(ReferenceLinkerVisitor);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700150
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700151 /**
152 * Transform a RawString value into a more specific, appropriate value, based
153 * on the
154 * Attribute. If a non RawString value is passed in, this is an identity
155 * transform.
156 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700157 std::unique_ptr<Item> ParseValueWithAttribute(std::unique_ptr<Item> value,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700158 const Attribute* attr) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700159 if (RawString* raw_string = ValueCast<RawString>(value.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700160 std::unique_ptr<Item> transformed =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700161 ResourceUtils::TryParseItemForAttribute(*raw_string->value, attr);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700162
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700163 // If we could not parse as any specific type, try a basic STRING.
164 if (!transformed &&
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700165 (attr->type_mask & android::ResTable_map::TYPE_STRING)) {
166 util::StringBuilder string_builder;
167 string_builder.Append(*raw_string->value);
168 if (string_builder) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700169 transformed = util::make_unique<String>(
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700170 string_pool_->MakeRef(string_builder.ToString()));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700171 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700172 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700173
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700174 if (transformed) {
175 return transformed;
176 }
177 };
178 return value;
179 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700180
181 IAaptContext* context_;
182 SymbolTable* symbols_;
183 xml::IPackageDeclStack* package_decls_;
184 StringPool* string_pool_;
185 CallSite* callsite_;
186 bool error_ = false;
187};
188
189class EmptyDeclStack : public xml::IPackageDeclStack {
190 public:
191 EmptyDeclStack() = default;
192
193 Maybe<xml::ExtractedPackage> TransformPackageAlias(
194 const StringPiece& alias,
195 const StringPiece& local_package) const override {
196 if (alias.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800197 return xml::ExtractedPackage{local_package.to_string(), true /* private */};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700198 }
199 return {};
200 }
201
202 private:
203 DISALLOW_COPY_AND_ASSIGN(EmptyDeclStack);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700204};
205
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700206} // namespace
Adam Lesinski467f1712015-11-16 17:35:44 -0800207
208/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700209 * The symbol is visible if it is public, or if the reference to it is
210 * requesting private access
Adam Lesinski467f1712015-11-16 17:35:44 -0800211 * or if the callsite comes from the same package.
212 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700213bool ReferenceLinker::IsSymbolVisible(const SymbolTable::Symbol& symbol,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700214 const Reference& ref,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700215 const CallSite& callsite) {
216 if (!symbol.is_public && !ref.private_reference) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700217 if (ref.name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 return callsite.resource.package == ref.name.value().package;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 } else if (ref.id && symbol.id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 return ref.id.value().package_id() == symbol.id.value().package_id();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 } else {
222 return false;
Adam Lesinski467f1712015-11-16 17:35:44 -0800223 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700224 }
225 return true;
Adam Lesinski467f1712015-11-16 17:35:44 -0800226}
227
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700228const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700229 const Reference& reference, NameMangler* mangler, SymbolTable* symbols) {
230 if (reference.name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700231 Maybe<ResourceName> mangled = mangler->MangleName(reference.name.value());
232 return symbols->FindByName(mangled ? mangled.value()
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700233 : reference.name.value());
234 } else if (reference.id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700235 return symbols->FindById(reference.id.value());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700236 } else {
237 return nullptr;
238 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800239}
240
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700241const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(
242 const Reference& reference, NameMangler* name_mangler, SymbolTable* symbols,
243 CallSite* callsite, std::string* out_error) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700244 const SymbolTable::Symbol* symbol =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700245 ResolveSymbol(reference, name_mangler, symbols);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700246 if (!symbol) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 if (out_error) *out_error = "not found";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700248 return nullptr;
249 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800250
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700251 if (!IsSymbolVisible(*symbol, reference, *callsite)) {
252 if (out_error) *out_error = "is private";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700253 return nullptr;
254 }
255 return symbol;
Adam Lesinski467f1712015-11-16 17:35:44 -0800256}
257
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700258const SymbolTable::Symbol* ReferenceLinker::ResolveAttributeCheckVisibility(
259 const Reference& reference, NameMangler* name_mangler, SymbolTable* symbols,
260 CallSite* callsite, std::string* out_error) {
261 const SymbolTable::Symbol* symbol = ResolveSymbolCheckVisibility(
262 reference, name_mangler, symbols, callsite, out_error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700263 if (!symbol) {
264 return nullptr;
265 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800266
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700267 if (!symbol->attribute) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700268 if (out_error) *out_error = "is not an attribute";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700269 return nullptr;
270 }
271 return symbol;
Adam Lesinski467f1712015-11-16 17:35:44 -0800272}
273
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700274Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(
275 const Reference& reference, NameMangler* name_mangler, SymbolTable* symbols,
276 CallSite* callsite, std::string* out_error) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700277 const SymbolTable::Symbol* symbol =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700278 ResolveSymbol(reference, name_mangler, symbols);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700279 if (!symbol) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700280 if (out_error) *out_error = "not found";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700281 return {};
282 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800283
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700284 if (!symbol->attribute) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700285 if (out_error) *out_error = "is not an attribute";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700286 return {};
287 }
288 return xml::AaptAttribute{symbol->id, *symbol->attribute};
Adam Lesinski467f1712015-11-16 17:35:44 -0800289}
290
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700291void ReferenceLinker::WriteResourceName(DiagMessage* out_msg,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700292 const Reference& orig,
Adam Lesinski28cacf02015-11-23 14:22:47 -0800293 const Reference& transformed) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700294 CHECK(out_msg != nullptr);
Adam Lesinski28cacf02015-11-23 14:22:47 -0800295
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700296 if (orig.name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700297 *out_msg << orig.name.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700298 if (transformed.name.value() != orig.name.value()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700299 *out_msg << " (aka " << transformed.name.value() << ")";
Adam Lesinski28cacf02015-11-23 14:22:47 -0800300 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700301 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700302 *out_msg << orig.id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700303 }
Adam Lesinski28cacf02015-11-23 14:22:47 -0800304}
305
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700306bool ReferenceLinker::LinkReference(Reference* reference, IAaptContext* context,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700307 SymbolTable* symbols,
308 xml::IPackageDeclStack* decls,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700309 CallSite* callsite) {
310 CHECK(reference != nullptr);
311 CHECK(reference->name || reference->id);
Adam Lesinski467f1712015-11-16 17:35:44 -0800312
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700313 Reference transformed_reference = *reference;
314 TransformReferenceFromNamespace(decls, context->GetCompilationPackage(),
315 &transformed_reference);
Adam Lesinski467f1712015-11-16 17:35:44 -0800316
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700317 std::string err_str;
318 const SymbolTable::Symbol* s = ResolveSymbolCheckVisibility(
319 transformed_reference, context->GetNameMangler(), symbols, callsite,
320 &err_str);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700321 if (s) {
322 // The ID may not exist. This is fine because of the possibility of building
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700323 // against libraries without assigned IDs.
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700324 // Ex: Linking against own resources when building a static library.
325 reference->id = s->id;
326 return true;
327 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800328
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700329 DiagMessage error_msg(reference->GetSource());
330 error_msg << "resource ";
331 WriteResourceName(&error_msg, *reference, transformed_reference);
332 error_msg << " " << err_str;
333 context->GetDiagnostics()->Error(error_msg);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700334 return false;
Adam Lesinski467f1712015-11-16 17:35:44 -0800335}
336
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700337bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) {
338 EmptyDeclStack decl_stack;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700339 bool error = false;
340 for (auto& package : table->packages) {
341 for (auto& type : package->types) {
342 for (auto& entry : type->entries) {
343 // Symbol state information may be lost if there is no value for the
344 // resource.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700345 if (entry->symbol_status.state != SymbolState::kUndefined &&
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700346 entry->values.empty()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700347 context->GetDiagnostics()->Error(
348 DiagMessage(entry->symbol_status.source)
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700349 << "no definition for declared symbol '"
350 << ResourceNameRef(package->name, type->type, entry->name)
351 << "'");
352 error = true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700353 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700354
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700355 CallSite callsite = {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700356 ResourceNameRef(package->name, type->type, entry->name)};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 ReferenceLinkerVisitor visitor(context, context->GetExternalSymbols(),
358 &table->string_pool, &decl_stack,
359 &callsite);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700360
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700361 for (auto& config_value : entry->values) {
362 config_value->value->Accept(&visitor);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700363 }
364
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700365 if (visitor.HasError()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700366 error = true;
367 }
368 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700369 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700370 }
371 return !error;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700372}
373
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700374} // namespace aapt