Diff.cpp revision 71be70507de9cb619b644e55eda1cc181e3f7e90
1776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski/* 2776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * Copyright (C) 2016 The Android Open Source Project 3776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * 4776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * you may not use this file except in compliance with the License. 6776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * You may obtain a copy of the License at 7776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * 8776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * 10776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * Unless required by applicable law or agreed to in writing, software 11776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * See the License for the specific language governing permissions and 14776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski * limitations under the License. 15776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski */ 16776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 17776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski#include "android-base/macros.h" 18776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 19776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski#include "Flags.h" 20776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski#include "LoadedApk.h" 21776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski#include "ValueVisitor.h" 22776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski#include "process/IResourceTableConsumer.h" 23776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski#include "process/SymbolTable.h" 24776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 25776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskiusing ::android::StringPiece; 26776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 27776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskinamespace aapt { 28776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 29776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskiclass DiffContext : public IAaptContext { 30776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski public: 31776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski DiffContext() : name_mangler_({}), symbol_table_(&name_mangler_) { 32776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 33776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 34776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski PackageType GetPackageType() override { 35776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski // Doesn't matter. 36776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return PackageType::kApp; 37776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 38776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 39776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski const std::string& GetCompilationPackage() override { 40776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return empty_; 41776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 42776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 43776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski uint8_t GetPackageId() override { 44776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return 0x0; 45776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 46776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 47776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski IDiagnostics* GetDiagnostics() override { 48776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return &diagnostics_; 49776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 50776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 51776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski NameMangler* GetNameMangler() override { 52776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return &name_mangler_; 53776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 54776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 55776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski SymbolTable* GetExternalSymbols() override { 56776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return &symbol_table_; 57776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 58776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 59776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski bool IsVerbose() override { 60776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return false; 61776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 62776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 63776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski int GetMinSdkVersion() override { 64776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return 0; 65776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 66776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 67776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski private: 68776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski std::string empty_; 69776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski StdErrDiagnostics diagnostics_; 70776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski NameMangler name_mangler_; 71776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski SymbolTable symbol_table_; 72776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski}; 73776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 74776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskistatic void EmitDiffLine(const Source& source, const StringPiece& message) { 75776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski std::cerr << source << ": " << message << "\n"; 76776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski} 77776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 78776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskistatic bool IsSymbolVisibilityDifferent(const Visibility& vis_a, const Visibility& vis_b) { 79776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return vis_a.level != vis_b.level; 80776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski} 81776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 82776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskitemplate <typename Id> 83776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskistatic bool IsIdDiff(const Visibility::Level& level_a, const Maybe<Id>& id_a, 84776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski const Visibility::Level& level_b, const Maybe<Id>& id_b) { 85776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (level_a == Visibility::Level::kPublic || level_b == Visibility::Level::kPublic) { 86776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return id_a != id_b; 87776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 88776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return false; 89776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski} 90776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 91776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskistatic bool EmitResourceConfigValueDiff(IAaptContext* context, LoadedApk* apk_a, 92776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceTablePackage* pkg_a, ResourceTableType* type_a, 93776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceEntry* entry_a, ResourceConfigValue* config_value_a, 94776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski LoadedApk* apk_b, ResourceTablePackage* pkg_b, 95776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceTableType* type_b, ResourceEntry* entry_b, 96776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceConfigValue* config_value_b) { 97776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski Value* value_a = config_value_a->value.get(); 98776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski Value* value_b = config_value_b->value.get(); 99776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (!value_a->Equals(value_b)) { 100dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu std::stringstream str_stream; 101dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu str_stream << "value " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name 102dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu << " config=" << config_value_a->config << " does not match:\n"; 103dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu value_a->Print(&str_stream); 104dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu str_stream << "\n vs \n"; 105dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu value_b->Print(&str_stream); 106dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu EmitDiffLine(apk_b->GetSource(), str_stream.str()); 107dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu return true; 108dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu } 109dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu return false; 110dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu} 111dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu 112dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhustatic bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a, 113dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu ResourceTablePackage* pkg_a, ResourceTableType* type_a, 114dbee9bb342cdfaa5155b1918f90262c05e2464cbTeng-Hui Zhu ResourceEntry* entry_a, LoadedApk* apk_b, 115776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceTablePackage* pkg_b, ResourceTableType* type_b, 116776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceEntry* entry_b) { 117776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski bool diff = false; 118776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski for (std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) { 119776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceConfigValue* config_value_b = entry_b->FindValue(config_value_a->config); 120776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (!config_value_b) { 121776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski std::stringstream str_stream; 122776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name 123776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski << " config=" << config_value_a->config; 124776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 125776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski diff = true; 126776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } else { 127776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski diff |= 128776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a.get(), 129776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski apk_b, pkg_b, type_b, entry_b, config_value_b); 130776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 131776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 132776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 133776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski // Check for any newly added config values. 134776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski for (std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) { 135776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceConfigValue* config_value_a = entry_a->FindValue(config_value_b->config); 136776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (!config_value_a) { 137776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski std::stringstream str_stream; 138776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "new config " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name 139776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski << " config=" << config_value_b->config; 140776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 141776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski diff = true; 142776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 143776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 144776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return false; 145776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski} 146776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 147776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskistatic bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a, 148776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceTablePackage* pkg_a, ResourceTableType* type_a, 149776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski LoadedApk* apk_b, ResourceTablePackage* pkg_b, 150776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceTableType* type_b) { 151776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski bool diff = false; 152776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski for (std::unique_ptr<ResourceEntry>& entry_a : type_a->entries) { 153776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceEntry* entry_b = type_b->FindEntry(entry_a->name); 154776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (!entry_b) { 155776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski std::stringstream str_stream; 156776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "missing " << pkg_a->name << ":" << type_a->type << "/" << entry_a->name; 157776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 158776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski diff = true; 159776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } else { 160776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (IsSymbolVisibilityDifferent(entry_a->visibility, entry_b->visibility)) { 161776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski std::stringstream str_stream; 162776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name 163776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski << " has different visibility ("; 164776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (entry_b->visibility.level == Visibility::Level::kPublic) { 165776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "PUBLIC"; 166776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } else { 167776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "PRIVATE"; 168776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 169776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << " vs "; 170776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (entry_a->visibility.level == Visibility::Level::kPublic) { 171776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "PUBLIC"; 172776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } else { 173776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "PRIVATE"; 174776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 175776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << ")"; 176776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 177776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski diff = true; 178776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } else if (IsIdDiff(entry_a->visibility.level, entry_a->id, entry_b->visibility.level, 179776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski entry_b->id)) { 180776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski std::stringstream str_stream; 181776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << pkg_a->name << ":" << type_a->type << "/" << entry_a->name 182776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski << " has different public ID ("; 183776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (entry_b->id) { 184776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "0x" << std::hex << entry_b->id.value(); 185776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } else { 186776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "none"; 187776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 188776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << " vs "; 189776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (entry_a->id) { 190776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "0x " << std::hex << entry_a->id.value(); 191776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } else { 192776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "none"; 193776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 194776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << ")"; 195776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 196776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski diff = true; 197776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 198776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a.get(), apk_b, pkg_b, 199776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski type_b, entry_b); 200776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 201776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 202776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 203776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski // Check for any newly added entries. 204776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski for (std::unique_ptr<ResourceEntry>& entry_b : type_b->entries) { 205776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski ResourceEntry* entry_a = type_a->FindEntry(entry_b->name); 206776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (!entry_a) { 207776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski std::stringstream str_stream; 208776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski str_stream << "new entry " << pkg_b->name << ":" << type_b->type << "/" << entry_b->name; 209776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski EmitDiffLine(apk_b->GetSource(), str_stream.str()); 210776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski diff = true; 211776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 212 } 213 return diff; 214} 215 216static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a, 217 ResourceTablePackage* pkg_a, LoadedApk* apk_b, 218 ResourceTablePackage* pkg_b) { 219 bool diff = false; 220 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()); 226 diff = true; 227 } else { 228 if (type_a->visibility_level != type_b->visibility_level) { 229 std::stringstream str_stream; 230 str_stream << pkg_a->name << ":" << type_a->type << " has different visibility ("; 231 if (type_b->visibility_level == Visibility::Level::kPublic) { 232 str_stream << "PUBLIC"; 233 } else { 234 str_stream << "PRIVATE"; 235 } 236 str_stream << " vs "; 237 if (type_a->visibility_level == Visibility::Level::kPublic) { 238 str_stream << "PUBLIC"; 239 } else { 240 str_stream << "PRIVATE"; 241 } 242 str_stream << ")"; 243 EmitDiffLine(apk_b->GetSource(), str_stream.str()); 244 diff = true; 245 } else if (IsIdDiff(type_a->visibility_level, type_a->id, type_b->visibility_level, 246 type_b->id)) { 247 std::stringstream str_stream; 248 str_stream << pkg_a->name << ":" << type_a->type << " has different public ID ("; 249 if (type_b->id) { 250 str_stream << "0x" << std::hex << type_b->id.value(); 251 } else { 252 str_stream << "none"; 253 } 254 str_stream << " vs "; 255 if (type_a->id) { 256 str_stream << "0x " << std::hex << type_a->id.value(); 257 } else { 258 str_stream << "none"; 259 } 260 str_stream << ")"; 261 EmitDiffLine(apk_b->GetSource(), str_stream.str()); 262 diff = true; 263 } 264 diff |= EmitResourceTypeDiff(context, apk_a, pkg_a, type_a.get(), apk_b, pkg_b, type_b); 265 } 266 } 267 268 // Check for any newly added types. 269 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()); 275 diff = true; 276 } 277 } 278 return diff; 279} 280 281static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) { 282 ResourceTable* table_a = apk_a->GetResourceTable(); 283 ResourceTable* table_b = apk_b->GetResourceTable(); 284 285 bool diff = false; 286 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()); 292 diff = true; 293 } else { 294 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(); 299 } else { 300 str_stream << "none"; 301 } 302 str_stream << " vs "; 303 if (pkg_a->id) { 304 str_stream << "0x" << std::hex << pkg_a->id.value(); 305 } else { 306 str_stream << "none"; 307 } 308 str_stream << ")"; 309 EmitDiffLine(apk_b->GetSource(), str_stream.str()); 310 diff = true; 311 } 312 diff |= EmitResourcePackageDiff(context, apk_a, pkg_a.get(), apk_b, pkg_b); 313 } 314 } 315 316 // Check for any newly added packages. 317 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()); 323 diff = true; 324 } 325 } 326 return diff; 327} 328 329class ZeroingReferenceVisitor : public DescendingValueVisitor { 330 public: 331 using DescendingValueVisitor::Visit; 332 333 void Visit(Reference* ref) override { 334 if (ref->name && ref->id) { 335 if (ref->id.value().package_id() == kAppPackageId) { 336 ref->id = {}; 337 } 338 } 339 } 340}; 341 342static void ZeroOutAppReferences(ResourceTable* table) { 343 ZeroingReferenceVisitor visitor; 344 VisitAllValuesInTable(table, &visitor); 345} 346 347int Diff(const std::vector<StringPiece>& args) { 348 DiffContext context; 349 350 Flags flags; 351 if (!flags.Parse("aapt2 diff", args, &std::cerr)) { 352 return 1; 353 } 354 355 if (flags.GetArgs().size() != 2u) { 356 std::cerr << "must have two apks as arguments.\n\n"; 357 flags.Usage("aapt2 diff", &std::cerr); 358 return 1; 359 } 360 361 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); 364 if (!apk_a || !apk_b) { 365 return 1; 366 } 367 368 // Zero out Application IDs in references. 369 ZeroOutAppReferences(apk_a->GetResourceTable()); 370 ZeroOutAppReferences(apk_b->GetResourceTable()); 371 372 if (EmitResourceTableDiff(&context, apk_a.get(), apk_b.get())) { 373 // We emitted a diff, so return 1 (failure). 374 return 1; 375 } 376 return 0; 377} 378 379} // namespace aapt 380