blob: fdc89b2b24bd2d643e084efc7d5af20e68e6426b [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 Lesinskid5083f62017-01-16 15:07:21 -080025using android::StringPiece;
26
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 Lesinskid0f492d2017-04-03 18:12:45 -070034 const std::string& GetCompilationPackage() override {
35 return empty_;
36 }
Adam Lesinski458b8772016-04-25 14:20:21 -070037
Adam Lesinskid0f492d2017-04-03 18:12:45 -070038 uint8_t GetPackageId() override {
39 return 0x0;
40 }
Adam Lesinski458b8772016-04-25 14:20:21 -070041
Adam Lesinskid0f492d2017-04-03 18:12:45 -070042 IDiagnostics* GetDiagnostics() override {
43 return &diagnostics_;
44 }
Adam Lesinski458b8772016-04-25 14:20:21 -070045
Adam Lesinskid0f492d2017-04-03 18:12:45 -070046 NameMangler* GetNameMangler() override {
47 return &name_mangler_;
48 }
Adam Lesinski458b8772016-04-25 14:20:21 -070049
Adam Lesinskid0f492d2017-04-03 18:12:45 -070050 SymbolTable* GetExternalSymbols() override {
51 return &symbol_table_;
52 }
Adam Lesinski458b8772016-04-25 14:20:21 -070053
Adam Lesinskid0f492d2017-04-03 18:12:45 -070054 bool IsVerbose() override {
55 return false;
56 }
Adam Lesinski458b8772016-04-25 14:20:21 -070057
Adam Lesinskid0f492d2017-04-03 18:12:45 -070058 int GetMinSdkVersion() override {
59 return 0;
60 }
Adam Lesinskifb6312f2016-06-28 14:40:32 -070061
Adam Lesinskicacb28f2016-10-19 12:18:14 -070062 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070063 std::string empty_;
64 StdErrDiagnostics diagnostics_;
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080065 NameMangler name_mangler_;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070066 SymbolTable symbol_table_;
Adam Lesinski458b8772016-04-25 14:20:21 -070067};
68
Adam Lesinskice5e56e2016-10-21 17:56:45 -070069static void EmitDiffLine(const Source& source, const StringPiece& message) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070070 std::cerr << source << ": " << message << "\n";
Adam Lesinski458b8772016-04-25 14:20:21 -070071}
72
Adam Lesinskid0f492d2017-04-03 18:12:45 -070073static bool IsSymbolVisibilityDifferent(const Symbol& symbol_a, const Symbol& symbol_b) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070074 return symbol_a.state != symbol_b.state;
Adam Lesinski458b8772016-04-25 14:20:21 -070075}
76
77template <typename Id>
Adam Lesinskid0f492d2017-04-03 18:12:45 -070078static bool IsIdDiff(const Symbol& symbol_a, const Maybe<Id>& id_a, const Symbol& symbol_b,
79 const Maybe<Id>& id_b) {
80 if (symbol_a.state == SymbolState::kPublic || symbol_b.state == SymbolState::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070081 return id_a != id_b;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070082 }
83 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -070084}
85
Adam Lesinskid0f492d2017-04-03 18:12:45 -070086static bool EmitResourceConfigValueDiff(IAaptContext* context, LoadedApk* apk_a,
87 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
88 ResourceEntry* entry_a, ResourceConfigValue* config_value_a,
89 LoadedApk* apk_b, ResourceTablePackage* pkg_b,
90 ResourceTableType* type_b, ResourceEntry* entry_b,
91 ResourceConfigValue* config_value_b) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092 Value* value_a = config_value_a->value.get();
93 Value* value_b = config_value_b->value.get();
94 if (!value_a->Equals(value_b)) {
95 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -070096 str_stream << "value " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
97 << " config=" << config_value_a->config << " does not match:\n";
Adam Lesinskice5e56e2016-10-21 17:56:45 -070098 value_a->Print(&str_stream);
99 str_stream << "\n vs \n";
100 value_b->Print(&str_stream);
101 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700102 return true;
103 }
104 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700105}
106
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700107static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700108 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700109 ResourceEntry* entry_a, LoadedApk* apk_b,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700110 ResourceTablePackage* pkg_b, ResourceTableType* type_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700111 ResourceEntry* entry_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700112 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700113 for (std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700114 ResourceConfigValue* config_value_b = entry_b->FindValue(config_value_a->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700115 if (!config_value_b) {
116 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700117 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
118 << " config=" << config_value_a->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700119 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700120 diff = true;
121 } else {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700122 diff |=
123 EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a.get(),
124 apk_b, pkg_b, type_b, entry_b, config_value_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700125 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700126 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700127
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700128 // Check for any newly added config values.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700129 for (std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700130 ResourceConfigValue* config_value_a = entry_a->FindValue(config_value_b->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700131 if (!config_value_a) {
132 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700133 str_stream << "new config " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name
134 << " config=" << config_value_b->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700135 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700136 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700137 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700138 }
139 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700140}
141
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700142static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700143 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
144 LoadedApk* apk_b, ResourceTablePackage* pkg_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700145 ResourceTableType* type_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700146 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700147 for (std::unique_ptr<ResourceEntry>& entry_a : type_a->entries) {
148 ResourceEntry* entry_b = type_b->FindEntry(entry_a->name);
149 if (!entry_b) {
150 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700151 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700152 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700153 diff = true;
154 } else {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700155 if (IsSymbolVisibilityDifferent(entry_a->symbol_status, entry_b->symbol_status)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 std::stringstream str_stream;
157 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
158 << " has different visibility (";
159 if (entry_b->symbol_status.state == SymbolState::kPublic) {
160 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700161 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700162 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700163 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700164 str_stream << " vs ";
165 if (entry_a->symbol_status.state == SymbolState::kPublic) {
166 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700167 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700168 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700169 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700170 str_stream << ")";
171 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700172 diff = true;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700173 } else if (IsIdDiff(entry_a->symbol_status, entry_a->id, entry_b->symbol_status,
174 entry_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700175 std::stringstream str_stream;
176 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
177 << " has different public ID (";
178 if (entry_b->id) {
179 str_stream << "0x" << std::hex << entry_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700180 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700181 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700182 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700183 str_stream << " vs ";
184 if (entry_a->id) {
185 str_stream << "0x " << std::hex << entry_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700186 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700187 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700188 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700189 str_stream << ")";
190 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700191 diff = true;
192 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700193 diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a.get(), apk_b, pkg_b,
194 type_b, entry_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700195 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700196 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700197
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700198 // Check for any newly added entries.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700199 for (std::unique_ptr<ResourceEntry>& entry_b : type_b->entries) {
200 ResourceEntry* entry_a = type_a->FindEntry(entry_b->name);
201 if (!entry_a) {
202 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700203 str_stream << "new entry " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700204 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700205 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700206 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700207 }
208 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700209}
210
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700211static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700212 ResourceTablePackage* pkg_a, LoadedApk* apk_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700213 ResourceTablePackage* pkg_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700214 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700215 for (std::unique_ptr<ResourceTableType>& type_a : pkg_a->types) {
216 ResourceTableType* type_b = pkg_b->FindType(type_a->type);
217 if (!type_b) {
218 std::stringstream str_stream;
219 str_stream << "missing " << pkg_a->name << ":" << type_a->type;
220 EmitDiffLine(apk_a->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 diff = true;
222 } else {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700223 if (IsSymbolVisibilityDifferent(type_a->symbol_status, type_b->symbol_status)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700224 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700225 str_stream << pkg_a->name << ":" << type_a->type << " has different visibility (";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700226 if (type_b->symbol_status.state == SymbolState::kPublic) {
227 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700228 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700229 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700230 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700231 str_stream << " vs ";
232 if (type_a->symbol_status.state == SymbolState::kPublic) {
233 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700234 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700235 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700236 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700237 str_stream << ")";
238 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700239 diff = true;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700240 } else if (IsIdDiff(type_a->symbol_status, type_a->id, type_b->symbol_status, type_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700241 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700242 str_stream << pkg_a->name << ":" << type_a->type << " has different public ID (";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700243 if (type_b->id) {
244 str_stream << "0x" << std::hex << type_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700245 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700246 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700247 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700248 str_stream << " vs ";
249 if (type_a->id) {
250 str_stream << "0x " << std::hex << type_a->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 << ")";
255 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700256 diff = true;
257 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700258 diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a.get(), apk_b, pkg_b, type_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700259 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700260 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700261
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700262 // Check for any newly added types.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700263 for (std::unique_ptr<ResourceTableType>& type_b : pkg_b->types) {
264 ResourceTableType* type_a = pkg_a->FindType(type_b->type);
265 if (!type_a) {
266 std::stringstream str_stream;
267 str_stream << "new type " << pkg_b->name << ":" << type_b->type;
268 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700269 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700270 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700271 }
272 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700273}
274
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700275static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700276 ResourceTable* table_a = apk_a->GetResourceTable();
277 ResourceTable* table_b = apk_b->GetResourceTable();
Adam Lesinski458b8772016-04-25 14:20:21 -0700278
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700279 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700280 for (std::unique_ptr<ResourceTablePackage>& pkg_a : table_a->packages) {
281 ResourceTablePackage* pkg_b = table_b->FindPackage(pkg_a->name);
282 if (!pkg_b) {
283 std::stringstream str_stream;
284 str_stream << "missing package " << pkg_a->name;
285 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700286 diff = true;
287 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700288 if (pkg_a->id != pkg_b->id) {
289 std::stringstream str_stream;
290 str_stream << "package '" << pkg_a->name << "' has different id (";
291 if (pkg_b->id) {
292 str_stream << "0x" << std::hex << pkg_b->id.value();
Adam Lesinski458b8772016-04-25 14:20:21 -0700293 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700294 str_stream << "none";
Adam Lesinski458b8772016-04-25 14:20:21 -0700295 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700296 str_stream << " vs ";
297 if (pkg_a->id) {
298 str_stream << "0x" << std::hex << pkg_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700299 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700300 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700301 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700302 str_stream << ")";
303 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700304 diff = true;
305 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700306 diff |= EmitResourcePackageDiff(context, apk_a, pkg_a.get(), apk_b, pkg_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700307 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700308 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700309
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700310 // Check for any newly added packages.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700311 for (std::unique_ptr<ResourceTablePackage>& pkg_b : table_b->packages) {
312 ResourceTablePackage* pkg_a = table_a->FindPackage(pkg_b->name);
313 if (!pkg_a) {
314 std::stringstream str_stream;
315 str_stream << "new package " << pkg_b->name;
316 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700317 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700318 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700319 }
320 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700321}
322
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700323class ZeroingReferenceVisitor : public ValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700324 public:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700325 using ValueVisitor::Visit;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700326
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700327 void Visit(Reference* ref) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700328 if (ref->name && ref->id) {
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800329 if (ref->id.value().package_id() == kAppPackageId) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700330 ref->id = {};
331 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700332 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700333 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700334};
335
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700336static void ZeroOutAppReferences(ResourceTable* table) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700337 ZeroingReferenceVisitor visitor;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700338 VisitAllValuesInTable(table, &visitor);
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700339}
340
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700341int Diff(const std::vector<StringPiece>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700342 DiffContext context;
Adam Lesinski458b8772016-04-25 14:20:21 -0700343
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700344 Flags flags;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700345 if (!flags.Parse("aapt2 diff", args, &std::cerr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700346 return 1;
347 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700348
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700349 if (flags.GetArgs().size() != 2u) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700350 std::cerr << "must have two apks as arguments.\n\n";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700351 flags.Usage("aapt2 diff", &std::cerr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700352 return 1;
353 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700354
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700355 std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[0]);
356 std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[1]);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 if (!apk_a || !apk_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700358 return 1;
359 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700360
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700361 // Zero out Application IDs in references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700362 ZeroOutAppReferences(apk_a->GetResourceTable());
363 ZeroOutAppReferences(apk_b->GetResourceTable());
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700364
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700365 if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700366 // We emitted a diff, so return 1 (failure).
367 return 1;
368 }
369 return 0;
Adam Lesinski458b8772016-04-25 14:20:21 -0700370}
371
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700372} // namespace aapt