1 /* 2 * Copyright (C) 2017 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 17 #include <getopt.h> 18 19 #include <android-base/strings.h> 20 #include <vintf/VintfObject.h> 21 #include <vintf/parse_string.h> 22 #include <vintf/parse_xml.h> 23 #include <iomanip> 24 #include <iostream> 25 #include <string> 26 #include <vector> 27 28 using namespace ::android::vintf; 29 30 static const std::string kColumnSeperator = " "; 31 32 std::string existString(bool value) { 33 return value ? "GOOD" : "DOES NOT EXIST"; 34 } 35 36 std::string compatibleString(int32_t value) { 37 switch (value) { 38 case COMPATIBLE: 39 return "GOOD"; 40 case INCOMPATIBLE: 41 return "INCOMPATIBLE"; 42 default: 43 return strerror(-value); 44 } 45 } 46 47 std::string boolCompatString(bool value) { 48 return compatibleString(value ? COMPATIBLE : INCOMPATIBLE); 49 } 50 51 std::string deprecateString(int32_t value) { 52 switch (value) { 53 case NO_DEPRECATED_HALS: 54 return "GOOD"; 55 case DEPRECATED: 56 return "DEPRECATED"; 57 default: 58 return strerror(-value); 59 } 60 } 61 62 enum Status : int { 63 OK = 0, 64 USAGE, 65 }; 66 67 struct ParsedOptions { 68 bool verbose = false; 69 }; 70 71 struct Option { 72 char shortOption = '\0'; 73 std::string longOption; 74 std::string help; 75 std::function<Status(ParsedOptions*)> op; 76 }; 77 78 std::string getShortOptions(const std::vector<Option>& options) { 79 std::stringstream ret; 80 for (const auto& e : options) 81 if (e.shortOption != '\0') ret << e.shortOption; 82 return ret.str(); 83 } 84 85 std::unique_ptr<struct option[]> getLongOptions(const std::vector<Option>& options, 86 int* longOptFlag) { 87 std::unique_ptr<struct option[]> ret{new struct option[options.size() + 1]}; 88 int i = 0; 89 for (const auto& e : options) { 90 ret[i].name = e.longOption.c_str(); 91 ret[i].has_arg = no_argument; 92 ret[i].flag = longOptFlag; 93 ret[i].val = i; 94 95 i++; 96 } 97 // getopt_long last option has all zeros 98 ret[i].name = NULL; 99 ret[i].has_arg = 0; 100 ret[i].flag = NULL; 101 ret[i].val = 0; 102 103 return ret; 104 } 105 106 Status parseOptions(int argc, char** argv, const std::vector<Option>& options, ParsedOptions* out) { 107 int longOptFlag; 108 std::unique_ptr<struct option[]> longOptions = getLongOptions(options, &longOptFlag); 109 std::string shortOptions = getShortOptions(options); 110 int optionIndex; 111 for (;;) { 112 int c = getopt_long(argc, argv, shortOptions.c_str(), longOptions.get(), &optionIndex); 113 if (c == -1) { 114 break; 115 } 116 const Option* found = nullptr; 117 for (size_t i = 0; i < options.size(); ++i) 118 if ((c == 0 && longOptFlag == static_cast<int>(i)) || 119 (c != 0 && c == options[i].shortOption)) 120 121 found = &options[i]; 122 123 if (found == nullptr) { 124 // see unrecognized options 125 std::cerr << "unrecognized option `" << argv[optind - 1] << "'" << std::endl; 126 return USAGE; 127 } 128 129 Status status = found->op(out); 130 if (status != OK) return status; 131 } 132 if (optind < argc) { 133 // see non option 134 std::cerr << "unrecognized option `" << argv[optind] << "'" << std::endl; 135 return USAGE; 136 } 137 return OK; 138 } 139 140 void usage(char* me, const std::vector<Option>& options) { 141 std::cerr << me << ": dump VINTF metadata via libvintf." << std::endl; 142 for (const auto& e : options) { 143 if (e.help.empty()) continue; 144 std::cerr << " "; 145 if (e.shortOption != '\0') std::cerr << "-" << e.shortOption; 146 if (e.shortOption != '\0' && !e.longOption.empty()) std::cerr << ", "; 147 if (!e.longOption.empty()) std::cerr << "--" << e.longOption; 148 std::cerr << ": " 149 << android::base::Join(android::base::Split(e.help, "\n"), "\n ") 150 << std::endl; 151 } 152 } 153 154 struct TableRow { 155 // Whether the HAL version is in device manifest, framework manifest, device compatibility 156 // matrix, framework compatibility matrix, respectively. 157 bool dm = false; 158 bool fm = false; 159 bool dcm = false; 160 bool fcm = false; 161 // If the HAL version is in device / framework compatibility matrix, whether it is required 162 // or not. 163 bool required = false; 164 165 // Return true if: 166 // - not a required HAL version; OR 167 // - required in device matrix and framework manifest; 168 // - required in framework matrix and device manifest. 169 bool meetsReqeuirement() const { 170 if (!required) return true; 171 if (dcm && !fm) return false; 172 if (fcm && !dm) return false; 173 return true; 174 } 175 }; 176 177 std::ostream& operator<<(std::ostream& out, const TableRow& row) { 178 return out << (row.required ? "R" : " ") << (row.meetsReqeuirement() ? " " : "!") 179 << kColumnSeperator << (row.dm ? "DM" : " ") << kColumnSeperator 180 << (row.fm ? "FM" : " ") << kColumnSeperator << (row.fcm ? "FCM" : " ") 181 << kColumnSeperator << (row.dcm ? "DCM" : " "); 182 } 183 184 using RowMutator = std::function<void(TableRow*)>; 185 using Table = std::map<std::string, TableRow>; 186 187 // Insert each fqInstanceName foo (at) x.y::IFoo/instance to the table by inserting the key 188 // if it does not exist and setting the corresponding indicator (as specified by "mutate"). 189 void insert(const HalManifest* manifest, Table* table, const RowMutator& mutate) { 190 if (manifest == nullptr) return; 191 manifest->forEachInstance([&](const auto& manifestInstance) { 192 std::string key = toFQNameString(manifestInstance.package(), manifestInstance.version(), 193 manifestInstance.interface(), manifestInstance.instance()); 194 mutate(&(*table)[key]); 195 return true; 196 }); 197 } 198 199 void insert(const CompatibilityMatrix* matrix, Table* table, const RowMutator& mutate) { 200 if (matrix == nullptr) return; 201 matrix->forEachInstance([&](const auto& matrixInstance) { 202 for (auto minorVer = matrixInstance.versionRange().minMinor; 203 minorVer <= matrixInstance.versionRange().maxMinor; ++minorVer) { 204 std::string key = toFQNameString( 205 matrixInstance.package(), Version{matrixInstance.versionRange().majorVer, minorVer}, 206 matrixInstance.interface(), 207 matrixInstance.isRegex() ? matrixInstance.regexPattern() 208 : matrixInstance.exactInstance()); 209 auto it = table->find(key); 210 if (it == table->end()) { 211 mutate(&(*table)[key]); 212 } else { 213 mutate(&it->second); 214 if (minorVer == matrixInstance.versionRange().minMinor) { 215 it->second.required = !matrixInstance.optional(); 216 } 217 } 218 } 219 return true; 220 }); 221 } 222 223 Table generateHalSummary(const HalManifest* vm, const HalManifest* fm, 224 const CompatibilityMatrix* vcm, const CompatibilityMatrix* fcm) { 225 Table table; 226 insert(vm, &table, [](auto* row) { row->dm = true; }); 227 insert(fm, &table, [](auto* row) { row->fm = true; }); 228 insert(vcm, &table, [](auto* row) { row->dcm = true; }); 229 insert(fcm, &table, [](auto* row) { row->fcm = true; }); 230 231 return table; 232 } 233 234 static const std::vector<Option> gAvailableOptions{ 235 {'h', "help", "Print help message.", [](auto) { return USAGE; }}, 236 {'v', "verbose", "Dump detailed and raw content, including kernel configurations", [](auto o) { 237 o->verbose = true; 238 return OK; 239 }}}; 240 // A convenience binary to dump information available through libvintf. 241 int main(int argc, char** argv) { 242 ParsedOptions options; 243 Status status = parseOptions(argc, argv, gAvailableOptions, &options); 244 if (status == USAGE) usage(argv[0], gAvailableOptions); 245 if (status != OK) return status; 246 247 auto vm = VintfObject::GetDeviceHalManifest(); 248 auto fm = VintfObject::GetFrameworkHalManifest(); 249 auto vcm = VintfObject::GetDeviceCompatibilityMatrix(); 250 auto fcm = VintfObject::GetFrameworkCompatibilityMatrix(); 251 auto ki = VintfObject::GetRuntimeInfo(); 252 253 if (!options.verbose) { 254 std::cout << "======== HALs =========" << std::endl 255 << "R: required. (empty): optional or missing from matrices. " 256 << "!: required and not in manifest." << std::endl 257 << "DM: device manifest. FM: framework manifest." << std::endl 258 << "FCM: framework compatibility matrix. DCM: device compatibility matrix." 259 << std::endl 260 << std::endl; 261 auto table = generateHalSummary(vm.get(), fm.get(), vcm.get(), fcm.get()); 262 263 for (const auto& pair : table) 264 std::cout << pair.second << kColumnSeperator << pair.first << std::endl; 265 266 std::cout << std::endl; 267 } 268 269 SerializeFlags flags = SerializeFlag::EVERYTHING; 270 if (!options.verbose) { 271 flags |= SerializeFlag::NO_HALS; 272 flags |= SerializeFlag::NO_KERNEL; 273 } 274 std::cout << "======== Device HAL Manifest =========" << std::endl; 275 if (vm != nullptr) std::cout << gHalManifestConverter(*vm, flags); 276 std::cout << "======== Framework HAL Manifest =========" << std::endl; 277 if (fm != nullptr) std::cout << gHalManifestConverter(*fm, flags); 278 std::cout << "======== Device Compatibility Matrix =========" << std::endl; 279 if (vcm != nullptr) std::cout << gCompatibilityMatrixConverter(*vcm, flags); 280 std::cout << "======== Framework Compatibility Matrix =========" << std::endl; 281 if (fcm != nullptr) std::cout << gCompatibilityMatrixConverter(*fcm, flags); 282 283 std::cout << "======== Runtime Info =========" << std::endl; 284 if (ki != nullptr) std::cout << dump(*ki, options.verbose); 285 286 std::cout << std::endl; 287 288 std::cout << "======== Summary =========" << std::endl; 289 std::cout << "Device Manifest? " << existString(vm != nullptr) << std::endl 290 << "Device Matrix? " << existString(vcm != nullptr) << std::endl 291 << "Framework Manifest? " << existString(fm != nullptr) << std::endl 292 << "Framework Matrix? " << existString(fcm != nullptr) << std::endl; 293 std::string error; 294 if (vm && fcm) { 295 bool compatible = vm->checkCompatibility(*fcm, &error); 296 std::cout << "Device HAL Manifest <==> Framework Compatibility Matrix? " 297 << boolCompatString(compatible); 298 if (!compatible) 299 std::cout << ", " << error; 300 std::cout << std::endl; 301 } 302 if (fm && vcm) { 303 bool compatible = fm->checkCompatibility(*vcm, &error); 304 std::cout << "Framework HAL Manifest <==> Device Compatibility Matrix? " 305 << boolCompatString(compatible); 306 if (!compatible) 307 std::cout << ", " << error; 308 std::cout << std::endl; 309 } 310 if (ki && fcm) { 311 bool compatible = ki->checkCompatibility(*fcm, &error); 312 std::cout << "Runtime info <==> Framework Compatibility Matrix? " 313 << boolCompatString(compatible); 314 if (!compatible) std::cout << ", " << error; 315 std::cout << std::endl; 316 } 317 318 { 319 auto compatible = VintfObject::CheckCompatibility({}, &error); 320 std::cout << "VintfObject::CheckCompatibility? " 321 << compatibleString(compatible); 322 if (compatible != COMPATIBLE) std::cout << ", " << error; 323 std::cout << std::endl; 324 } 325 326 if (vm && fcm) { 327 auto deprecate = VintfObject::CheckDeprecation(&error); 328 std::cout << "VintfObject::CheckDeprecation (against device manifest)? " 329 << deprecateString(deprecate); 330 if (deprecate != NO_DEPRECATED_HALS) std::cout << ", " << error; 331 std::cout << std::endl; 332 } 333 } 334