1458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski/* 2458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * Copyright (C) 2016 The Android Open Source Project 3458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * 4458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * you may not use this file except in compliance with the License. 6458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * You may obtain a copy of the License at 7458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * 8458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * 10458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * See the License for the specific language governing permissions and 14458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * limitations under the License. 15458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski */ 16458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 17ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "android-base/macros.h" 18ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 19458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski#include "Flags.h" 20ff759e6a6ef6dd741b174e58a0f01cb87accc897Pierre Lecesne#include "LoadedApk.h" 215e8fa3a24835a1ad39f758f630a61c83133eabf8Adam Lesinski#include "ValueVisitor.h" 22458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski#include "process/IResourceTableConsumer.h" 23458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski#include "process/SymbolTable.h" 24458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 25d3ffa844f5a07756009f019e13806e253d1bb119Adam Lesinskiusing ::android::StringPiece; 26d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski 27458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinskinamespace aapt { 28458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 29458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinskiclass DiffContext : public IAaptContext { 30cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski public: 31d0f492db038c6210c1138865d816bfb134376538Adam Lesinski DiffContext() : name_mangler_({}), symbol_table_(&name_mangler_) { 32d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 33ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 34b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski PackageType GetPackageType() override { 35b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski // Doesn't matter. 36b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski return PackageType::kApp; 37b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski } 38b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski 39d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const std::string& GetCompilationPackage() override { 40d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return empty_; 41d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 42458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 43d0f492db038c6210c1138865d816bfb134376538Adam Lesinski uint8_t GetPackageId() override { 44d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return 0x0; 45d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 46458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 47d0f492db038c6210c1138865d816bfb134376538Adam Lesinski IDiagnostics* GetDiagnostics() override { 48d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return &diagnostics_; 49d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 50458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 51d0f492db038c6210c1138865d816bfb134376538Adam Lesinski NameMangler* GetNameMangler() override { 52d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return &name_mangler_; 53d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 54458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 55d0f492db038c6210c1138865d816bfb134376538Adam Lesinski SymbolTable* GetExternalSymbols() override { 56d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return &symbol_table_; 57d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 58458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 59d0f492db038c6210c1138865d816bfb134376538Adam Lesinski bool IsVerbose() override { 60d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return false; 61d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 62458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 63d0f492db038c6210c1138865d816bfb134376538Adam Lesinski int GetMinSdkVersion() override { 64d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return 0; 65d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 66fb6312fe93a8544e6a95d1c619c8cea3940cbe1aAdam Lesinski 67cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski private: 68ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string empty_; 69ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StdErrDiagnostics diagnostics_; 70ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski NameMangler name_mangler_; 71ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski SymbolTable symbol_table_; 72458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski}; 73458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 74ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic void EmitDiffLine(const Source& source, const StringPiece& message) { 75cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::cerr << source << ": " << message << "\n"; 76458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 77458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 7871be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinskistatic bool IsSymbolVisibilityDifferent(const Visibility& vis_a, const Visibility& vis_b) { 7971be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski return vis_a.level != vis_b.level; 80458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 81458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 82458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinskitemplate <typename Id> 8371be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinskistatic bool IsIdDiff(const Visibility::Level& level_a, const Maybe<Id>& id_a, 8471be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski const Visibility::Level& level_b, const Maybe<Id>& id_b) { 8571be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski if (level_a == Visibility::Level::kPublic || level_b == Visibility::Level::kPublic) { 86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return id_a != id_b; 87cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 88cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 89458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 90458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 91d0f492db038c6210c1138865d816bfb134376538Adam Lesinskistatic bool EmitResourceConfigValueDiff(IAaptContext* context, LoadedApk* apk_a, 92d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceTablePackage* pkg_a, ResourceTableType* type_a, 93d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceEntry* entry_a, ResourceConfigValue* config_value_a, 94d0f492db038c6210c1138865d816bfb134376538Adam Lesinski LoadedApk* apk_b, ResourceTablePackage* pkg_b, 95d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceTableType* type_b, ResourceEntry* entry_b, 96d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceConfigValue* config_value_b) { 97ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Value* value_a = config_value_a->value.get(); 98ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Value* value_b = config_value_b->value.get(); 99ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!value_a->Equals(value_b)) { 100ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 101d0f492db038c6210c1138865d816bfb134376538Adam Lesinski str_stream << "value " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name 102d0f492db038c6210c1138865d816bfb134376538Adam Lesinski << " config=" << config_value_a->config << " does not match:\n"; 103ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value_a->Print(&str_stream); 104ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "\n vs \n"; 105ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value_b->Print(&str_stream); 106ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 108cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 109cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 110458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 111458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 112ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a, 113d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceTablePackage* pkg_a, ResourceTableType* type_a, 114ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceEntry* entry_a, LoadedApk* apk_b, 115d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceTablePackage* pkg_b, ResourceTableType* type_b, 116ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceEntry* entry_b) { 117cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool diff = false; 118ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) { 119d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceConfigValue* config_value_b = entry_b->FindValue(config_value_a->config); 120ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!config_value_b) { 121ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 122d0f492db038c6210c1138865d816bfb134376538Adam Lesinski str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name 123d0f492db038c6210c1138865d816bfb134376538Adam Lesinski << " config=" << config_value_a->config; 124ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 125cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 126cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 127d0f492db038c6210c1138865d816bfb134376538Adam Lesinski diff |= 128d0f492db038c6210c1138865d816bfb134376538Adam Lesinski EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a.get(), 129d0f492db038c6210c1138865d816bfb134376538Adam Lesinski apk_b, pkg_b, type_b, entry_b, config_value_b); 130458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 131cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 133cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Check for any newly added config values. 134ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) { 135d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceConfigValue* config_value_a = entry_a->FindValue(config_value_b->config); 136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!config_value_a) { 137ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 138d0f492db038c6210c1138865d816bfb134376538Adam Lesinski str_stream << "new config " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name 139d0f492db038c6210c1138865d816bfb134376538Adam Lesinski << " config=" << config_value_b->config; 140ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 141cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 142458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 143cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 144cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 145458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 146458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 147ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a, 148d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceTablePackage* pkg_a, ResourceTableType* type_a, 149d0f492db038c6210c1138865d816bfb134376538Adam Lesinski LoadedApk* apk_b, ResourceTablePackage* pkg_b, 150ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTableType* type_b) { 151cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool diff = false; 152ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (std::unique_ptr<ResourceEntry>& entry_a : type_a->entries) { 153ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceEntry* entry_b = type_b->FindEntry(entry_a->name); 154ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!entry_b) { 155ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 156d0f492db038c6210c1138865d816bfb134376538Adam Lesinski str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name; 157ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 158cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 159cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 16071be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski if (IsSymbolVisibilityDifferent(entry_a->visibility, entry_b->visibility)) { 161ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 162ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name 163ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski << " has different visibility ("; 16471be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski if (entry_b->visibility.level == Visibility::Level::kPublic) { 165ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "PUBLIC"; 166458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } else { 167ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "PRIVATE"; 168458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 169ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << " vs "; 17071be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski if (entry_a->visibility.level == Visibility::Level::kPublic) { 171ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "PUBLIC"; 172cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 173ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "PRIVATE"; 174458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 175ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << ")"; 176ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 177cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 17871be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski } else if (IsIdDiff(entry_a->visibility.level, entry_a->id, entry_b->visibility.level, 179d0f492db038c6210c1138865d816bfb134376538Adam Lesinski entry_b->id)) { 180ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 181ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name 182ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski << " has different public ID ("; 183ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (entry_b->id) { 184ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "0x" << std::hex << entry_b->id.value(); 185cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 186ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "none"; 187cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 188ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << " vs "; 189ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (entry_a->id) { 190ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "0x " << std::hex << entry_a->id.value(); 191cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 192ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "none"; 193cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 194ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << ")"; 195ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 196cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 197cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 198d0f492db038c6210c1138865d816bfb134376538Adam Lesinski diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a.get(), apk_b, pkg_b, 199d0f492db038c6210c1138865d816bfb134376538Adam Lesinski type_b, entry_b); 200cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 202cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 203cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Check for any newly added entries. 204ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (std::unique_ptr<ResourceEntry>& entry_b : type_b->entries) { 205ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceEntry* entry_a = type_a->FindEntry(entry_b->name); 206ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!entry_a) { 207ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 208d0f492db038c6210c1138865d816bfb134376538Adam Lesinski str_stream << "new entry " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name; 209ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 210cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 211458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 212cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 213cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return diff; 214458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 215458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 216ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a, 217d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceTablePackage* pkg_a, LoadedApk* apk_b, 218ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTablePackage* pkg_b) { 219cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool diff = false; 220ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (std::unique_ptr<ResourceTableType>& type_a : pkg_a->types) { 221ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTableType* type_b = pkg_b->FindType(type_a->type); 222ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!type_b) { 223ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 224ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "missing " << pkg_a->name << ":" << type_a->type; 225ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_a->GetSource(), str_stream.str()); 226cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 227cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 22871be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski if (type_a->visibility_level != type_b->visibility_level) { 229ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 230d0f492db038c6210c1138865d816bfb134376538Adam Lesinski str_stream << pkg_a->name << ":" << type_a->type << " has different visibility ("; 23171be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski if (type_b->visibility_level == Visibility::Level::kPublic) { 232ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "PUBLIC"; 233458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } else { 234ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "PRIVATE"; 235458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 236ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << " vs "; 23771be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski if (type_a->visibility_level == Visibility::Level::kPublic) { 238ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "PUBLIC"; 239cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 240ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "PRIVATE"; 241458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 242ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << ")"; 243ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 244cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 24571be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski } else if (IsIdDiff(type_a->visibility_level, type_a->id, type_b->visibility_level, 24671be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski type_b->id)) { 247ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 248d0f492db038c6210c1138865d816bfb134376538Adam Lesinski str_stream << pkg_a->name << ":" << type_a->type << " has different public ID ("; 249ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_b->id) { 250ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "0x" << std::hex << type_b->id.value(); 251cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 252ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "none"; 253cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 254ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << " vs "; 255ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_a->id) { 256ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "0x " << std::hex << type_a->id.value(); 257cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 258ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "none"; 259cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 260ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << ")"; 261ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 262cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 263cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 264d0f492db038c6210c1138865d816bfb134376538Adam Lesinski diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a.get(), apk_b, pkg_b, type_b); 265cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 266cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 267cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 268cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Check for any newly added types. 269ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (std::unique_ptr<ResourceTableType>& type_b : pkg_b->types) { 270ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTableType* type_a = pkg_a->FindType(type_b->type); 271ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!type_a) { 272ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 273ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "new type " << pkg_b->name << ":" << type_b->type; 274ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 275cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 276458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 277cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 278cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return diff; 279458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 280458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 281d0f492db038c6210c1138865d816bfb134376538Adam Lesinskistatic bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) { 282ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTable* table_a = apk_a->GetResourceTable(); 283ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTable* table_b = apk_b->GetResourceTable(); 284cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 285cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool diff = false; 286ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (std::unique_ptr<ResourceTablePackage>& pkg_a : table_a->packages) { 287ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTablePackage* pkg_b = table_b->FindPackage(pkg_a->name); 288ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!pkg_b) { 289ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 290ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "missing package " << pkg_a->name; 291ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 292cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 293cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 294ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (pkg_a->id != pkg_b->id) { 295ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 296ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "package '" << pkg_a->name << "' has different id ("; 297ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (pkg_b->id) { 298ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "0x" << std::hex << pkg_b->id.value(); 299458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } else { 300ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "none"; 301458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 302ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << " vs "; 303ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (pkg_a->id) { 304ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "0x" << std::hex << pkg_a->id.value(); 305cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 306ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "none"; 307458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 308ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << ")"; 309ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 310cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 311cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 312d0f492db038c6210c1138865d816bfb134376538Adam Lesinski diff |= EmitResourcePackageDiff(context, apk_a, pkg_a.get(), apk_b, pkg_b); 313cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 314cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 315cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 316cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Check for any newly added packages. 317ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (std::unique_ptr<ResourceTablePackage>& pkg_b : table_b->packages) { 318ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTablePackage* pkg_a = table_a->FindPackage(pkg_b->name); 319ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!pkg_a) { 320ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream str_stream; 321ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str_stream << "new package " << pkg_b->name; 322ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 323cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski diff = true; 324458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski } 325cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 326cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return diff; 327458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 328458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 329d3ffa844f5a07756009f019e13806e253d1bb119Adam Lesinskiclass ZeroingReferenceVisitor : public DescendingValueVisitor { 330cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski public: 331d3ffa844f5a07756009f019e13806e253d1bb119Adam Lesinski using DescendingValueVisitor::Visit; 332cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 333ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski void Visit(Reference* ref) override { 334cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (ref->name && ref->id) { 335f34b6f4f2b969b47a3f371eb9549e92ef1680d91Adam Lesinski if (ref->id.value().package_id() == kAppPackageId) { 336cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ref->id = {}; 337cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 3385e8fa3a24835a1ad39f758f630a61c83133eabf8Adam Lesinski } 339cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 3405e8fa3a24835a1ad39f758f630a61c83133eabf8Adam Lesinski}; 3415e8fa3a24835a1ad39f758f630a61c83133eabf8Adam Lesinski 342ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic void ZeroOutAppReferences(ResourceTable* table) { 343cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ZeroingReferenceVisitor visitor; 344ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski VisitAllValuesInTable(table, &visitor); 3455e8fa3a24835a1ad39f758f630a61c83133eabf8Adam Lesinski} 3465e8fa3a24835a1ad39f758f630a61c83133eabf8Adam Lesinski 347ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiint Diff(const std::vector<StringPiece>& args) { 348cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski DiffContext context; 349cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 350cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Flags flags; 351ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!flags.Parse("aapt2 diff", args, &std::cerr)) { 352cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 1; 353cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 354cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 355ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (flags.GetArgs().size() != 2u) { 356cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::cerr << "must have two apks as arguments.\n\n"; 357ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski flags.Usage("aapt2 diff", &std::cerr); 358cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 1; 359cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 360cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 3618780eb6e4918ae24fb1ae74d631042c32e41dc3dAdam Lesinski IDiagnostics* diag = context.GetDiagnostics(); 3628780eb6e4918ae24fb1ae74d631042c32e41dc3dAdam Lesinski std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(flags.GetArgs()[0], diag); 3638780eb6e4918ae24fb1ae74d631042c32e41dc3dAdam Lesinski std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(flags.GetArgs()[1], diag); 364ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!apk_a || !apk_b) { 365cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 1; 366cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 367cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 368cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Zero out Application IDs in references. 369ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ZeroOutAppReferences(apk_a->GetResourceTable()); 370ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ZeroOutAppReferences(apk_b->GetResourceTable()); 371cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 372ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) { 373cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // We emitted a diff, so return 1 (failure). 374cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 1; 375cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 376cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 0; 377458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 378458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 379cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} // namespace aapt 380