1/*
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#ifndef AAPT_PROCESS_SYMBOLTABLE_H
18#define AAPT_PROCESS_SYMBOLTABLE_H
19
20#include <algorithm>
21#include <memory>
22#include <vector>
23
24#include "android-base/macros.h"
25#include "androidfw/AssetManager.h"
26#include "utils/JenkinsHash.h"
27#include "utils/LruCache.h"
28
29#include "Resource.h"
30#include "ResourceTable.h"
31#include "ResourceValues.h"
32#include "util/Util.h"
33
34namespace aapt {
35
36inline android::hash_t hash_type(const ResourceName& name) {
37  std::hash<std::string> str_hash;
38  android::hash_t hash = 0;
39  hash = android::JenkinsHashMix(hash, (uint32_t)str_hash(name.package));
40  hash = android::JenkinsHashMix(hash, (uint32_t)name.type);
41  hash = android::JenkinsHashMix(hash, (uint32_t)str_hash(name.entry));
42  return hash;
43}
44
45inline android::hash_t hash_type(const ResourceId& id) {
46  return android::hash_type(id.id);
47}
48
49class ISymbolSource;
50class ISymbolTableDelegate;
51class NameMangler;
52
53class SymbolTable {
54 public:
55  struct Symbol {
56    Symbol() = default;
57
58    explicit Symbol(const Maybe<ResourceId>& i, const std::shared_ptr<Attribute>& attr = {},
59                    bool pub = false)
60        : id(i), attribute(attr), is_public(pub) {
61    }
62
63    Symbol(const Symbol&) = default;
64    Symbol(Symbol&&) = default;
65    Symbol& operator=(const Symbol&) = default;
66    Symbol& operator=(Symbol&&) = default;
67
68    Maybe<ResourceId> id;
69    std::shared_ptr<Attribute> attribute;
70    bool is_public = false;
71  };
72
73  SymbolTable(NameMangler* mangler);
74
75  // Overrides the default ISymbolTableDelegate, which allows a custom defined strategy for
76  // looking up resources from a set of sources.
77  void SetDelegate(std::unique_ptr<ISymbolTableDelegate> delegate);
78
79  // Appends a symbol source. The cache is not cleared since entries that
80  // have already been found would take precedence due to ordering.
81  void AppendSource(std::unique_ptr<ISymbolSource> source);
82
83  // Prepends a symbol source so that its symbols take precedence. This will
84  // cause the existing cache to be cleared.
85  void PrependSource(std::unique_ptr<ISymbolSource> source);
86
87  // NOTE: Never hold on to the result between calls to FindByXXX. The
88  // results are stored in a cache which may evict entries on subsequent calls.
89  const Symbol* FindByName(const ResourceName& name);
90
91  // NOTE: Never hold on to the result between calls to FindByXXX. The
92  // results are stored in a cache which may evict entries on subsequent calls.
93  const Symbol* FindById(const ResourceId& id);
94
95  // Let's the ISymbolSource decide whether looking up by name or ID is faster,
96  // if both are available.
97  // NOTE: Never hold on to the result between calls to FindByXXX. The
98  // results are stored in a cache which may evict entries on subsequent calls.
99  const Symbol* FindByReference(const Reference& ref);
100
101 private:
102  NameMangler* mangler_;
103  std::unique_ptr<ISymbolTableDelegate> delegate_;
104  std::vector<std::unique_ptr<ISymbolSource>> sources_;
105
106  // We use shared_ptr because unique_ptr is not supported and
107  // we need automatic deletion.
108  android::LruCache<ResourceName, std::shared_ptr<Symbol>> cache_;
109  android::LruCache<ResourceId, std::shared_ptr<Symbol>> id_cache_;
110
111  DISALLOW_COPY_AND_ASSIGN(SymbolTable);
112};
113
114// Allows the customization of the lookup strategy/order of a symbol from a set of
115// symbol sources.
116class ISymbolTableDelegate {
117 public:
118  ISymbolTableDelegate() = default;
119  virtual ~ISymbolTableDelegate() = default;
120
121  // The name is already mangled and does not need further processing.
122  virtual std::unique_ptr<SymbolTable::Symbol> FindByName(
123      const ResourceName& name, const std::vector<std::unique_ptr<ISymbolSource>>& sources) = 0;
124
125  virtual std::unique_ptr<SymbolTable::Symbol> FindById(
126      ResourceId id, const std::vector<std::unique_ptr<ISymbolSource>>& sources) = 0;
127
128 private:
129  DISALLOW_COPY_AND_ASSIGN(ISymbolTableDelegate);
130};
131
132class DefaultSymbolTableDelegate : public ISymbolTableDelegate {
133 public:
134  DefaultSymbolTableDelegate() = default;
135  virtual ~DefaultSymbolTableDelegate() = default;
136
137  virtual std::unique_ptr<SymbolTable::Symbol> FindByName(
138      const ResourceName& name,
139      const std::vector<std::unique_ptr<ISymbolSource>>& sources) override;
140  virtual std::unique_ptr<SymbolTable::Symbol> FindById(
141      ResourceId id, const std::vector<std::unique_ptr<ISymbolSource>>& sources) override;
142
143 private:
144  DISALLOW_COPY_AND_ASSIGN(DefaultSymbolTableDelegate);
145};
146
147// An interface that a symbol source implements in order to surface symbol information
148// to the symbol table.
149class ISymbolSource {
150 public:
151  virtual ~ISymbolSource() = default;
152
153  virtual std::unique_ptr<SymbolTable::Symbol> FindByName(
154      const ResourceName& name) = 0;
155  virtual std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) = 0;
156
157  // Default implementation tries the name if it exists, else the ID.
158  virtual std::unique_ptr<SymbolTable::Symbol> FindByReference(
159      const Reference& ref) {
160    if (ref.name) {
161      return FindByName(ref.name.value());
162    } else if (ref.id) {
163      return FindById(ref.id.value());
164    }
165    return {};
166  }
167};
168
169// Exposes the resources in a ResourceTable as symbols for SymbolTable.
170// Instances of this class must outlive the encompassed ResourceTable.
171// Lookups by ID are ignored.
172class ResourceTableSymbolSource : public ISymbolSource {
173 public:
174  explicit ResourceTableSymbolSource(ResourceTable* table) : table_(table) {}
175
176  std::unique_ptr<SymbolTable::Symbol> FindByName(
177      const ResourceName& name) override;
178
179  std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) override {
180    return {};
181  }
182
183 private:
184  ResourceTable* table_;
185
186  DISALLOW_COPY_AND_ASSIGN(ResourceTableSymbolSource);
187};
188
189class AssetManagerSymbolSource : public ISymbolSource {
190 public:
191  AssetManagerSymbolSource() = default;
192
193  bool AddAssetPath(const android::StringPiece& path);
194  std::map<size_t, std::string> GetAssignedPackageIds() const;
195
196  std::unique_ptr<SymbolTable::Symbol> FindByName(
197      const ResourceName& name) override;
198  std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) override;
199  std::unique_ptr<SymbolTable::Symbol> FindByReference(
200      const Reference& ref) override;
201
202 private:
203  android::AssetManager assets_;
204
205  DISALLOW_COPY_AND_ASSIGN(AssetManagerSymbolSource);
206};
207
208}  // namespace aapt
209
210#endif /* AAPT_PROCESS_SYMBOLTABLE_H */
211