blob: 12113ed8a48a84fc11cdc2db8628e90be795c7cd [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
Adam Lesinskicacb28f2016-10-19 12:18:14 -070067 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070068 std::string empty_;
69 StdErrDiagnostics diagnostics_;
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080070 NameMangler name_mangler_;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070071 SymbolTable symbol_table_;
Adam Lesinski458b8772016-04-25 14:20:21 -070072};
73
Adam Lesinskice5e56e2016-10-21 17:56:45 -070074static void EmitDiffLine(const Source& source, const StringPiece& message) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070075 std::cerr << source << ": " << message << "\n";
Adam Lesinski458b8772016-04-25 14:20:21 -070076}
77
Adam Lesinski71be7052017-12-12 16:48:07 -080078static bool IsSymbolVisibilityDifferent(const Visibility& vis_a, const Visibility& vis_b) {
79 return vis_a.level != vis_b.level;
Adam Lesinski458b8772016-04-25 14:20:21 -070080}
81
82template <typename Id>
Adam Lesinski71be7052017-12-12 16:48:07 -080083static bool IsIdDiff(const Visibility::Level& level_a, const Maybe<Id>& id_a,
84 const Visibility::Level& level_b, const Maybe<Id>& id_b) {
85 if (level_a == Visibility::Level::kPublic || level_b == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070086 return id_a != id_b;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070087 }
88 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -070089}
90
Adam Lesinskid0f492d2017-04-03 18:12:45 -070091static bool EmitResourceConfigValueDiff(IAaptContext* context, LoadedApk* apk_a,
92 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
93 ResourceEntry* entry_a, ResourceConfigValue* config_value_a,
94 LoadedApk* apk_b, ResourceTablePackage* pkg_b,
95 ResourceTableType* type_b, ResourceEntry* entry_b,
96 ResourceConfigValue* config_value_b) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070097 Value* value_a = config_value_a->value.get();
98 Value* value_b = config_value_b->value.get();
99 if (!value_a->Equals(value_b)) {
100 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700101 str_stream << "value " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
102 << " config=" << config_value_a->config << " does not match:\n";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700103 value_a->Print(&str_stream);
104 str_stream << "\n vs \n";
105 value_b->Print(&str_stream);
106 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700107 return true;
108 }
109 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700110}
111
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700112static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700113 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700114 ResourceEntry* entry_a, LoadedApk* apk_b,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700115 ResourceTablePackage* pkg_b, ResourceTableType* type_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700116 ResourceEntry* entry_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700117 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700118 for (std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700119 ResourceConfigValue* config_value_b = entry_b->FindValue(config_value_a->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700120 if (!config_value_b) {
121 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700122 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
123 << " config=" << config_value_a->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700124 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700125 diff = true;
126 } else {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700127 diff |=
128 EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a.get(),
129 apk_b, pkg_b, type_b, entry_b, config_value_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700130 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700131 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700132
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700133 // Check for any newly added config values.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700134 for (std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700135 ResourceConfigValue* config_value_a = entry_a->FindValue(config_value_b->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700136 if (!config_value_a) {
137 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700138 str_stream << "new config " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name
139 << " config=" << config_value_b->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700140 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700141 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700142 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143 }
144 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700145}
146
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700147static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700148 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
149 LoadedApk* apk_b, ResourceTablePackage* pkg_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700150 ResourceTableType* type_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700151 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700152 for (std::unique_ptr<ResourceEntry>& entry_a : type_a->entries) {
153 ResourceEntry* entry_b = type_b->FindEntry(entry_a->name);
154 if (!entry_b) {
155 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700156 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700157 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700158 diff = true;
159 } else {
Adam Lesinski71be7052017-12-12 16:48:07 -0800160 if (IsSymbolVisibilityDifferent(entry_a->visibility, entry_b->visibility)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700161 std::stringstream str_stream;
162 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
163 << " has different visibility (";
Adam Lesinski71be7052017-12-12 16:48:07 -0800164 if (entry_b->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700165 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700166 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700167 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700168 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700169 str_stream << " vs ";
Adam Lesinski71be7052017-12-12 16:48:07 -0800170 if (entry_a->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700171 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700172 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700173 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700174 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700175 str_stream << ")";
176 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700177 diff = true;
Adam Lesinski71be7052017-12-12 16:48:07 -0800178 } else if (IsIdDiff(entry_a->visibility.level, entry_a->id, entry_b->visibility.level,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700179 entry_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700180 std::stringstream str_stream;
181 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
182 << " has different public ID (";
183 if (entry_b->id) {
184 str_stream << "0x" << std::hex << entry_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700185 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700186 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700187 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700188 str_stream << " vs ";
189 if (entry_a->id) {
190 str_stream << "0x " << std::hex << entry_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700191 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700192 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700193 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700194 str_stream << ")";
195 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700196 diff = true;
197 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700198 diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a.get(), apk_b, pkg_b,
199 type_b, entry_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700200 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700201 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700202
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700203 // Check for any newly added entries.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700204 for (std::unique_ptr<ResourceEntry>& entry_b : type_b->entries) {
205 ResourceEntry* entry_a = type_a->FindEntry(entry_b->name);
206 if (!entry_a) {
207 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700208 str_stream << "new entry " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700209 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700210 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700211 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700212 }
213 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700214}
215
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700216static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700217 ResourceTablePackage* pkg_a, LoadedApk* apk_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 ResourceTablePackage* pkg_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 for (std::unique_ptr<ResourceTableType>& type_a : pkg_a->types) {
221 ResourceTableType* type_b = pkg_b->FindType(type_a->type);
222 if (!type_b) {
223 std::stringstream str_stream;
224 str_stream << "missing " << pkg_a->name << ":" << type_a->type;
225 EmitDiffLine(apk_a->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700226 diff = true;
227 } else {
Adam Lesinski71be7052017-12-12 16:48:07 -0800228 if (type_a->visibility_level != type_b->visibility_level) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700229 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700230 str_stream << pkg_a->name << ":" << type_a->type << " has different visibility (";
Adam Lesinski71be7052017-12-12 16:48:07 -0800231 if (type_b->visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700232 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700233 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700234 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700235 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700236 str_stream << " vs ";
Adam Lesinski71be7052017-12-12 16:48:07 -0800237 if (type_a->visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700238 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700239 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700240 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700241 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700242 str_stream << ")";
243 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700244 diff = true;
Adam Lesinski71be7052017-12-12 16:48:07 -0800245 } else if (IsIdDiff(type_a->visibility_level, type_a->id, type_b->visibility_level,
246 type_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700248 str_stream << pkg_a->name << ":" << type_a->type << " has different public ID (";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700249 if (type_b->id) {
250 str_stream << "0x" << std::hex << type_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700251 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700252 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700253 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700254 str_stream << " vs ";
255 if (type_a->id) {
256 str_stream << "0x " << std::hex << type_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700257 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700258 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700259 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700260 str_stream << ")";
261 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700262 diff = true;
263 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700264 diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a.get(), apk_b, pkg_b, type_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700265 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700266 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700267
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700268 // Check for any newly added types.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700269 for (std::unique_ptr<ResourceTableType>& type_b : pkg_b->types) {
270 ResourceTableType* type_a = pkg_a->FindType(type_b->type);
271 if (!type_a) {
272 std::stringstream str_stream;
273 str_stream << "new type " << pkg_b->name << ":" << type_b->type;
274 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700275 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700276 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700277 }
278 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700279}
280
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700281static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700282 ResourceTable* table_a = apk_a->GetResourceTable();
283 ResourceTable* table_b = apk_b->GetResourceTable();
Adam Lesinski458b8772016-04-25 14:20:21 -0700284
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700285 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700286 for (std::unique_ptr<ResourceTablePackage>& pkg_a : table_a->packages) {
287 ResourceTablePackage* pkg_b = table_b->FindPackage(pkg_a->name);
288 if (!pkg_b) {
289 std::stringstream str_stream;
290 str_stream << "missing package " << pkg_a->name;
291 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700292 diff = true;
293 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700294 if (pkg_a->id != pkg_b->id) {
295 std::stringstream str_stream;
296 str_stream << "package '" << pkg_a->name << "' has different id (";
297 if (pkg_b->id) {
298 str_stream << "0x" << std::hex << pkg_b->id.value();
Adam Lesinski458b8772016-04-25 14:20:21 -0700299 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700300 str_stream << "none";
Adam Lesinski458b8772016-04-25 14:20:21 -0700301 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700302 str_stream << " vs ";
303 if (pkg_a->id) {
304 str_stream << "0x" << std::hex << pkg_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700305 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700306 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700307 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700308 str_stream << ")";
309 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700310 diff = true;
311 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700312 diff |= EmitResourcePackageDiff(context, apk_a, pkg_a.get(), apk_b, pkg_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700313 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700314 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700315
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700316 // Check for any newly added packages.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700317 for (std::unique_ptr<ResourceTablePackage>& pkg_b : table_b->packages) {
318 ResourceTablePackage* pkg_a = table_a->FindPackage(pkg_b->name);
319 if (!pkg_a) {
320 std::stringstream str_stream;
321 str_stream << "new package " << pkg_b->name;
322 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700323 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700324 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700325 }
326 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700327}
328
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700329class ZeroingReferenceVisitor : public DescendingValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700330 public:
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700331 using DescendingValueVisitor::Visit;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700332
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700333 void Visit(Reference* ref) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700334 if (ref->name && ref->id) {
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800335 if (ref->id.value().package_id() == kAppPackageId) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700336 ref->id = {};
337 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700338 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700339 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700340};
341
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700342static void ZeroOutAppReferences(ResourceTable* table) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700343 ZeroingReferenceVisitor visitor;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700344 VisitAllValuesInTable(table, &visitor);
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700345}
346
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700347int Diff(const std::vector<StringPiece>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700348 DiffContext context;
Adam Lesinski458b8772016-04-25 14:20:21 -0700349
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700350 Flags flags;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700351 if (!flags.Parse("aapt2 diff", args, &std::cerr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700352 return 1;
353 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700354
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700355 if (flags.GetArgs().size() != 2u) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700356 std::cerr << "must have two apks as arguments.\n\n";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 flags.Usage("aapt2 diff", &std::cerr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700358 return 1;
359 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700360
Adam Lesinski8780eb62017-10-31 17:44:39 -0700361 IDiagnostics* diag = context.GetDiagnostics();
362 std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(flags.GetArgs()[0], diag);
363 std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(flags.GetArgs()[1], diag);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700364 if (!apk_a || !apk_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700365 return 1;
366 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700367
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700368 // Zero out Application IDs in references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700369 ZeroOutAppReferences(apk_a->GetResourceTable());
370 ZeroOutAppReferences(apk_b->GetResourceTable());
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700371
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700372 if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700373 // We emitted a diff, so return 1 (failure).
374 return 1;
375 }
376 return 0;
Adam Lesinski458b8772016-04-25 14:20:21 -0700377}
378
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700379} // namespace aapt