blob: 593e7ab119f16267298b66442176e4c3fbc6ba32 [file] [log] [blame]
Adam Lesinski458b8772016-04-25 14:20:21 -07001/*
2 * Copyright (C) 2016 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 "android-base/macros.h"
18
Adam Lesinski458b8772016-04-25 14:20:21 -070019#include "Flags.h"
20#include "ResourceTable.h"
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -070021#include "ValueVisitor.h"
Adam Lesinski458b8772016-04-25 14:20:21 -070022#include "io/ZipArchive.h"
23#include "process/IResourceTableConsumer.h"
24#include "process/SymbolTable.h"
25#include "unflatten/BinaryResourceParser.h"
26
Adam Lesinski458b8772016-04-25 14:20:21 -070027namespace aapt {
28
29class DiffContext : public IAaptContext {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070030 public:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070031 const std::string& GetCompilationPackage() override { return empty_; }
Adam Lesinski458b8772016-04-25 14:20:21 -070032
Adam Lesinskice5e56e2016-10-21 17:56:45 -070033 uint8_t GetPackageId() override { return 0x0; }
Adam Lesinski458b8772016-04-25 14:20:21 -070034
Adam Lesinskice5e56e2016-10-21 17:56:45 -070035 IDiagnostics* GetDiagnostics() override { return &diagnostics_; }
Adam Lesinski458b8772016-04-25 14:20:21 -070036
Adam Lesinskice5e56e2016-10-21 17:56:45 -070037 NameMangler* GetNameMangler() override { return &name_mangler_; }
Adam Lesinski458b8772016-04-25 14:20:21 -070038
Adam Lesinskice5e56e2016-10-21 17:56:45 -070039 SymbolTable* GetExternalSymbols() override { return &symbol_table_; }
Adam Lesinski458b8772016-04-25 14:20:21 -070040
Adam Lesinskice5e56e2016-10-21 17:56:45 -070041 bool IsVerbose() override { return false; }
Adam Lesinski458b8772016-04-25 14:20:21 -070042
Adam Lesinskice5e56e2016-10-21 17:56:45 -070043 int GetMinSdkVersion() override { return 0; }
Adam Lesinskifb6312f2016-06-28 14:40:32 -070044
Adam Lesinskicacb28f2016-10-19 12:18:14 -070045 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070046 std::string empty_;
47 StdErrDiagnostics diagnostics_;
48 NameMangler name_mangler_ = NameMangler(NameManglerPolicy{});
49 SymbolTable symbol_table_;
Adam Lesinski458b8772016-04-25 14:20:21 -070050};
51
52class LoadedApk {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070053 public:
54 LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
55 std::unique_ptr<ResourceTable> table)
Adam Lesinskice5e56e2016-10-21 17:56:45 -070056 : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
Adam Lesinski458b8772016-04-25 14:20:21 -070057
Adam Lesinskice5e56e2016-10-21 17:56:45 -070058 io::IFileCollection* GetFileCollection() { return apk_.get(); }
Adam Lesinski458b8772016-04-25 14:20:21 -070059
Adam Lesinskice5e56e2016-10-21 17:56:45 -070060 ResourceTable* GetResourceTable() { return table_.get(); }
Adam Lesinski458b8772016-04-25 14:20:21 -070061
Adam Lesinskice5e56e2016-10-21 17:56:45 -070062 const Source& GetSource() { return source_; }
Adam Lesinski458b8772016-04-25 14:20:21 -070063
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070065 Source source_;
66 std::unique_ptr<io::IFileCollection> apk_;
67 std::unique_ptr<ResourceTable> table_;
Adam Lesinski458b8772016-04-25 14:20:21 -070068
Adam Lesinskicacb28f2016-10-19 12:18:14 -070069 DISALLOW_COPY_AND_ASSIGN(LoadedApk);
Adam Lesinski458b8772016-04-25 14:20:21 -070070};
71
Adam Lesinskice5e56e2016-10-21 17:56:45 -070072static std::unique_ptr<LoadedApk> LoadApkFromPath(IAaptContext* context,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 const StringPiece& path) {
74 Source source(path);
75 std::string error;
76 std::unique_ptr<io::ZipFileCollection> apk =
Adam Lesinskice5e56e2016-10-21 17:56:45 -070077 io::ZipFileCollection::Create(path, &error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070078 if (!apk) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070079 context->GetDiagnostics()->Error(DiagMessage(source) << error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070080 return {};
81 }
Adam Lesinski458b8772016-04-25 14:20:21 -070082
Adam Lesinskice5e56e2016-10-21 17:56:45 -070083 io::IFile* file = apk->FindFile("resources.arsc");
Adam Lesinskicacb28f2016-10-19 12:18:14 -070084 if (!file) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070085 context->GetDiagnostics()->Error(DiagMessage(source)
Adam Lesinskicacb28f2016-10-19 12:18:14 -070086 << "no resources.arsc found");
87 return {};
88 }
Adam Lesinski458b8772016-04-25 14:20:21 -070089
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090 std::unique_ptr<io::IData> data = file->OpenAsData();
Adam Lesinskicacb28f2016-10-19 12:18:14 -070091 if (!data) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092 context->GetDiagnostics()->Error(DiagMessage(source)
Adam Lesinskicacb28f2016-10-19 12:18:14 -070093 << "could not open resources.arsc");
94 return {};
95 }
Adam Lesinski458b8772016-04-25 14:20:21 -070096
Adam Lesinskicacb28f2016-10-19 12:18:14 -070097 std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
98 BinaryResourceParser parser(context, table.get(), source, data->data(),
99 data->size());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100 if (!parser.Parse()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700101 return {};
102 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700103
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700104 return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
Adam Lesinski458b8772016-04-25 14:20:21 -0700105}
106
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700107static void EmitDiffLine(const Source& source, const StringPiece& message) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700108 std::cerr << source << ": " << message << "\n";
Adam Lesinski458b8772016-04-25 14:20:21 -0700109}
110
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700111static bool IsSymbolVisibilityDifferent(const Symbol& symbol_a,
112 const Symbol& symbol_b) {
113 return symbol_a.state != symbol_b.state;
Adam Lesinski458b8772016-04-25 14:20:21 -0700114}
115
116template <typename Id>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700117static bool IsIdDiff(const Symbol& symbol_a, const Maybe<Id>& id_a,
118 const Symbol& symbol_b, const Maybe<Id>& id_b) {
119 if (symbol_a.state == SymbolState::kPublic ||
120 symbol_b.state == SymbolState::kPublic) {
121 return id_a != id_b;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700122 }
123 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700124}
125
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700126static bool EmitResourceConfigValueDiff(
127 IAaptContext* context, LoadedApk* apk_a, ResourceTablePackage* pkg_a,
128 ResourceTableType* type_a, ResourceEntry* entry_a,
129 ResourceConfigValue* config_value_a, LoadedApk* apk_b,
130 ResourceTablePackage* pkg_b, ResourceTableType* type_b,
131 ResourceEntry* entry_b, ResourceConfigValue* config_value_b) {
132 Value* value_a = config_value_a->value.get();
133 Value* value_b = config_value_b->value.get();
134 if (!value_a->Equals(value_b)) {
135 std::stringstream str_stream;
136 str_stream << "value " << pkg_a->name << ":" << type_a->type << "/"
137 << entry_a->name << " config=" << config_value_a->config
138 << " does not match:\n";
139 value_a->Print(&str_stream);
140 str_stream << "\n vs \n";
141 value_b->Print(&str_stream);
142 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143 return true;
144 }
145 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700146}
147
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700148static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
149 ResourceTablePackage* pkg_a,
150 ResourceTableType* type_a,
151 ResourceEntry* entry_a, LoadedApk* apk_b,
152 ResourceTablePackage* pkg_b,
153 ResourceTableType* type_b,
154 ResourceEntry* entry_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700155 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 for (std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) {
157 ResourceConfigValue* config_value_b =
158 entry_b->FindValue(config_value_a->config);
159 if (!config_value_b) {
160 std::stringstream str_stream;
161 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/"
162 << entry_a->name << " config=" << config_value_a->config;
163 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700164 diff = true;
165 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700166 diff |= EmitResourceConfigValueDiff(
167 context, apk_a, pkg_a, type_a, entry_a, config_value_a.get(), apk_b,
168 pkg_b, type_b, entry_b, config_value_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700169 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700170 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700171
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700172 // Check for any newly added config values.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700173 for (std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) {
174 ResourceConfigValue* config_value_a =
175 entry_a->FindValue(config_value_b->config);
176 if (!config_value_a) {
177 std::stringstream str_stream;
178 str_stream << "new config " << pkg_b->name << ":" << type_b->type << "/"
179 << entry_b->name << " config=" << config_value_b->config;
180 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700181 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700182 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 }
184 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700185}
186
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700187static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
188 ResourceTablePackage* pkg_a,
189 ResourceTableType* type_a, LoadedApk* apk_b,
190 ResourceTablePackage* pkg_b,
191 ResourceTableType* type_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700192 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700193 for (std::unique_ptr<ResourceEntry>& entry_a : type_a->entries) {
194 ResourceEntry* entry_b = type_b->FindEntry(entry_a->name);
195 if (!entry_b) {
196 std::stringstream str_stream;
197 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/"
198 << entry_a->name;
199 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700200 diff = true;
201 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700202 if (IsSymbolVisibilityDifferent(entry_a->symbol_status,
203 entry_b->symbol_status)) {
204 std::stringstream str_stream;
205 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
206 << " has different visibility (";
207 if (entry_b->symbol_status.state == SymbolState::kPublic) {
208 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700209 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700210 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700211 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700212 str_stream << " vs ";
213 if (entry_a->symbol_status.state == SymbolState::kPublic) {
214 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700215 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700216 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700217 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 str_stream << ")";
219 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700220 diff = true;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700221 } else if (IsIdDiff(entry_a->symbol_status, entry_a->id,
222 entry_b->symbol_status, entry_b->id)) {
223 std::stringstream str_stream;
224 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
225 << " has different public ID (";
226 if (entry_b->id) {
227 str_stream << "0x" << std::hex << entry_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700228 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700229 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700230 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700231 str_stream << " vs ";
232 if (entry_a->id) {
233 str_stream << "0x " << std::hex << entry_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700234 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700235 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700236 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700237 str_stream << ")";
238 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700239 diff = true;
240 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700241 diff |=
242 EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a.get(),
243 apk_b, pkg_b, type_b, entry_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700244 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700245 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700246
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700247 // Check for any newly added entries.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700248 for (std::unique_ptr<ResourceEntry>& entry_b : type_b->entries) {
249 ResourceEntry* entry_a = type_a->FindEntry(entry_b->name);
250 if (!entry_a) {
251 std::stringstream str_stream;
252 str_stream << "new entry " << pkg_b->name << ":" << type_b->type << "/"
253 << entry_b->name;
254 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700255 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700256 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700257 }
258 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700259}
260
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700261static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
262 ResourceTablePackage* pkg_a,
263 LoadedApk* apk_b,
264 ResourceTablePackage* pkg_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700265 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700266 for (std::unique_ptr<ResourceTableType>& type_a : pkg_a->types) {
267 ResourceTableType* type_b = pkg_b->FindType(type_a->type);
268 if (!type_b) {
269 std::stringstream str_stream;
270 str_stream << "missing " << pkg_a->name << ":" << type_a->type;
271 EmitDiffLine(apk_a->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700272 diff = true;
273 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700274 if (IsSymbolVisibilityDifferent(type_a->symbol_status,
275 type_b->symbol_status)) {
276 std::stringstream str_stream;
277 str_stream << pkg_a->name << ":" << type_a->type
278 << " has different visibility (";
279 if (type_b->symbol_status.state == SymbolState::kPublic) {
280 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700281 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700282 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700283 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700284 str_stream << " vs ";
285 if (type_a->symbol_status.state == SymbolState::kPublic) {
286 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700287 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700288 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700289 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700290 str_stream << ")";
291 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700292 diff = true;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700293 } else if (IsIdDiff(type_a->symbol_status, type_a->id,
294 type_b->symbol_status, type_b->id)) {
295 std::stringstream str_stream;
296 str_stream << pkg_a->name << ":" << type_a->type
297 << " has different public ID (";
298 if (type_b->id) {
299 str_stream << "0x" << std::hex << type_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700300 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700301 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700302 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700303 str_stream << " vs ";
304 if (type_a->id) {
305 str_stream << "0x " << std::hex << type_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700306 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700307 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700308 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700309 str_stream << ")";
310 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700311 diff = true;
312 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700313 diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a.get(), apk_b,
314 pkg_b, type_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700315 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700316 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700317
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700318 // Check for any newly added types.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700319 for (std::unique_ptr<ResourceTableType>& type_b : pkg_b->types) {
320 ResourceTableType* type_a = pkg_a->FindType(type_b->type);
321 if (!type_a) {
322 std::stringstream str_stream;
323 str_stream << "new type " << pkg_b->name << ":" << type_b->type;
324 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700325 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700326 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700327 }
328 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700329}
330
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700331static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a,
332 LoadedApk* apk_b) {
333 ResourceTable* table_a = apk_a->GetResourceTable();
334 ResourceTable* table_b = apk_b->GetResourceTable();
Adam Lesinski458b8772016-04-25 14:20:21 -0700335
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700336 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700337 for (std::unique_ptr<ResourceTablePackage>& pkg_a : table_a->packages) {
338 ResourceTablePackage* pkg_b = table_b->FindPackage(pkg_a->name);
339 if (!pkg_b) {
340 std::stringstream str_stream;
341 str_stream << "missing package " << pkg_a->name;
342 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700343 diff = true;
344 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700345 if (pkg_a->id != pkg_b->id) {
346 std::stringstream str_stream;
347 str_stream << "package '" << pkg_a->name << "' has different id (";
348 if (pkg_b->id) {
349 str_stream << "0x" << std::hex << pkg_b->id.value();
Adam Lesinski458b8772016-04-25 14:20:21 -0700350 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700351 str_stream << "none";
Adam Lesinski458b8772016-04-25 14:20:21 -0700352 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700353 str_stream << " vs ";
354 if (pkg_a->id) {
355 str_stream << "0x" << std::hex << pkg_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700356 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700358 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700359 str_stream << ")";
360 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700361 diff = true;
362 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700363 diff |=
364 EmitResourcePackageDiff(context, apk_a, pkg_a.get(), apk_b, pkg_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700365 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700366 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700367
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700368 // Check for any newly added packages.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700369 for (std::unique_ptr<ResourceTablePackage>& pkg_b : table_b->packages) {
370 ResourceTablePackage* pkg_a = table_a->FindPackage(pkg_b->name);
371 if (!pkg_a) {
372 std::stringstream str_stream;
373 str_stream << "new package " << pkg_b->name;
374 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700375 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700376 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700377 }
378 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700379}
380
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700381class ZeroingReferenceVisitor : public ValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700382 public:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700383 using ValueVisitor::Visit;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700384
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700385 void Visit(Reference* ref) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700386 if (ref->name && ref->id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700387 if (ref->id.value().package_id() == 0x7f) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700388 ref->id = {};
389 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700390 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700391 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700392};
393
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700394static void ZeroOutAppReferences(ResourceTable* table) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700395 ZeroingReferenceVisitor visitor;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700396 VisitAllValuesInTable(table, &visitor);
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700397}
398
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700399int Diff(const std::vector<StringPiece>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700400 DiffContext context;
Adam Lesinski458b8772016-04-25 14:20:21 -0700401
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700402 Flags flags;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700403 if (!flags.Parse("aapt2 diff", args, &std::cerr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700404 return 1;
405 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700406
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700407 if (flags.GetArgs().size() != 2u) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700408 std::cerr << "must have two apks as arguments.\n\n";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700409 flags.Usage("aapt2 diff", &std::cerr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700410 return 1;
411 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700412
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700413 std::unique_ptr<LoadedApk> apk_a =
414 LoadApkFromPath(&context, flags.GetArgs()[0]);
415 std::unique_ptr<LoadedApk> apk_b =
416 LoadApkFromPath(&context, flags.GetArgs()[1]);
417 if (!apk_a || !apk_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700418 return 1;
419 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700420
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700421 // Zero out Application IDs in references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700422 ZeroOutAppReferences(apk_a->GetResourceTable());
423 ZeroOutAppReferences(apk_b->GetResourceTable());
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700424
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700425 if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700426 // We emitted a diff, so return 1 (failure).
427 return 1;
428 }
429 return 0;
Adam Lesinski458b8772016-04-25 14:20:21 -0700430}
431
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700432} // namespace aapt