blob: 0bb044e8c6cb8b2cc79408e0e083653566f98e4d [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
Ryan Mitchell833a1a62018-07-10 13:51:36 -070017#include "Diff.h"
18
Adam Lesinskice5e56e2016-10-21 17:56:45 -070019#include "android-base/macros.h"
20
Pierre Lecesneff759e62017-02-01 00:29:25 +000021#include "LoadedApk.h"
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -070022#include "ValueVisitor.h"
Adam Lesinski458b8772016-04-25 14:20:21 -070023#include "process/IResourceTableConsumer.h"
24#include "process/SymbolTable.h"
Adam Lesinski458b8772016-04-25 14:20:21 -070025
Adam Lesinskid3ffa8442017-09-28 13:34:35 -070026using ::android::StringPiece;
Adam Lesinskid5083f62017-01-16 15:07:21 -080027
Adam Lesinski458b8772016-04-25 14:20:21 -070028namespace aapt {
29
30class DiffContext : public IAaptContext {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070031 public:
Adam Lesinskid0f492d2017-04-03 18:12:45 -070032 DiffContext() : name_mangler_({}), symbol_table_(&name_mangler_) {
33 }
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080034
Adam Lesinskib522f042017-04-21 16:57:59 -070035 PackageType GetPackageType() override {
36 // Doesn't matter.
37 return PackageType::kApp;
38 }
39
Adam Lesinskid0f492d2017-04-03 18:12:45 -070040 const std::string& GetCompilationPackage() override {
41 return empty_;
42 }
Adam Lesinski458b8772016-04-25 14:20:21 -070043
Adam Lesinskid0f492d2017-04-03 18:12:45 -070044 uint8_t GetPackageId() override {
45 return 0x0;
46 }
Adam Lesinski458b8772016-04-25 14:20:21 -070047
Adam Lesinskid0f492d2017-04-03 18:12:45 -070048 IDiagnostics* GetDiagnostics() override {
49 return &diagnostics_;
50 }
Adam Lesinski458b8772016-04-25 14:20:21 -070051
Adam Lesinskid0f492d2017-04-03 18:12:45 -070052 NameMangler* GetNameMangler() override {
53 return &name_mangler_;
54 }
Adam Lesinski458b8772016-04-25 14:20:21 -070055
Adam Lesinskid0f492d2017-04-03 18:12:45 -070056 SymbolTable* GetExternalSymbols() override {
57 return &symbol_table_;
58 }
Adam Lesinski458b8772016-04-25 14:20:21 -070059
Adam Lesinskid0f492d2017-04-03 18:12:45 -070060 bool IsVerbose() override {
61 return false;
62 }
Adam Lesinski458b8772016-04-25 14:20:21 -070063
Adam Lesinskid0f492d2017-04-03 18:12:45 -070064 int GetMinSdkVersion() override {
65 return 0;
66 }
Adam Lesinskifb6312f2016-06-28 14:40:32 -070067
Udam Sainib228df32019-06-18 16:50:34 -070068 const std::set<std::string>& GetSplitNameDependencies() override {
69 UNIMPLEMENTED(FATAL) << "Split Name Dependencies should not be necessary";
70 static std::set<std::string> empty;
71 return empty;
72 }
73
Adam Lesinskicacb28f2016-10-19 12:18:14 -070074 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070075 std::string empty_;
76 StdErrDiagnostics diagnostics_;
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080077 NameMangler name_mangler_;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078 SymbolTable symbol_table_;
Adam Lesinski458b8772016-04-25 14:20:21 -070079};
80
Adam Lesinskice5e56e2016-10-21 17:56:45 -070081static void EmitDiffLine(const Source& source, const StringPiece& message) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070082 std::cerr << source << ": " << message << "\n";
Adam Lesinski458b8772016-04-25 14:20:21 -070083}
84
Adam Lesinski71be7052017-12-12 16:48:07 -080085static bool IsSymbolVisibilityDifferent(const Visibility& vis_a, const Visibility& vis_b) {
86 return vis_a.level != vis_b.level;
Adam Lesinski458b8772016-04-25 14:20:21 -070087}
88
89template <typename Id>
Adam Lesinski71be7052017-12-12 16:48:07 -080090static bool IsIdDiff(const Visibility::Level& level_a, const Maybe<Id>& id_a,
91 const Visibility::Level& level_b, const Maybe<Id>& id_b) {
92 if (level_a == Visibility::Level::kPublic || level_b == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070093 return id_a != id_b;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094 }
95 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -070096}
97
Ryan Mitchell9634efb2021-03-19 14:53:17 -070098static bool EmitResourceConfigValueDiff(
99 IAaptContext* context, LoadedApk* apk_a, const ResourceTablePackageView& pkg_a,
100 const ResourceTableTypeView& type_a, const ResourceEntry* entry_a,
101 const ResourceConfigValue* config_value_a, LoadedApk* apk_b,
102 const ResourceTablePackageView& pkg_b, const ResourceTableTypeView& type_b,
103 const ResourceEntry* entry_b, const ResourceConfigValue* config_value_b) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700104 Value* value_a = config_value_a->value.get();
105 Value* value_b = config_value_b->value.get();
106 if (!value_a->Equals(value_b)) {
107 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700108 str_stream << "value " << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700109 << " config=" << config_value_a->config << " does not match:\n";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700110 value_a->Print(&str_stream);
111 str_stream << "\n vs \n";
112 value_b->Print(&str_stream);
113 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700114 return true;
115 }
116 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700117}
118
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700119static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700120 const ResourceTablePackageView& pkg_a,
121 const ResourceTableTypeView& type_a, const ResourceEntry* entry_a,
122 LoadedApk* apk_b, const ResourceTablePackageView& pkg_b,
123 const ResourceTableTypeView& type_b,
124 const ResourceEntry* entry_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700125 bool diff = false;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700126 for (const std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) {
127 auto config_value_b = entry_b->FindValue(config_value_a->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700128 if (!config_value_b) {
129 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700130 str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700131 << " config=" << config_value_a->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700132 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700133 diff = true;
134 } else {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700135 diff |=
136 EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a.get(),
137 apk_b, pkg_b, type_b, entry_b, config_value_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700138 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700139 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700140
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700141 // Check for any newly added config values.
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700142 for (const std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) {
143 auto config_value_a = entry_a->FindValue(config_value_b->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700144 if (!config_value_a) {
145 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700146 str_stream << "new config " << pkg_b.name << ":" << type_b.type << "/" << entry_b->name
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700147 << " config=" << config_value_b->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700148 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700149 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700150 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700151 }
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700152 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700153}
154
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700155static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700156 const ResourceTablePackageView& pkg_a,
157 const ResourceTableTypeView& type_a, LoadedApk* apk_b,
158 const ResourceTablePackageView& pkg_b,
159 const ResourceTableTypeView& type_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700160 bool diff = false;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700161 auto entry_a_iter = type_a.entries.begin();
162 auto entry_b_iter = type_b.entries.begin();
163 while (entry_a_iter != type_a.entries.end() || entry_b_iter != type_b.entries.end()) {
164 if (entry_b_iter == type_b.entries.end()) {
165 // Type A contains a type that type B does not have.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700166 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700167 str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << (*entry_a_iter)->name;
168 EmitDiffLine(apk_a->GetSource(), str_stream.str());
169 diff = true;
170 } else if (entry_a_iter == type_a.entries.end()) {
171 // Type B contains a type that type A does not have.
172 std::stringstream str_stream;
173 str_stream << "new entry " << pkg_b.name << ":" << type_b.type << "/"
174 << (*entry_b_iter)->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700175 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700176 diff = true;
177 } else {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700178 const auto& entry_a = *entry_a_iter;
179 const auto& entry_b = *entry_a_iter;
Adam Lesinski71be7052017-12-12 16:48:07 -0800180 if (IsSymbolVisibilityDifferent(entry_a->visibility, entry_b->visibility)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700181 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700182 str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700183 << " has different visibility (";
Adam Lesinski71be7052017-12-12 16:48:07 -0800184 if (entry_b->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700185 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700186 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700187 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700188 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700189 str_stream << " vs ";
Adam Lesinski71be7052017-12-12 16:48:07 -0800190 if (entry_a->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700191 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700192 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700193 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700194 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700195 str_stream << ")";
196 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700197 diff = true;
Adam Lesinski71be7052017-12-12 16:48:07 -0800198 } else if (IsIdDiff(entry_a->visibility.level, entry_a->id, entry_b->visibility.level,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700199 entry_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700200 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700201 str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700202 << " has different public ID (";
203 if (entry_b->id) {
204 str_stream << "0x" << std::hex << entry_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700205 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700206 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700207 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700208 str_stream << " vs ";
209 if (entry_a->id) {
210 str_stream << "0x " << std::hex << entry_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700211 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700212 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700213 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700214 str_stream << ")";
215 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700216 diff = true;
217 }
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700218 diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a, apk_b, pkg_b, type_b,
219 entry_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700220 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 }
222 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700223}
224
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700225static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700226 const ResourceTablePackageView& pkg_a, LoadedApk* apk_b,
227 const ResourceTablePackageView& pkg_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700228 bool diff = false;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700229 auto type_a_iter = pkg_a.types.begin();
230 auto type_b_iter = pkg_b.types.begin();
231 while (type_a_iter != pkg_a.types.end() || type_b_iter != pkg_b.types.end()) {
232 if (type_b_iter == pkg_b.types.end()) {
233 // Type A contains a type that type B does not have.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700234 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700235 str_stream << "missing " << pkg_a.name << ":" << type_a_iter->type;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700236 EmitDiffLine(apk_a->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700237 diff = true;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700238 } else if (type_a_iter == pkg_a.types.end()) {
239 // Type B contains a type that type A does not have.
240 std::stringstream str_stream;
241 str_stream << "new type " << pkg_b.name << ":" << type_b_iter->type;
242 EmitDiffLine(apk_b->GetSource(), str_stream.str());
243 diff = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700244 } else {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700245 if (type_a_iter->visibility_level != type_b_iter->visibility_level) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700246 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700247 str_stream << pkg_a.name << ":" << type_a_iter->type << " has different visibility (";
248 if (type_b_iter->visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700249 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700250 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700251 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700252 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700253 str_stream << " vs ";
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700254 if (type_a_iter->visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700255 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700256 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700257 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700258 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700259 str_stream << ")";
260 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700261 diff = true;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700262 } else if (IsIdDiff(type_a_iter->visibility_level, type_a_iter->id,
263 type_b_iter->visibility_level, type_b_iter->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700264 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700265 str_stream << pkg_a.name << ":" << type_a_iter->type << " has different public ID (";
266 if (type_b_iter->id) {
267 str_stream << "0x" << std::hex << type_b_iter->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700268 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700269 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700270 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 str_stream << " vs ";
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700272 if (type_a_iter->id) {
273 str_stream << "0x " << std::hex << type_a_iter->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700274 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700275 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700276 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700277 str_stream << ")";
278 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700279 diff = true;
280 }
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700281 diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, *type_a_iter, apk_b, pkg_b, *type_b_iter);
Adam Lesinski458b8772016-04-25 14:20:21 -0700282 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700283 }
284 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700285}
286
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700287static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700288 const auto table_a = apk_a->GetResourceTable()->GetPartitionedView();
289 const auto table_b = apk_b->GetResourceTable()->GetPartitionedView();
Adam Lesinski458b8772016-04-25 14:20:21 -0700290
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700291 bool diff = false;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700292 auto package_a_iter = table_a.packages.begin();
293 auto package_b_iter = table_b.packages.begin();
294 while (package_a_iter != table_a.packages.end() || package_b_iter != table_b.packages.end()) {
295 if (package_b_iter == table_b.packages.end()) {
296 // Table A contains a package that table B does not have.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700297 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700298 str_stream << "missing package " << package_a_iter->name;
299 EmitDiffLine(apk_a->GetSource(), str_stream.str());
300 diff = true;
301 } else if (package_a_iter == table_a.packages.end()) {
302 // Table B contains a package that table A does not have.
303 std::stringstream str_stream;
304 str_stream << "new package " << package_b_iter->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700305 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700306 diff = true;
307 } else {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700308 if (package_a_iter->id != package_b_iter->id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700309 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700310 str_stream << "package '" << package_a_iter->name << "' has different id (";
311 if (package_b_iter->id) {
312 str_stream << "0x" << std::hex << package_b_iter->id.value();
Adam Lesinski458b8772016-04-25 14:20:21 -0700313 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700314 str_stream << "none";
Adam Lesinski458b8772016-04-25 14:20:21 -0700315 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700316 str_stream << " vs ";
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700317 if (package_a_iter->id) {
318 str_stream << "0x" << std::hex << package_b_iter->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700319 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700320 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700321 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700322 str_stream << ")";
323 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700324 diff = true;
325 }
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700326 diff |= EmitResourcePackageDiff(context, apk_a, *package_a_iter, apk_b, *package_b_iter);
Adam Lesinski458b8772016-04-25 14:20:21 -0700327 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700328 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700329
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700330 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
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700351int DiffCommand::Action(const std::vector<std::string>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700352 DiffContext context;
Adam Lesinski458b8772016-04-25 14:20:21 -0700353
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700354 if (args.size() != 2u) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700355 std::cerr << "must have two apks as arguments.\n\n";
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700356 Usage(&std::cerr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700357 return 1;
358 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700359
Adam Lesinski8780eb62017-10-31 17:44:39 -0700360 IDiagnostics* diag = context.GetDiagnostics();
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700361 std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(args[0], diag);
362 std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(args[1], diag);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700363 if (!apk_a || !apk_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700364 return 1;
365 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700366
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700367 // Zero out Application IDs in references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700368 ZeroOutAppReferences(apk_a->GetResourceTable());
369 ZeroOutAppReferences(apk_b->GetResourceTable());
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700370
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700371 if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700372 // We emitted a diff, so return 1 (failure).
373 return 1;
374 }
375 return 0;
Adam Lesinski458b8772016-04-25 14:20:21 -0700376}
377
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700378} // namespace aapt