blob: 16c7bba33e101b66e878797dc514a84bc6e12d82 [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"
Pierre Lecesneff759e62017-02-01 00:29:25 +000020#include "LoadedApk.h"
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -070021#include "ValueVisitor.h"
Adam Lesinski458b8772016-04-25 14:20:21 -070022#include "process/IResourceTableConsumer.h"
23#include "process/SymbolTable.h"
Adam Lesinski458b8772016-04-25 14:20:21 -070024
Adam Lesinskid3ffa8442017-09-28 13:34:35 -070025using ::android::StringPiece;
Adam Lesinskid5083f62017-01-16 15:07:21 -080026
Adam Lesinski458b8772016-04-25 14:20:21 -070027namespace aapt {
28
29class DiffContext : public IAaptContext {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070030 public:
Adam Lesinskid0f492d2017-04-03 18:12:45 -070031 DiffContext() : name_mangler_({}), symbol_table_(&name_mangler_) {
32 }
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080033
Adam Lesinskib522f042017-04-21 16:57:59 -070034 PackageType GetPackageType() override {
35 // Doesn't matter.
36 return PackageType::kApp;
37 }
38
Adam Lesinskid0f492d2017-04-03 18:12:45 -070039 const std::string& GetCompilationPackage() override {
40 return empty_;
41 }
Adam Lesinski458b8772016-04-25 14:20:21 -070042
Adam Lesinskid0f492d2017-04-03 18:12:45 -070043 uint8_t GetPackageId() override {
44 return 0x0;
45 }
Adam Lesinski458b8772016-04-25 14:20:21 -070046
Adam Lesinskid0f492d2017-04-03 18:12:45 -070047 IDiagnostics* GetDiagnostics() override {
48 return &diagnostics_;
49 }
Adam Lesinski458b8772016-04-25 14:20:21 -070050
Adam Lesinskid0f492d2017-04-03 18:12:45 -070051 NameMangler* GetNameMangler() override {
52 return &name_mangler_;
53 }
Adam Lesinski458b8772016-04-25 14:20:21 -070054
Adam Lesinskid0f492d2017-04-03 18:12:45 -070055 SymbolTable* GetExternalSymbols() override {
56 return &symbol_table_;
57 }
Adam Lesinski458b8772016-04-25 14:20:21 -070058
Adam Lesinskid0f492d2017-04-03 18:12:45 -070059 bool IsVerbose() override {
60 return false;
61 }
Adam Lesinski458b8772016-04-25 14:20:21 -070062
Adam Lesinskid0f492d2017-04-03 18:12:45 -070063 int GetMinSdkVersion() override {
64 return 0;
65 }
Adam Lesinskifb6312f2016-06-28 14:40:32 -070066
Chris Warrington481f0272018-02-06 14:03:39 +000067 bool IsAutoNamespace() override {
68 return false;
69 }
70
Adam Lesinskicacb28f2016-10-19 12:18:14 -070071 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070072 std::string empty_;
73 StdErrDiagnostics diagnostics_;
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080074 NameMangler name_mangler_;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070075 SymbolTable symbol_table_;
Adam Lesinski458b8772016-04-25 14:20:21 -070076};
77
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078static void EmitDiffLine(const Source& source, const StringPiece& message) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070079 std::cerr << source << ": " << message << "\n";
Adam Lesinski458b8772016-04-25 14:20:21 -070080}
81
Adam Lesinski71be7052017-12-12 16:48:07 -080082static bool IsSymbolVisibilityDifferent(const Visibility& vis_a, const Visibility& vis_b) {
83 return vis_a.level != vis_b.level;
Adam Lesinski458b8772016-04-25 14:20:21 -070084}
85
86template <typename Id>
Adam Lesinski71be7052017-12-12 16:48:07 -080087static bool IsIdDiff(const Visibility::Level& level_a, const Maybe<Id>& id_a,
88 const Visibility::Level& level_b, const Maybe<Id>& id_b) {
89 if (level_a == Visibility::Level::kPublic || level_b == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090 return id_a != id_b;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070091 }
92 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -070093}
94
Adam Lesinskid0f492d2017-04-03 18:12:45 -070095static bool EmitResourceConfigValueDiff(IAaptContext* context, LoadedApk* apk_a,
96 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
97 ResourceEntry* entry_a, ResourceConfigValue* config_value_a,
98 LoadedApk* apk_b, ResourceTablePackage* pkg_b,
99 ResourceTableType* type_b, ResourceEntry* entry_b,
100 ResourceConfigValue* config_value_b) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700101 Value* value_a = config_value_a->value.get();
102 Value* value_b = config_value_b->value.get();
103 if (!value_a->Equals(value_b)) {
104 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700105 str_stream << "value " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
106 << " config=" << config_value_a->config << " does not match:\n";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700107 value_a->Print(&str_stream);
108 str_stream << "\n vs \n";
109 value_b->Print(&str_stream);
110 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700111 return true;
112 }
113 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700114}
115
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700116static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700117 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700118 ResourceEntry* entry_a, LoadedApk* apk_b,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700119 ResourceTablePackage* pkg_b, ResourceTableType* type_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700120 ResourceEntry* entry_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700121 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700122 for (std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700123 ResourceConfigValue* config_value_b = entry_b->FindValue(config_value_a->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700124 if (!config_value_b) {
125 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700126 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
127 << " config=" << config_value_a->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700128 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700129 diff = true;
130 } else {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700131 diff |=
132 EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a.get(),
133 apk_b, pkg_b, type_b, entry_b, config_value_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700134 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700135 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700136
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700137 // Check for any newly added config values.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700138 for (std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700139 ResourceConfigValue* config_value_a = entry_a->FindValue(config_value_b->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700140 if (!config_value_a) {
141 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700142 str_stream << "new config " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name
143 << " config=" << config_value_b->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700144 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700145 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700146 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700147 }
148 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700149}
150
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700151static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700152 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
153 LoadedApk* apk_b, ResourceTablePackage* pkg_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154 ResourceTableType* type_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700155 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 for (std::unique_ptr<ResourceEntry>& entry_a : type_a->entries) {
157 ResourceEntry* entry_b = type_b->FindEntry(entry_a->name);
158 if (!entry_b) {
159 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700160 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700161 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700162 diff = true;
163 } else {
Adam Lesinski71be7052017-12-12 16:48:07 -0800164 if (IsSymbolVisibilityDifferent(entry_a->visibility, entry_b->visibility)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700165 std::stringstream str_stream;
166 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
167 << " has different visibility (";
Adam Lesinski71be7052017-12-12 16:48:07 -0800168 if (entry_b->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700169 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700170 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700171 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700172 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700173 str_stream << " vs ";
Adam Lesinski71be7052017-12-12 16:48:07 -0800174 if (entry_a->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700175 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700176 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700177 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700178 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700179 str_stream << ")";
180 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700181 diff = true;
Adam Lesinski71be7052017-12-12 16:48:07 -0800182 } else if (IsIdDiff(entry_a->visibility.level, entry_a->id, entry_b->visibility.level,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700183 entry_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700184 std::stringstream str_stream;
185 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
186 << " has different public ID (";
187 if (entry_b->id) {
188 str_stream << "0x" << std::hex << entry_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700189 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700190 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700191 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700192 str_stream << " vs ";
193 if (entry_a->id) {
194 str_stream << "0x " << std::hex << entry_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700195 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700196 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700197 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700198 str_stream << ")";
199 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700200 diff = true;
201 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700202 diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a.get(), apk_b, pkg_b,
203 type_b, entry_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700204 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700205 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700206
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700207 // Check for any newly added entries.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700208 for (std::unique_ptr<ResourceEntry>& entry_b : type_b->entries) {
209 ResourceEntry* entry_a = type_a->FindEntry(entry_b->name);
210 if (!entry_a) {
211 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700212 str_stream << "new entry " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700213 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700214 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700215 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700216 }
217 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700218}
219
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700221 ResourceTablePackage* pkg_a, LoadedApk* apk_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700222 ResourceTablePackage* pkg_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700223 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700224 for (std::unique_ptr<ResourceTableType>& type_a : pkg_a->types) {
225 ResourceTableType* type_b = pkg_b->FindType(type_a->type);
226 if (!type_b) {
227 std::stringstream str_stream;
228 str_stream << "missing " << pkg_a->name << ":" << type_a->type;
229 EmitDiffLine(apk_a->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700230 diff = true;
231 } else {
Adam Lesinski71be7052017-12-12 16:48:07 -0800232 if (type_a->visibility_level != type_b->visibility_level) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700233 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700234 str_stream << pkg_a->name << ":" << type_a->type << " has different visibility (";
Adam Lesinski71be7052017-12-12 16:48:07 -0800235 if (type_b->visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700236 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700237 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700238 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700239 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700240 str_stream << " vs ";
Adam Lesinski71be7052017-12-12 16:48:07 -0800241 if (type_a->visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700242 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700243 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700244 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700245 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700246 str_stream << ")";
247 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700248 diff = true;
Adam Lesinski71be7052017-12-12 16:48:07 -0800249 } else if (IsIdDiff(type_a->visibility_level, type_a->id, type_b->visibility_level,
250 type_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700251 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700252 str_stream << pkg_a->name << ":" << type_a->type << " has different public ID (";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700253 if (type_b->id) {
254 str_stream << "0x" << std::hex << type_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700255 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700256 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700257 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700258 str_stream << " vs ";
259 if (type_a->id) {
260 str_stream << "0x " << std::hex << type_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700261 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700262 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700263 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700264 str_stream << ")";
265 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700266 diff = true;
267 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700268 diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a.get(), apk_b, pkg_b, type_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700269 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700270 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700271
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700272 // Check for any newly added types.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700273 for (std::unique_ptr<ResourceTableType>& type_b : pkg_b->types) {
274 ResourceTableType* type_a = pkg_a->FindType(type_b->type);
275 if (!type_a) {
276 std::stringstream str_stream;
277 str_stream << "new type " << pkg_b->name << ":" << type_b->type;
278 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700279 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700280 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700281 }
282 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700283}
284
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700285static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700286 ResourceTable* table_a = apk_a->GetResourceTable();
287 ResourceTable* table_b = apk_b->GetResourceTable();
Adam Lesinski458b8772016-04-25 14:20:21 -0700288
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700289 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700290 for (std::unique_ptr<ResourceTablePackage>& pkg_a : table_a->packages) {
291 ResourceTablePackage* pkg_b = table_b->FindPackage(pkg_a->name);
292 if (!pkg_b) {
293 std::stringstream str_stream;
294 str_stream << "missing package " << pkg_a->name;
295 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700296 diff = true;
297 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700298 if (pkg_a->id != pkg_b->id) {
299 std::stringstream str_stream;
300 str_stream << "package '" << pkg_a->name << "' has different id (";
301 if (pkg_b->id) {
302 str_stream << "0x" << std::hex << pkg_b->id.value();
Adam Lesinski458b8772016-04-25 14:20:21 -0700303 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700304 str_stream << "none";
Adam Lesinski458b8772016-04-25 14:20:21 -0700305 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700306 str_stream << " vs ";
307 if (pkg_a->id) {
308 str_stream << "0x" << std::hex << pkg_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700309 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700310 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700311 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700312 str_stream << ")";
313 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700314 diff = true;
315 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700316 diff |= EmitResourcePackageDiff(context, apk_a, pkg_a.get(), apk_b, pkg_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700317 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700318 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700319
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700320 // Check for any newly added packages.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700321 for (std::unique_ptr<ResourceTablePackage>& pkg_b : table_b->packages) {
322 ResourceTablePackage* pkg_a = table_a->FindPackage(pkg_b->name);
323 if (!pkg_a) {
324 std::stringstream str_stream;
325 str_stream << "new package " << pkg_b->name;
326 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700327 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700328 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700329 }
330 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700331}
332
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700333class ZeroingReferenceVisitor : public DescendingValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700334 public:
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700335 using DescendingValueVisitor::Visit;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700336
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700337 void Visit(Reference* ref) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700338 if (ref->name && ref->id) {
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800339 if (ref->id.value().package_id() == kAppPackageId) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700340 ref->id = {};
341 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700342 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700343 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700344};
345
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700346static void ZeroOutAppReferences(ResourceTable* table) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700347 ZeroingReferenceVisitor visitor;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700348 VisitAllValuesInTable(table, &visitor);
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700349}
350
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700351int Diff(const std::vector<StringPiece>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700352 DiffContext context;
Adam Lesinski458b8772016-04-25 14:20:21 -0700353
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700354 Flags flags;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700355 if (!flags.Parse("aapt2 diff", args, &std::cerr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700356 return 1;
357 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700358
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700359 if (flags.GetArgs().size() != 2u) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700360 std::cerr << "must have two apks as arguments.\n\n";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700361 flags.Usage("aapt2 diff", &std::cerr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700362 return 1;
363 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700364
Adam Lesinski8780eb62017-10-31 17:44:39 -0700365 IDiagnostics* diag = context.GetDiagnostics();
366 std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(flags.GetArgs()[0], diag);
367 std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(flags.GetArgs()[1], diag);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700368 if (!apk_a || !apk_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700369 return 1;
370 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700371
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700372 // Zero out Application IDs in references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700373 ZeroOutAppReferences(apk_a->GetResourceTable());
374 ZeroOutAppReferences(apk_b->GetResourceTable());
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700375
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700376 if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700377 // We emitted a diff, so return 1 (failure).
378 return 1;
379 }
380 return 0;
Adam Lesinski458b8772016-04-25 14:20:21 -0700381}
382
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700383} // namespace aapt