blob: d9e8c921dbc56f9af4a3fa82c6004adefcefb33c [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>
Ryan Mitchell4382e442021-07-14 12:53:01 -070090static bool IsIdDiff(const Visibility::Level& level_a, const std::optional<Id>& id_a,
91 const Visibility::Level& level_b, const std::optional<Id>& id_b) {
Adam Lesinski71be7052017-12-12 16:48:07 -080092 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,
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700100 const ResourceTableTypeView& type_a, const ResourceTableEntryView& entry_a,
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700101 const ResourceConfigValue* config_value_a, LoadedApk* apk_b,
102 const ResourceTablePackageView& pkg_b, const ResourceTableTypeView& type_b,
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700103 const ResourceTableEntryView& 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 Mitchell2fedba92021-04-23 07:47:38 -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,
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700121 const ResourceTableTypeView& type_a,
122 const ResourceTableEntryView& entry_a, LoadedApk* apk_b,
123 const ResourceTablePackageView& pkg_b,
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700124 const ResourceTableTypeView& type_b,
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700125 const ResourceTableEntryView& entry_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700126 bool diff = false;
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700127 for (const ResourceConfigValue* config_value_a : entry_a.values) {
128 auto config_value_b = entry_b.FindValue(config_value_a->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700129 if (!config_value_b) {
130 std::stringstream str_stream;
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700131 str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700132 << " config=" << config_value_a->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700133 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700134 diff = true;
135 } else {
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700136 diff |= EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a,
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 Mitchell2fedba92021-04-23 07:47:38 -0700142 for (const 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 Mitchell2fedba92021-04-23 07:47:38 -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 Mitchell2fedba92021-04-23 07:47:38 -0700167 str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a_iter->name;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700168 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;
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700173 str_stream << "new entry " << pkg_b.name << ":" << type_b.type << "/" << entry_b_iter->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700175 diff = true;
176 } else {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700177 const auto& entry_a = *entry_a_iter;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700178 const auto& entry_b = *entry_b_iter;
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700179 if (IsSymbolVisibilityDifferent(entry_a.visibility, entry_b.visibility)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700180 std::stringstream str_stream;
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700181 str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700182 << " has different visibility (";
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700183 if (entry_b.visibility.staged_api) {
Ryan Mitchell1499f502021-03-30 12:20:08 -0700184 str_stream << "STAGED ";
185 }
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700186 if (entry_b.visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700187 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700188 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700189 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700190 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700191 str_stream << " vs ";
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700192 if (entry_a.visibility.staged_api) {
Ryan Mitchell1499f502021-03-30 12:20:08 -0700193 str_stream << "STAGED ";
194 }
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700195 if (entry_a.visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700196 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700197 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700198 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700199 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700200 str_stream << ")";
201 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700202 diff = true;
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700203 } else if (IsIdDiff(entry_a.visibility.level, entry_a.id, entry_b.visibility.level,
204 entry_b.id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700205 std::stringstream str_stream;
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700206 str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700207 << " has different public ID (";
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700208 if (entry_b.id) {
209 str_stream << "0x" << std::hex << entry_b.id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700210 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700211 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700212 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700213 str_stream << " vs ";
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700214 if (entry_a.id) {
215 str_stream << "0x " << std::hex << entry_a.id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700216 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700217 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700218 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700219 str_stream << ")";
220 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 diff = true;
222 }
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700223 diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a, apk_b, pkg_b, type_b,
224 entry_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700225 }
Ryan Mitchell1499f502021-03-30 12:20:08 -0700226 if (entry_a_iter != type_a.entries.end()) {
227 ++entry_a_iter;
228 }
229 if (entry_b_iter != type_b.entries.end()) {
230 ++entry_b_iter;
231 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700232 }
233 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700234}
235
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700236static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700237 const ResourceTablePackageView& pkg_a, LoadedApk* apk_b,
238 const ResourceTablePackageView& pkg_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700239 bool diff = false;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700240 auto type_a_iter = pkg_a.types.begin();
241 auto type_b_iter = pkg_b.types.begin();
242 while (type_a_iter != pkg_a.types.end() || type_b_iter != pkg_b.types.end()) {
243 if (type_b_iter == pkg_b.types.end()) {
244 // Type A contains a type that type B does not have.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700245 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700246 str_stream << "missing " << pkg_a.name << ":" << type_a_iter->type;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 EmitDiffLine(apk_a->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700248 diff = true;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700249 } else if (type_a_iter == pkg_a.types.end()) {
250 // Type B contains a type that type A does not have.
251 std::stringstream str_stream;
252 str_stream << "new type " << pkg_b.name << ":" << type_b_iter->type;
253 EmitDiffLine(apk_b->GetSource(), str_stream.str());
254 diff = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700255 } else {
Ryan Mitchell1499f502021-03-30 12:20:08 -0700256 const auto& type_a = *type_a_iter;
257 const auto& type_b = *type_b_iter;
258 if (type_a.visibility_level != type_b.visibility_level) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700259 std::stringstream str_stream;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700260 str_stream << pkg_a.name << ":" << type_a.type << " has different visibility (";
261 if (type_b.visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700262 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700263 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700264 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700265 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700266 str_stream << " vs ";
Ryan Mitchell1499f502021-03-30 12:20:08 -0700267 if (type_a.visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700268 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700269 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700270 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700271 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700272 str_stream << ")";
273 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700274 diff = true;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700275 } else if (IsIdDiff(type_a.visibility_level, type_a.id, type_b.visibility_level, type_b.id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700276 std::stringstream str_stream;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700277 str_stream << pkg_a.name << ":" << type_a.type << " has different public ID (";
278 if (type_b.id) {
279 str_stream << "0x" << std::hex << type_b.id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700280 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700281 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700282 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700283 str_stream << " vs ";
Ryan Mitchell1499f502021-03-30 12:20:08 -0700284 if (type_a.id) {
285 str_stream << "0x " << std::hex << type_a.id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700286 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700287 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700288 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700289 str_stream << ")";
290 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700291 diff = true;
292 }
Ryan Mitchell1499f502021-03-30 12:20:08 -0700293 diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a, apk_b, pkg_b, type_b);
294 }
295 if (type_a_iter != pkg_a.types.end()) {
296 ++type_a_iter;
297 }
298 if (type_b_iter != pkg_b.types.end()) {
299 ++type_b_iter;
Adam Lesinski458b8772016-04-25 14:20:21 -0700300 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700301 }
302 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700303}
304
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700305static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700306 const auto table_a = apk_a->GetResourceTable()->GetPartitionedView();
307 const auto table_b = apk_b->GetResourceTable()->GetPartitionedView();
Adam Lesinski458b8772016-04-25 14:20:21 -0700308
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700309 bool diff = false;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700310 auto package_a_iter = table_a.packages.begin();
311 auto package_b_iter = table_b.packages.begin();
312 while (package_a_iter != table_a.packages.end() || package_b_iter != table_b.packages.end()) {
313 if (package_b_iter == table_b.packages.end()) {
314 // Table A contains a package that table B does not have.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700315 std::stringstream str_stream;
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700316 str_stream << "missing package " << package_a_iter->name;
317 EmitDiffLine(apk_a->GetSource(), str_stream.str());
318 diff = true;
319 } else if (package_a_iter == table_a.packages.end()) {
320 // Table B contains a package that table A does not have.
321 std::stringstream str_stream;
322 str_stream << "new package " << package_b_iter->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700323 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700324 diff = true;
325 } else {
Ryan Mitchell1499f502021-03-30 12:20:08 -0700326 const auto& package_a = *package_a_iter;
327 const auto& package_b = *package_b_iter;
328 if (package_a.id != package_b.id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700329 std::stringstream str_stream;
Ryan Mitchell1499f502021-03-30 12:20:08 -0700330 str_stream << "package '" << package_a.name << "' has different id (";
331 if (package_b.id) {
332 str_stream << "0x" << std::hex << package_b.id.value();
Adam Lesinski458b8772016-04-25 14:20:21 -0700333 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700334 str_stream << "none";
Adam Lesinski458b8772016-04-25 14:20:21 -0700335 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700336 str_stream << " vs ";
Ryan Mitchell1499f502021-03-30 12:20:08 -0700337 if (package_a.id) {
338 str_stream << "0x" << std::hex << package_b.id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700339 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700340 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700341 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700342 str_stream << ")";
343 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700344 diff = true;
345 }
Ryan Mitchell1499f502021-03-30 12:20:08 -0700346 diff |= EmitResourcePackageDiff(context, apk_a, package_a, apk_b, package_b);
347 }
348 if (package_a_iter != table_a.packages.end()) {
349 ++package_a_iter;
350 }
351 if (package_b_iter != table_b.packages.end()) {
352 ++package_b_iter;
Adam Lesinski458b8772016-04-25 14:20:21 -0700353 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700354 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700355
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700356 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700357}
358
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700359class ZeroingReferenceVisitor : public DescendingValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700360 public:
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700361 using DescendingValueVisitor::Visit;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700362
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700363 void Visit(Reference* ref) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700364 if (ref->name && ref->id) {
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800365 if (ref->id.value().package_id() == kAppPackageId) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700366 ref->id = {};
367 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700368 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700369 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700370};
371
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700372static void ZeroOutAppReferences(ResourceTable* table) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700373 ZeroingReferenceVisitor visitor;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700374 VisitAllValuesInTable(table, &visitor);
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700375}
376
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700377int DiffCommand::Action(const std::vector<std::string>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700378 DiffContext context;
Adam Lesinski458b8772016-04-25 14:20:21 -0700379
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700380 if (args.size() != 2u) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700381 std::cerr << "must have two apks as arguments.\n\n";
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700382 Usage(&std::cerr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700383 return 1;
384 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700385
Adam Lesinski8780eb62017-10-31 17:44:39 -0700386 IDiagnostics* diag = context.GetDiagnostics();
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700387 std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(args[0], diag);
388 std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(args[1], diag);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700389 if (!apk_a || !apk_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700390 return 1;
391 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700392
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700393 // Zero out Application IDs in references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700394 ZeroOutAppReferences(apk_a->GetResourceTable());
395 ZeroOutAppReferences(apk_b->GetResourceTable());
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700396
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700397 if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700398 // We emitted a diff, so return 1 (failure).
399 return 1;
400 }
401 return 0;
Adam Lesinski458b8772016-04-25 14:20:21 -0700402}
403
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700404} // namespace aapt