main.cpp 12 KB

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