blob: d56994e3ae24aa774bd82222542987fec755581e [file] [log] [blame]
Adam Lesinski458b8772016-04-25 14:20:21 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Ryan Mitchell833a1a62018-07-10 13:51:36 -070017#include "Diff.h"
18
Adam Lesinskice5e56e2016-10-21 17:56:45 -070019#include "android-base/macros.h"
20
Pierre Lecesneff759e62017-02-01 00:29:25 +000021#include "LoadedApk.h"
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -070022#include "ValueVisitor.h"
Adam Lesinski458b8772016-04-25 14:20:21 -070023#include "process/IResourceTableConsumer.h"
24#include "process/SymbolTable.h"
Adam Lesinski458b8772016-04-25 14:20:21 -070025
Adam Lesinskid3ffa8442017-09-28 13:34:35 -070026using ::android::StringPiece;
Adam Lesinskid5083f62017-01-16 15:07:21 -080027
Adam Lesinski458b8772016-04-25 14:20:21 -070028namespace aapt {
29
30class DiffContext : public IAaptContext {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070031 public:
Adam Lesinskid0f492d2017-04-03 18:12:45 -070032 DiffContext() : name_mangler_({}), symbol_table_(&name_mangler_) {
33 }
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080034
Adam Lesinskib522f042017-04-21 16:57:59 -070035 PackageType GetPackageType() override {
36 // Doesn't matter.
37 return PackageType::kApp;
38 }
39
Adam Lesinskid0f492d2017-04-03 18:12:45 -070040 const std::string& GetCompilationPackage() override {
41 return empty_;
42 }
Adam Lesinski458b8772016-04-25 14:20:21 -070043
Adam Lesinskid0f492d2017-04-03 18:12:45 -070044 uint8_t GetPackageId() override {
45 return 0x0;
46 }
Adam Lesinski458b8772016-04-25 14:20:21 -070047
Adam Lesinskid0f492d2017-04-03 18:12:45 -070048 IDiagnostics* GetDiagnostics() override {
49 return &diagnostics_;
50 }
Adam Lesinski458b8772016-04-25 14:20:21 -070051
Adam Lesinskid0f492d2017-04-03 18:12:45 -070052 NameMangler* GetNameMangler() override {
53 return &name_mangler_;
54 }
Adam Lesinski458b8772016-04-25 14:20:21 -070055
Adam Lesinskid0f492d2017-04-03 18:12:45 -070056 SymbolTable* GetExternalSymbols() override {
57 return &symbol_table_;
58 }
Adam Lesinski458b8772016-04-25 14:20:21 -070059
Adam Lesinskid0f492d2017-04-03 18:12:45 -070060 bool IsVerbose() override {
61 return false;
62 }
Adam Lesinski458b8772016-04-25 14:20:21 -070063
Adam Lesinskid0f492d2017-04-03 18:12:45 -070064 int GetMinSdkVersion() override {
65 return 0;
66 }
Adam Lesinskifb6312f2016-06-28 14:40:32 -070067
Udam Sainib228df32019-06-18 16:50:34 -070068 const std::set<std::string>& GetSplitNameDependencies() override {
69 UNIMPLEMENTED(FATAL) << "Split Name Dependencies should not be necessary";
70 static std::set<std::string> empty;
71 return empty;
72 }
73
Adam Lesinskicacb28f2016-10-19 12:18:14 -070074 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070075 std::string empty_;
76 StdErrDiagnostics diagnostics_;
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080077 NameMangler name_mangler_;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078 SymbolTable symbol_table_;
Adam Lesinski458b8772016-04-25 14:20:21 -070079};
80
Adam Lesinskice5e56e2016-10-21 17:56:45 -070081static void EmitDiffLine(const Source& source, const StringPiece& message) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070082 std::cerr << source << ": " << message << "\n";
Adam Lesinski458b8772016-04-25 14:20:21 -070083}
84
Adam Lesinski71be7052017-12-12 16:48:07 -080085static bool IsSymbolVisibilityDifferent(const Visibility& vis_a, const Visibility& vis_b) {
86 return vis_a.level != vis_b.level;
Adam Lesinski458b8772016-04-25 14:20:21 -070087}
88
89template <typename Id>
Adam Lesinski71be7052017-12-12 16:48:07 -080090static bool IsIdDiff(const Visibility::Level& level_a, const Maybe<Id>& id_a,
91 const Visibility::Level& level_b, const Maybe<Id>& id_b) {
92 if (level_a == Visibility::Level::kPublic || level_b == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070093 return id_a != id_b;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094 }
95 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -070096}
97
Adam Lesinskid0f492d2017-04-03 18:12:45 -070098static bool EmitResourceConfigValueDiff(IAaptContext* context, LoadedApk* apk_a,
99 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
100 ResourceEntry* entry_a, ResourceConfigValue* config_value_a,
101 LoadedApk* apk_b, ResourceTablePackage* pkg_b,
102 ResourceTableType* type_b, ResourceEntry* entry_b,
103 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;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700108 str_stream << "value " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
109 << " 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,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700120 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700121 ResourceEntry* entry_a, LoadedApk* apk_b,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700122 ResourceTablePackage* pkg_b, ResourceTableType* type_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700123 ResourceEntry* entry_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700124 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700125 for (std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700126 ResourceConfigValue* config_value_b = entry_b->FindValue(config_value_a->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700127 if (!config_value_b) {
128 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700129 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
130 << " config=" << config_value_a->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700131 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700132 diff = true;
133 } else {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700134 diff |=
135 EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a.get(),
136 apk_b, pkg_b, type_b, entry_b, config_value_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700137 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700138 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700139
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700140 // Check for any newly added config values.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700141 for (std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700142 ResourceConfigValue* config_value_a = entry_a->FindValue(config_value_b->config);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700143 if (!config_value_a) {
144 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700145 str_stream << "new config " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name
146 << " config=" << config_value_b->config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700147 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700148 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700149 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700150 }
151 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700152}
153
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700155 ResourceTablePackage* pkg_a, ResourceTableType* type_a,
156 LoadedApk* apk_b, ResourceTablePackage* pkg_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700157 ResourceTableType* type_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700158 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700159 for (std::unique_ptr<ResourceEntry>& entry_a : type_a->entries) {
160 ResourceEntry* entry_b = type_b->FindEntry(entry_a->name);
161 if (!entry_b) {
162 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700163 str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700164 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700165 diff = true;
166 } else {
Adam Lesinski71be7052017-12-12 16:48:07 -0800167 if (IsSymbolVisibilityDifferent(entry_a->visibility, entry_b->visibility)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700168 std::stringstream str_stream;
169 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
170 << " has different visibility (";
Adam Lesinski71be7052017-12-12 16:48:07 -0800171 if (entry_b->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700172 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700173 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700175 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700176 str_stream << " vs ";
Adam Lesinski71be7052017-12-12 16:48:07 -0800177 if (entry_a->visibility.level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700178 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700179 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700180 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700181 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700182 str_stream << ")";
183 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700184 diff = true;
Adam Lesinski71be7052017-12-12 16:48:07 -0800185 } else if (IsIdDiff(entry_a->visibility.level, entry_a->id, entry_b->visibility.level,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700186 entry_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700187 std::stringstream str_stream;
188 str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name
189 << " has different public ID (";
190 if (entry_b->id) {
191 str_stream << "0x" << std::hex << entry_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700192 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700193 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700194 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700195 str_stream << " vs ";
196 if (entry_a->id) {
197 str_stream << "0x " << std::hex << entry_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700198 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700199 str_stream << "none";
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;
204 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700205 diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a.get(), apk_b, pkg_b,
206 type_b, entry_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700207 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700208 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700209
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700210 // Check for any newly added entries.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700211 for (std::unique_ptr<ResourceEntry>& entry_b : type_b->entries) {
212 ResourceEntry* entry_a = type_a->FindEntry(entry_b->name);
213 if (!entry_a) {
214 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700215 str_stream << "new entry " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700216 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700217 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700218 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 }
220 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700221}
222
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700223static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700224 ResourceTablePackage* pkg_a, LoadedApk* apk_b,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700225 ResourceTablePackage* pkg_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700226 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700227 for (std::unique_ptr<ResourceTableType>& type_a : pkg_a->types) {
228 ResourceTableType* type_b = pkg_b->FindType(type_a->type);
229 if (!type_b) {
230 std::stringstream str_stream;
231 str_stream << "missing " << pkg_a->name << ":" << type_a->type;
232 EmitDiffLine(apk_a->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700233 diff = true;
234 } else {
Adam Lesinski71be7052017-12-12 16:48:07 -0800235 if (type_a->visibility_level != type_b->visibility_level) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700236 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700237 str_stream << pkg_a->name << ":" << type_a->type << " has different visibility (";
Adam Lesinski71be7052017-12-12 16:48:07 -0800238 if (type_b->visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700239 str_stream << "PUBLIC";
Adam Lesinski458b8772016-04-25 14:20:21 -0700240 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700241 str_stream << "PRIVATE";
Adam Lesinski458b8772016-04-25 14:20:21 -0700242 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700243 str_stream << " vs ";
Adam Lesinski71be7052017-12-12 16:48:07 -0800244 if (type_a->visibility_level == Visibility::Level::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700245 str_stream << "PUBLIC";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700246 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 str_stream << "PRIVATE";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700248 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700249 str_stream << ")";
250 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700251 diff = true;
Adam Lesinski71be7052017-12-12 16:48:07 -0800252 } else if (IsIdDiff(type_a->visibility_level, type_a->id, type_b->visibility_level,
253 type_b->id)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700254 std::stringstream str_stream;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700255 str_stream << pkg_a->name << ":" << type_a->type << " has different public ID (";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700256 if (type_b->id) {
257 str_stream << "0x" << std::hex << type_b->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700258 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700259 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700260 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700261 str_stream << " vs ";
262 if (type_a->id) {
263 str_stream << "0x " << std::hex << type_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700264 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700265 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700266 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700267 str_stream << ")";
268 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700269 diff = true;
270 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700271 diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a.get(), apk_b, pkg_b, type_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700272 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700273 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700274
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700275 // Check for any newly added types.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700276 for (std::unique_ptr<ResourceTableType>& type_b : pkg_b->types) {
277 ResourceTableType* type_a = pkg_a->FindType(type_b->type);
278 if (!type_a) {
279 std::stringstream str_stream;
280 str_stream << "new type " << pkg_b->name << ":" << type_b->type;
281 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700282 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700283 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700284 }
285 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700286}
287
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700288static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700289 ResourceTable* table_a = apk_a->GetResourceTable();
290 ResourceTable* table_b = apk_b->GetResourceTable();
Adam Lesinski458b8772016-04-25 14:20:21 -0700291
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700292 bool diff = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700293 for (std::unique_ptr<ResourceTablePackage>& pkg_a : table_a->packages) {
294 ResourceTablePackage* pkg_b = table_b->FindPackage(pkg_a->name);
295 if (!pkg_b) {
296 std::stringstream str_stream;
297 str_stream << "missing package " << pkg_a->name;
298 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700299 diff = true;
300 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700301 if (pkg_a->id != pkg_b->id) {
302 std::stringstream str_stream;
303 str_stream << "package '" << pkg_a->name << "' has different id (";
304 if (pkg_b->id) {
305 str_stream << "0x" << std::hex << pkg_b->id.value();
Adam Lesinski458b8772016-04-25 14:20:21 -0700306 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700307 str_stream << "none";
Adam Lesinski458b8772016-04-25 14:20:21 -0700308 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700309 str_stream << " vs ";
310 if (pkg_a->id) {
311 str_stream << "0x" << std::hex << pkg_a->id.value();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700312 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700313 str_stream << "none";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700314 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700315 str_stream << ")";
316 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700317 diff = true;
318 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700319 diff |= EmitResourcePackageDiff(context, apk_a, pkg_a.get(), apk_b, pkg_b);
Adam Lesinski458b8772016-04-25 14:20:21 -0700320 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700321 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700322
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700323 // Check for any newly added packages.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700324 for (std::unique_ptr<ResourceTablePackage>& pkg_b : table_b->packages) {
325 ResourceTablePackage* pkg_a = table_a->FindPackage(pkg_b->name);
326 if (!pkg_a) {
327 std::stringstream str_stream;
328 str_stream << "new package " << pkg_b->name;
329 EmitDiffLine(apk_b->GetSource(), str_stream.str());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700330 diff = true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700331 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700332 }
333 return diff;
Adam Lesinski458b8772016-04-25 14:20:21 -0700334}
335
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700336class ZeroingReferenceVisitor : public DescendingValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700337 public:
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700338 using DescendingValueVisitor::Visit;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700339
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700340 void Visit(Reference* ref) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700341 if (ref->name && ref->id) {
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800342 if (ref->id.value().package_id() == kAppPackageId) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700343 ref->id = {};
344 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700345 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700346 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700347};
348
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700349static void ZeroOutAppReferences(ResourceTable* table) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700350 ZeroingReferenceVisitor visitor;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700351 VisitAllValuesInTable(table, &visitor);
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700352}
353
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700354int DiffCommand::Action(const std::vector<std::string>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700355 DiffContext context;
Adam Lesinski458b8772016-04-25 14:20:21 -0700356
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700357 if (args.size() != 2u) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700358 std::cerr << "must have two apks as arguments.\n\n";
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700359 Usage(&std::cerr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700360 return 1;
361 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700362
Adam Lesinski8780eb62017-10-31 17:44:39 -0700363 IDiagnostics* diag = context.GetDiagnostics();
Ryan Mitchell833a1a62018-07-10 13:51:36 -0700364 std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(args[0], diag);
365 std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(args[1], diag);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700366 if (!apk_a || !apk_b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700367 return 1;
368 }
Adam Lesinski458b8772016-04-25 14:20:21 -0700369
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700370 // Zero out Application IDs in references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700371 ZeroOutAppReferences(apk_a->GetResourceTable());
372 ZeroOutAppReferences(apk_b->GetResourceTable());
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700373
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700374 if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700375 // We emitted a diff, so return 1 (failure).
376 return 1;
377 }
378 return 0;
Adam Lesinski458b8772016-04-25 14:20:21 -0700379}
380
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700381} // namespace aapt