blob: df31087c50784d47b2f8645073c488aa453dc6cd [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) {
Ryan Mitchell1499f502021-03-30 12:20:08 -070086 return vis_a.level != vis_b.level || vis_a.staged_api != vis_b.staged_api;
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;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700179 const auto& entry_b = *entry_b_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 (";
Ryan Mitchell1499f502021-03-30 12:20:08 -0700184 if (entry_b->visibility.staged_api) {
185 str_stream << "STAGED ";
186 }
Adam Lesinski71be7052017-12-12 16:48:07 -0800187 if (entry_b->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700188 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700189 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700190 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700191 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700192 str_stream << " vs ";
Ryan Mitchell1499f502021-03-30 12:20:08 -0700193 if (entry_a->visibility.staged_api) {
194 str_stream << "STAGED ";
195 }
Adam Lesinski71be7052017-12-12 16:48:07 -0800196 if (entry_a->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700197 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700198 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700199 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700200 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700201 str_stream << ")";
202 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700203 diff = true;
Adam Lesinski71be7052017-12-12 16:48:07 -0800204 } else if (IsIdDiff(entry_a->visibility.level, entry_a->id, entry_b->visibility.level,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700205 entry_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700206 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700207 str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700208 << " has different public ID (";
209 if (entry_b->id) {
210 str_stream << "0x" << std::hex << entry_b->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 << " vs ";
215 if (entry_a->id) {
216 str_stream << "0x " << std::hex << entry_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700217 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 str_stream << ")";
221 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700222 diff = true;
223 }
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700224 diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a, apk_b, pkg_b, type_b,
225 entry_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700226 }
Ryan Mitchell1499f502021-03-30 12:20:08 -0700227 if (entry_a_iter != type_a.entries.end()) {
228 ++entry_a_iter;
229 }
230 if (entry_b_iter != type_b.entries.end()) {
231 ++entry_b_iter;
232 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700233 }
234 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700235}
236
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700237static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700238 const ResourceTablePackageView& pkg_a, LoadedApk* apk_b,
239 const ResourceTablePackageView& pkg_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700240 bool diff = false;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700241 auto type_a_iter = pkg_a.types.begin();
242 auto type_b_iter = pkg_b.types.begin();
243 while (type_a_iter != pkg_a.types.end() || type_b_iter != pkg_b.types.end()) {
244 if (type_b_iter == pkg_b.types.end()) {
245 // Type A contains a type that type B does not have.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700246 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700247 str_stream << "missing " << pkg_a.name << ":" << type_a_iter->type;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700248 EmitDiffLine(apk_a->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700249 diff = true;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700250 } else if (type_a_iter == pkg_a.types.end()) {
251 // Type B contains a type that type A does not have.
252 std::stringstream str_stream;
253 str_stream << "new type " << pkg_b.name << ":" << type_b_iter->type;
254 EmitDiffLine(apk_b->GetSource(), str_stream.str());
255 diff = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700256 } else {
Ryan Mitchell1499f502021-03-30 12:20:08 -0700257 const auto& type_a = *type_a_iter;
258 const auto& type_b = *type_b_iter;
259 if (type_a.visibility_level != type_b.visibility_level) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700260 std::stringstream str_stream;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700261 str_stream << pkg_a.name << ":" << type_a.type << " has different visibility (";
262 if (type_b.visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700263 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700264 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700265 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700266 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700267 str_stream << " vs ";
Ryan Mitchell1499f502021-03-30 12:20:08 -0700268 if (type_a.visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700269 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700270 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700272 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700273 str_stream << ")";
274 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700275 diff = true;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700276 } else if (IsIdDiff(type_a.visibility_level, type_a.id, type_b.visibility_level, type_b.id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700277 std::stringstream str_stream;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700278 str_stream << pkg_a.name << ":" << type_a.type << " has different public ID (";
279 if (type_b.id) {
280 str_stream << "0x" << std::hex << type_b.id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700281 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700282 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700283 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700284 str_stream << " vs ";
Ryan Mitchell1499f502021-03-30 12:20:08 -0700285 if (type_a.id) {
286 str_stream << "0x " << std::hex << type_a.id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700287 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700288 str_stream << "none";
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;
293 }
Ryan Mitchell1499f502021-03-30 12:20:08 -0700294 diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a, apk_b, pkg_b, type_b);
295 }
296 if (type_a_iter != pkg_a.types.end()) {
297 ++type_a_iter;
298 }
299 if (type_b_iter != pkg_b.types.end()) {
300 ++type_b_iter;
Adam Lesinski458b8772016-04-25 14:20:21 -0700301 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700302 }
303 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700304}
305
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700306static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700307 const auto table_a = apk_a->GetResourceTable()->GetPartitionedView();
308 const auto table_b = apk_b->GetResourceTable()->GetPartitionedView();
Adam Lesinski458b8772016-04-25 14:20:21 -0700309
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700310 bool diff = false;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700311 auto package_a_iter = table_a.packages.begin();
312 auto package_b_iter = table_b.packages.begin();
313 while (package_a_iter != table_a.packages.end() || package_b_iter != table_b.packages.end()) {
314 if (package_b_iter == table_b.packages.end()) {
315 // Table A contains a package that table B does not have.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700316 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700317 str_stream << "missing package " << package_a_iter->name;
318 EmitDiffLine(apk_a->GetSource(), str_stream.str());
319 diff = true;
320 } else if (package_a_iter == table_a.packages.end()) {
321 // Table B contains a package that table A does not have.
322 std::stringstream str_stream;
323 str_stream << "new package " << package_b_iter->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700324 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700325 diff = true;
326 } else {
Ryan Mitchell1499f502021-03-30 12:20:08 -0700327 const auto& package_a = *package_a_iter;
328 const auto& package_b = *package_b_iter;
329 if (package_a.id != package_b.id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700330 std::stringstream str_stream;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700331 str_stream << "package '" << package_a.name << "' has different id (";
332 if (package_b.id) {
333 str_stream << "0x" << std::hex << package_b.id.value();
Adam Lesinski458b8772016-04-25 14:20:21 -0700334 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700335 str_stream << "none";
Adam Lesinski458b8772016-04-25 14:20:21 -0700336 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700337 str_stream << " vs ";
Ryan Mitchell1499f502021-03-30 12:20:08 -0700338 if (package_a.id) {
339 str_stream << "0x" << std::hex << package_b.id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700340 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700341 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700342 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700343 str_stream << ")";
344 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700345 diff = true;
346 }
Ryan Mitchell1499f502021-03-30 12:20:08 -0700347 diff |= EmitResourcePackageDiff(context, apk_a, package_a, apk_b, package_b);
348 }
349 if (package_a_iter != table_a.packages.end()) {
350 ++package_a_iter;
351 }
352 if (package_b_iter != table_b.packages.end()) {
353 ++package_b_iter;
Adam Lesinski458b8772016-04-25 14:20:21 -0700354 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700355 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700356
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700357 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700358}
359
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700360class ZeroingReferenceVisitor : public DescendingValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700361 public:
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700362 using DescendingValueVisitor::Visit;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700363
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700364 void Visit(Reference* ref) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700365 if (ref->name && ref->id) {
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800366 if (ref->id.value().package_id() == kAppPackageId) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700367 ref->id = {};
368 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700369 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700370 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700371};
372
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700373static void ZeroOutAppReferences(ResourceTable* table) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700374 ZeroingReferenceVisitor visitor;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700375 VisitAllValuesInTable(table, &visitor);
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700376}
377
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700378int DiffCommand::Action(const std::vector<std::string>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700379 DiffContext context;
Adam Lesinski458b8772016-04-25 14:20:21 -0700380
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700381 if (args.size() != 2u) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700382 std::cerr << "must have two apks as arguments.\n\n";
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700383 Usage(&std::cerr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700384 return 1;
385 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700386
Adam Lesinski8780eb62017-10-31 17:44:39 -0700387 IDiagnostics* diag = context.GetDiagnostics();
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700388 std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(args[0], diag);
389 std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(args[1], diag);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700390 if (!apk_a || !apk_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700391 return 1;
392 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700393
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700394 // Zero out Application IDs in references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700395 ZeroOutAppReferences(apk_a->GetResourceTable());
396 ZeroOutAppReferences(apk_b->GetResourceTable());
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700397
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700398 if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700399 // We emitted a diff, so return 1 (failure).
400 return 1;
401 }
402 return 0;
Adam Lesinski458b8772016-04-25 14:20:21 -0700403}
404
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700405} // namespace aapt