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 <stdlib.h> 18 #include <unistd.h> 19 20 #include <fstream> 21 #include <iostream> 22 #include <sstream> 23 #include <string> 24 #include <unordered_map> 25 26 #include <android-base/file.h> 27 #include <android-base/parseint.h> 28 #include <android-base/strings.h> 29 30 #include <vintf/AssembleVintf.h> 31 #include <vintf/KernelConfigParser.h> 32 #include <vintf/parse_string.h> 33 #include <vintf/parse_xml.h> 34 #include "utils.h" 35 36 #define BUFFER_SIZE sysconf(_SC_PAGESIZE) 37 38 namespace android { 39 namespace vintf { 40 41 static const std::string gConfigPrefix = "android-base-"; 42 static const std::string gConfigSuffix = ".config"; 43 static const std::string gBaseConfig = "android-base.config"; 44 45 // An input stream with a name. 46 // The input stream may be an actual file, or a stringstream for testing. 47 // It takes ownership on the istream. 48 class NamedIstream { 49 public: 50 NamedIstream(const std::string& name, std::unique_ptr<std::istream>&& stream) 51 : mName(name), mStream(std::move(stream)) {} 52 const std::string& name() const { return mName; } 53 std::istream& stream() { return *mStream; } 54 55 private: 56 std::string mName; 57 std::unique_ptr<std::istream> mStream; 58 }; 59 60 /** 61 * Slurps the device manifest file and add build time flag to it. 62 */ 63 class AssembleVintfImpl : public AssembleVintf { 64 using Condition = std::unique_ptr<KernelConfig>; 65 using ConditionedConfig = std::pair<Condition, std::vector<KernelConfig> /* configs */>; 66 67 public: 68 void setFakeEnv(const std::string& key, const std::string& value) { mFakeEnv[key] = value; } 69 70 std::string getEnv(const std::string& key) const { 71 auto it = mFakeEnv.find(key); 72 if (it != mFakeEnv.end()) { 73 return it->second; 74 } 75 const char* envValue = getenv(key.c_str()); 76 return envValue != nullptr ? std::string(envValue) : std::string(); 77 } 78 79 // Get environment variable and split with space. 80 std::vector<std::string> getEnvList(const std::string& key) const { 81 std::vector<std::string> ret; 82 for (auto&& v : base::Split(getEnv(key), " ")) { 83 v = base::Trim(v); 84 if (!v.empty()) { 85 ret.push_back(v); 86 } 87 } 88 return ret; 89 } 90 91 template <typename T> 92 bool getFlag(const std::string& key, T* value, bool log = true) const { 93 std::string envValue = getEnv(key); 94 if (envValue.empty()) { 95 if (log) { 96 std::cerr << "Warning: " << key << " is missing, defaulted to " << (*value) << "." 97 << std::endl; 98 } 99 return true; 100 } 101 102 if (!parse(envValue, value)) { 103 std::cerr << "Cannot parse " << envValue << "." << std::endl; 104 return false; 105 } 106 return true; 107 } 108 109 /** 110 * Set *out to environment variable only if *out is a dummy value (i.e. default constructed). 111 * Return false if a fatal error has occurred: 112 * - The environment variable has an unknown format 113 * - The value of the environment variable does not match a predefined variable in the files 114 */ 115 template <typename T> 116 bool getFlagIfUnset(const std::string& envKey, T* out) const { 117 bool hasExistingValue = !(*out == T{}); 118 119 bool hasEnvValue = false; 120 T envValue; 121 std::string envStrValue = getEnv(envKey); 122 if (!envStrValue.empty()) { 123 if (!parse(envStrValue, &envValue)) { 124 std::cerr << "Cannot parse " << envValue << "." << std::endl; 125 return false; 126 } 127 hasEnvValue = true; 128 } 129 130 if (hasExistingValue) { 131 if (hasEnvValue && (*out != envValue)) { 132 std::cerr << "Cannot override existing value " << *out << " with " << envKey 133 << " (which is " << envValue << ")." << std::endl; 134 return false; 135 } 136 return true; 137 } 138 if (hasEnvValue) { 139 *out = envValue; 140 } 141 return true; 142 } 143 144 bool getBooleanFlag(const std::string& key) const { return getEnv(key) == std::string("true"); } 145 146 size_t getIntegerFlag(const std::string& key, size_t defaultValue = 0) const { 147 std::string envValue = getEnv(key); 148 if (envValue.empty()) { 149 return defaultValue; 150 } 151 size_t value; 152 if (!base::ParseUint(envValue, &value)) { 153 std::cerr << "Error: " << key << " must be a number." << std::endl; 154 return defaultValue; 155 } 156 return value; 157 } 158 159 static std::string read(std::basic_istream<char>& is) { 160 std::stringstream ss; 161 ss << is.rdbuf(); 162 return ss.str(); 163 } 164 165 // Return true if name of file is "android-base.config". This file must be specified 166 // exactly once for each kernel version. These requirements do not have any conditions. 167 static bool isCommonConfig(const std::string& path) { 168 return ::android::base::Basename(path) == gBaseConfig; 169 } 170 171 // Return true if name of file matches "android-base-foo.config". 172 // Zero or more conditional configs may be specified for each kernel version. These 173 // requirements are conditional on CONFIG_FOO=y. 174 static bool isConditionalConfig(const std::string& path) { 175 auto fname = ::android::base::Basename(path); 176 return ::android::base::StartsWith(fname, gConfigPrefix) && 177 ::android::base::EndsWith(fname, gConfigSuffix); 178 } 179 180 // Return true for all other file names (i.e. not android-base.config, and not conditional 181 // configs.) 182 // Zero or more conditional configs may be specified for each kernel version. 183 // These requirements do not have any conditions. 184 static bool isExtraCommonConfig(const std::string& path) { 185 return !isCommonConfig(path) && !isConditionalConfig(path); 186 } 187 188 // nullptr on any error, otherwise the condition. 189 static Condition generateCondition(const std::string& path) { 190 if (!isConditionalConfig(path)) { 191 return nullptr; 192 } 193 auto fname = ::android::base::Basename(path); 194 std::string sub = fname.substr(gConfigPrefix.size(), 195 fname.size() - gConfigPrefix.size() - gConfigSuffix.size()); 196 if (sub.empty()) { 197 return nullptr; // should not happen 198 } 199 for (size_t i = 0; i < sub.size(); ++i) { 200 if (sub[i] == '-') { 201 sub[i] = '_'; 202 continue; 203 } 204 if (isalnum(sub[i])) { 205 sub[i] = toupper(sub[i]); 206 continue; 207 } 208 std::cerr << "'" << fname << "' (in " << path 209 << ") is not a valid kernel config file name. Must match regex: " 210 << "android-base(-[0-9a-zA-Z-]+)?\\" << gConfigSuffix 211 << std::endl; 212 return nullptr; 213 } 214 sub.insert(0, "CONFIG_"); 215 return std::make_unique<KernelConfig>(std::move(sub), Tristate::YES); 216 } 217 218 static bool parseFileForKernelConfigs(std::basic_istream<char>& stream, 219 std::vector<KernelConfig>* out) { 220 KernelConfigParser parser(true /* processComments */, true /* relaxedFormat */); 221 status_t err = parser.processAndFinish(read(stream)); 222 if (err != OK) { 223 std::cerr << parser.error(); 224 return false; 225 } 226 227 for (auto& configPair : parser.configs()) { 228 out->push_back({}); 229 KernelConfig& config = out->back(); 230 config.first = std::move(configPair.first); 231 if (!parseKernelConfigTypedValue(configPair.second, &config.second)) { 232 std::cerr << "Unknown value type for key = '" << config.first << "', value = '" 233 << configPair.second << "'\n"; 234 return false; 235 } 236 } 237 return true; 238 } 239 240 static bool parseFilesForKernelConfigs(std::vector<NamedIstream>* streams, 241 std::vector<ConditionedConfig>* out) { 242 out->clear(); 243 ConditionedConfig commonConfig; 244 bool foundCommonConfig = false; 245 bool ret = true; 246 247 for (auto& namedStream : *streams) { 248 if (isCommonConfig(namedStream.name()) || isExtraCommonConfig(namedStream.name())) { 249 if (!parseFileForKernelConfigs(namedStream.stream(), &commonConfig.second)) { 250 std::cerr << "Failed to generate common configs for file " 251 << namedStream.name(); 252 ret = false; 253 } 254 if (isCommonConfig(namedStream.name())) { 255 foundCommonConfig = true; 256 } 257 } else { 258 Condition condition = generateCondition(namedStream.name()); 259 if (condition == nullptr) { 260 std::cerr << "Failed to generate conditional configs for file " 261 << namedStream.name(); 262 ret = false; 263 } 264 265 std::vector<KernelConfig> kernelConfigs; 266 if ((ret &= parseFileForKernelConfigs(namedStream.stream(), &kernelConfigs))) 267 out->emplace_back(std::move(condition), std::move(kernelConfigs)); 268 } 269 } 270 271 if (!foundCommonConfig) { 272 std::cerr << "No " << gBaseConfig << " is found in these paths:" << std::endl; 273 for (auto& namedStream : *streams) { 274 std::cerr << " " << namedStream.name() << std::endl; 275 } 276 ret = false; 277 } 278 // first element is always common configs (no conditions). 279 out->insert(out->begin(), std::move(commonConfig)); 280 return ret; 281 } 282 283 std::basic_ostream<char>& out() const { return mOutRef == nullptr ? std::cout : *mOutRef; } 284 285 // If -c is provided, check it. 286 bool checkDualFile(const HalManifest& manifest, const CompatibilityMatrix& matrix) { 287 if (getBooleanFlag("PRODUCT_ENFORCE_VINTF_MANIFEST")) { 288 std::string error; 289 if (!manifest.checkCompatibility(matrix, &error, mCheckFlags)) { 290 std::cerr << "Not compatible: " << error << std::endl; 291 return false; 292 } 293 } 294 return true; 295 } 296 297 template <typename S> 298 using Schemas = std::vector<Named<S>>; 299 using HalManifests = Schemas<HalManifest>; 300 using CompatibilityMatrices = Schemas<CompatibilityMatrix>; 301 302 template <typename M> 303 void outputInputs(const Schemas<M>& inputs) { 304 out() << "<!--" << std::endl; 305 out() << " Input:" << std::endl; 306 for (const auto& e : inputs) { 307 if (!e.name.empty()) { 308 out() << " " << base::Basename(e.name) << std::endl; 309 } 310 } 311 out() << "-->" << std::endl; 312 } 313 314 // Parse --kernel arguments and write to output manifest. 315 bool setDeviceManifestKernel(HalManifest* manifest) { 316 if (mKernels.empty()) { 317 return true; 318 } 319 if (mKernels.size() > 1) { 320 std::cerr << "Warning: multiple --kernel is specified when building device manifest. " 321 << "Only the first one will be used." << std::endl; 322 } 323 auto& kernelArg = *mKernels.begin(); 324 const auto& kernelVer = kernelArg.first; 325 auto& kernelConfigFiles = kernelArg.second; 326 // addKernel() guarantees that !kernelConfigFiles.empty(). 327 if (kernelConfigFiles.size() > 1) { 328 std::cerr << "Warning: multiple config files are specified in --kernel when building " 329 << "device manfiest. Only the first one will be used." << std::endl; 330 } 331 332 KernelConfigParser parser(true /* processComments */, false /* relaxedFormat */); 333 status_t err = parser.processAndFinish(read(kernelConfigFiles[0].stream())); 334 if (err != OK) { 335 std::cerr << parser.error(); 336 return false; 337 } 338 339 // Set version and configs in manifest. 340 auto kernel_info = std::make_optional<KernelInfo>(); 341 kernel_info->mVersion = kernelVer; 342 kernel_info->mConfigs = parser.configs(); 343 std::string error; 344 if (!manifest->mergeKernel(&kernel_info, &error)) { 345 std::cerr << error << "\n"; 346 return false; 347 } 348 349 return true; 350 } 351 352 void inferDeviceManifestKernelFcm(HalManifest* manifest) { 353 // No target FCM version. 354 if (manifest->level() == Level::UNSPECIFIED) return; 355 // target FCM version < R: leave value untouched. 356 if (manifest->level() < Level::R) return; 357 // Inject empty <kernel> tag if missing. 358 if (!manifest->kernel().has_value()) { 359 manifest->device.mKernel = std::make_optional<KernelInfo>(); 360 } 361 // Kernel FCM already set. 362 if (manifest->kernel()->level() != Level::UNSPECIFIED) return; 363 364 manifest->device.mKernel->mLevel = manifest->level(); 365 } 366 367 bool assembleHalManifest(HalManifests* halManifests) { 368 std::string error; 369 HalManifest* halManifest = &halManifests->front().object; 370 for (auto it = halManifests->begin() + 1; it != halManifests->end(); ++it) { 371 const std::string& path = it->name; 372 HalManifest& manifestToAdd = it->object; 373 374 if (manifestToAdd.level() != Level::UNSPECIFIED) { 375 if (halManifest->level() == Level::UNSPECIFIED) { 376 halManifest->mLevel = manifestToAdd.level(); 377 } else if (halManifest->level() != manifestToAdd.level()) { 378 std::cerr << "Inconsistent FCM Version in HAL manifests:" << std::endl 379 << " File '" << halManifests->front().name << "' has level " 380 << halManifest->level() << std::endl 381 << " File '" << path << "' has level " << manifestToAdd.level() 382 << std::endl; 383 return false; 384 } 385 } 386 387 if (!halManifest->addAll(&manifestToAdd, &error)) { 388 std::cerr << "File \"" << path << "\" cannot be added: " << error << std::endl; 389 return false; 390 } 391 } 392 393 if (halManifest->mType == SchemaType::DEVICE) { 394 if (!getFlagIfUnset("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion)) { 395 return false; 396 } 397 398 if (!setDeviceFcmVersion(halManifest)) { 399 return false; 400 } 401 402 if (!setDeviceManifestKernel(halManifest)) { 403 return false; 404 } 405 406 inferDeviceManifestKernelFcm(halManifest); 407 } 408 409 if (halManifest->mType == SchemaType::FRAMEWORK) { 410 for (auto&& v : getEnvList("PROVIDED_VNDK_VERSIONS")) { 411 halManifest->framework.mVendorNdks.emplace_back(std::move(v)); 412 } 413 414 for (auto&& v : getEnvList("PLATFORM_SYSTEMSDK_VERSIONS")) { 415 halManifest->framework.mSystemSdk.mVersions.emplace(std::move(v)); 416 } 417 } 418 419 outputInputs(*halManifests); 420 421 if (mOutputMatrix) { 422 CompatibilityMatrix generatedMatrix = halManifest->generateCompatibleMatrix(); 423 if (!halManifest->checkCompatibility(generatedMatrix, &error, mCheckFlags)) { 424 std::cerr << "FATAL ERROR: cannot generate a compatible matrix: " << error 425 << std::endl; 426 } 427 out() << "<!-- \n" 428 " Autogenerated skeleton compatibility matrix. \n" 429 " Use with caution. Modify it to suit your needs.\n" 430 " All HALs are set to optional.\n" 431 " Many entries other than HALs are zero-filled and\n" 432 " require human attention. \n" 433 "-->\n" 434 << gCompatibilityMatrixConverter(generatedMatrix, mSerializeFlags); 435 } else { 436 out() << gHalManifestConverter(*halManifest, mSerializeFlags); 437 } 438 out().flush(); 439 440 if (mCheckFile != nullptr) { 441 CompatibilityMatrix checkMatrix; 442 if (!gCompatibilityMatrixConverter(&checkMatrix, read(*mCheckFile), &error)) { 443 std::cerr << "Cannot parse check file as a compatibility matrix: " << error 444 << std::endl; 445 return false; 446 } 447 if (!checkDualFile(*halManifest, checkMatrix)) { 448 return false; 449 } 450 } 451 452 return true; 453 } 454 455 // Parse --kernel arguments and write to output matrix. 456 bool assembleFrameworkCompatibilityMatrixKernels(CompatibilityMatrix* matrix) { 457 for (auto& pair : mKernels) { 458 std::vector<ConditionedConfig> conditionedConfigs; 459 if (!parseFilesForKernelConfigs(&pair.second, &conditionedConfigs)) { 460 return false; 461 } 462 for (ConditionedConfig& conditionedConfig : conditionedConfigs) { 463 MatrixKernel kernel(KernelVersion{pair.first}, std::move(conditionedConfig.second)); 464 if (conditionedConfig.first != nullptr) 465 kernel.mConditions.push_back(std::move(*conditionedConfig.first)); 466 std::string error; 467 if (!matrix->addKernel(std::move(kernel), &error)) { 468 std::cerr << "Error:" << error << std::endl; 469 return false; 470 }; 471 } 472 } 473 return true; 474 } 475 476 bool setDeviceFcmVersion(HalManifest* manifest) { 477 // Not needed for generating empty manifest for DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE. 478 if (getBooleanFlag("VINTF_IGNORE_TARGET_FCM_VERSION")) { 479 return true; 480 } 481 482 size_t shippingApiLevel = getIntegerFlag("PRODUCT_SHIPPING_API_LEVEL"); 483 484 if (manifest->level() != Level::UNSPECIFIED) { 485 return true; 486 } 487 if (!getBooleanFlag("PRODUCT_ENFORCE_VINTF_MANIFEST")) { 488 manifest->mLevel = Level::LEGACY; 489 return true; 490 } 491 // TODO(b/70628538): Do not infer from Shipping API level. 492 if (shippingApiLevel) { 493 std::cerr << "Warning: Shipping FCM Version is inferred from Shipping API level. " 494 << "Declare Shipping FCM Version in device manifest directly." << std::endl; 495 manifest->mLevel = details::convertFromApiLevel(shippingApiLevel); 496 if (manifest->mLevel == Level::UNSPECIFIED) { 497 std::cerr << "Error: Shipping FCM Version cannot be inferred from Shipping API " 498 << "level " << shippingApiLevel << "." 499 << "Declare Shipping FCM Version in device manifest directly." 500 << std::endl; 501 return false; 502 } 503 return true; 504 } 505 // TODO(b/69638851): should be an error if Shipping API level is not defined. 506 // For now, just leave it empty; when framework compatibility matrix is built, 507 // lowest FCM Version is assumed. 508 std::cerr << "Warning: Shipping FCM Version cannot be inferred, because:" << std::endl 509 << " (1) It is not explicitly declared in device manifest;" << std::endl 510 << " (2) PRODUCT_ENFORCE_VINTF_MANIFEST is set to true;" << std::endl 511 << " (3) PRODUCT_SHIPPING_API_LEVEL is undefined." << std::endl 512 << "Assuming 'unspecified' Shipping FCM Version. " << std::endl 513 << "To remove this warning, define 'level' attribute in device manifest." 514 << std::endl; 515 return true; 516 } 517 518 Level getLowestFcmVersion(const CompatibilityMatrices& matrices) { 519 Level ret = Level::UNSPECIFIED; 520 for (const auto& e : matrices) { 521 if (ret == Level::UNSPECIFIED || ret > e.object.level()) { 522 ret = e.object.level(); 523 } 524 } 525 return ret; 526 } 527 528 bool assembleCompatibilityMatrix(CompatibilityMatrices* matrices) { 529 std::string error; 530 CompatibilityMatrix* matrix = nullptr; 531 std::unique_ptr<HalManifest> checkManifest; 532 std::unique_ptr<CompatibilityMatrix> builtMatrix; 533 534 if (mCheckFile != nullptr) { 535 checkManifest = std::make_unique<HalManifest>(); 536 if (!gHalManifestConverter(checkManifest.get(), read(*mCheckFile), &error)) { 537 std::cerr << "Cannot parse check file as a HAL manifest: " << error << std::endl; 538 return false; 539 } 540 } 541 542 if (matrices->front().object.mType == SchemaType::DEVICE) { 543 builtMatrix = CompatibilityMatrix::combineDeviceMatrices(matrices, &error); 544 matrix = builtMatrix.get(); 545 546 if (matrix == nullptr) { 547 std::cerr << error << std::endl; 548 return false; 549 } 550 551 auto vndkVersion = base::Trim(getEnv("REQUIRED_VNDK_VERSION")); 552 if (!vndkVersion.empty()) { 553 auto& valueInMatrix = matrix->device.mVendorNdk; 554 if (!valueInMatrix.version().empty() && valueInMatrix.version() != vndkVersion) { 555 std::cerr << "Hard-coded <vendor-ndk> version in device compatibility matrix (" 556 << matrices->front().name << "), '" << valueInMatrix.version() 557 << "', does not match value inferred " 558 << "from BOARD_VNDK_VERSION '" << vndkVersion << "'" << std::endl; 559 return false; 560 } 561 valueInMatrix = VendorNdk{std::move(vndkVersion)}; 562 } 563 564 for (auto&& v : getEnvList("BOARD_SYSTEMSDK_VERSIONS")) { 565 matrix->device.mSystemSdk.mVersions.emplace(std::move(v)); 566 } 567 } 568 569 if (matrices->front().object.mType == SchemaType::FRAMEWORK) { 570 Level deviceLevel = 571 checkManifest != nullptr ? checkManifest->level() : Level::UNSPECIFIED; 572 if (deviceLevel == Level::UNSPECIFIED) { 573 deviceLevel = getLowestFcmVersion(*matrices); 574 if (checkManifest != nullptr && deviceLevel != Level::UNSPECIFIED) { 575 std::cerr << "Warning: No Target FCM Version for device. Assuming \"" 576 << to_string(deviceLevel) 577 << "\" when building final framework compatibility matrix." 578 << std::endl; 579 } 580 } 581 builtMatrix = CompatibilityMatrix::combine(deviceLevel, matrices, &error); 582 matrix = builtMatrix.get(); 583 584 if (matrix == nullptr) { 585 std::cerr << error << std::endl; 586 return false; 587 } 588 589 if (!assembleFrameworkCompatibilityMatrixKernels(matrix)) { 590 return false; 591 } 592 593 // Add PLATFORM_SEPOLICY_* to sepolicy.sepolicy-version. Remove dupes. 594 std::set<Version> sepolicyVersions; 595 auto sepolicyVersionStrings = getEnvList("PLATFORM_SEPOLICY_COMPAT_VERSIONS"); 596 auto currentSepolicyVersionString = getEnv("PLATFORM_SEPOLICY_VERSION"); 597 if (!currentSepolicyVersionString.empty()) { 598 sepolicyVersionStrings.push_back(currentSepolicyVersionString); 599 } 600 for (auto&& s : sepolicyVersionStrings) { 601 Version v; 602 if (!parse(s, &v)) { 603 std::cerr << "Error: unknown sepolicy version '" << s << "' specified by " 604 << (s == currentSepolicyVersionString 605 ? "PLATFORM_SEPOLICY_VERSION" 606 : "PLATFORM_SEPOLICY_COMPAT_VERSIONS") 607 << "."; 608 return false; 609 } 610 sepolicyVersions.insert(v); 611 } 612 for (auto&& v : sepolicyVersions) { 613 matrix->framework.mSepolicy.mSepolicyVersionRanges.emplace_back(v.majorVer, 614 v.minorVer); 615 } 616 617 if (!getFlagIfUnset("POLICYVERS", 618 &matrix->framework.mSepolicy.mKernelSepolicyVersion)) { 619 return false; 620 } 621 if (!getFlagIfUnset("FRAMEWORK_VBMETA_VERSION", &matrix->framework.mAvbMetaVersion)) { 622 return false; 623 } 624 // Hard-override existing AVB version 625 getFlag("FRAMEWORK_VBMETA_VERSION_OVERRIDE", &matrix->framework.mAvbMetaVersion, 626 false /* log */); 627 } 628 outputInputs(*matrices); 629 out() << gCompatibilityMatrixConverter(*matrix, mSerializeFlags); 630 out().flush(); 631 632 if (checkManifest != nullptr && !checkDualFile(*checkManifest, *matrix)) { 633 return false; 634 } 635 636 return true; 637 } 638 639 enum AssembleStatus { SUCCESS, FAIL_AND_EXIT, TRY_NEXT }; 640 template <typename Schema, typename AssembleFunc> 641 AssembleStatus tryAssemble(const XmlConverter<Schema>& converter, const std::string& schemaName, 642 AssembleFunc assemble, std::string* error) { 643 Schemas<Schema> schemas; 644 Schema schema; 645 if (!converter(&schema, read(mInFiles.front().stream()), error)) { 646 return TRY_NEXT; 647 } 648 auto firstType = schema.type(); 649 schemas.emplace_back(mInFiles.front().name(), std::move(schema)); 650 651 for (auto it = mInFiles.begin() + 1; it != mInFiles.end(); ++it) { 652 Schema additionalSchema; 653 const std::string& fileName = it->name(); 654 if (!converter(&additionalSchema, read(it->stream()), error)) { 655 std::cerr << "File \"" << fileName << "\" is not a valid " << firstType << " " 656 << schemaName << " (but the first file is a valid " << firstType << " " 657 << schemaName << "). Error: " << *error << std::endl; 658 return FAIL_AND_EXIT; 659 } 660 if (additionalSchema.type() != firstType) { 661 std::cerr << "File \"" << fileName << "\" is a " << additionalSchema.type() << " " 662 << schemaName << " (but a " << firstType << " " << schemaName 663 << " is expected)." << std::endl; 664 return FAIL_AND_EXIT; 665 } 666 667 schemas.emplace_back(fileName, std::move(additionalSchema)); 668 } 669 return assemble(&schemas) ? SUCCESS : FAIL_AND_EXIT; 670 } 671 672 bool assemble() override { 673 using std::placeholders::_1; 674 if (mInFiles.empty()) { 675 std::cerr << "Missing input file." << std::endl; 676 return false; 677 } 678 679 std::string manifestError; 680 auto status = tryAssemble(gHalManifestConverter, "manifest", 681 std::bind(&AssembleVintfImpl::assembleHalManifest, this, _1), 682 &manifestError); 683 if (status == SUCCESS) return true; 684 if (status == FAIL_AND_EXIT) return false; 685 686 resetInFiles(); 687 688 std::string matrixError; 689 status = tryAssemble(gCompatibilityMatrixConverter, "compatibility matrix", 690 std::bind(&AssembleVintfImpl::assembleCompatibilityMatrix, this, _1), 691 &matrixError); 692 if (status == SUCCESS) return true; 693 if (status == FAIL_AND_EXIT) return false; 694 695 std::cerr << "Input file has unknown format." << std::endl 696 << "Error when attempting to convert to manifest: " << manifestError << std::endl 697 << "Error when attempting to convert to compatibility matrix: " << matrixError 698 << std::endl; 699 return false; 700 } 701 702 std::ostream& setOutputStream(Ostream&& out) override { 703 mOutRef = std::move(out); 704 return *mOutRef; 705 } 706 707 std::istream& addInputStream(const std::string& name, Istream&& in) override { 708 auto it = mInFiles.emplace(mInFiles.end(), name, std::move(in)); 709 return it->stream(); 710 } 711 712 std::istream& setCheckInputStream(Istream&& in) override { 713 mCheckFile = std::move(in); 714 return *mCheckFile; 715 } 716 717 bool hasKernelVersion(const KernelVersion& kernelVer) const override { 718 return mKernels.find(kernelVer) != mKernels.end(); 719 } 720 721 std::istream& addKernelConfigInputStream(const KernelVersion& kernelVer, 722 const std::string& name, Istream&& in) override { 723 auto&& kernel = mKernels[kernelVer]; 724 auto it = kernel.emplace(kernel.end(), name, std::move(in)); 725 return it->stream(); 726 } 727 728 void resetInFiles() { 729 for (auto& inFile : mInFiles) { 730 inFile.stream().clear(); 731 inFile.stream().seekg(0); 732 } 733 } 734 735 void setOutputMatrix() override { mOutputMatrix = true; } 736 737 bool setHalsOnly() override { 738 if (mHasSetHalsOnlyFlag) { 739 std::cerr << "Error: Cannot set --hals-only with --no-hals." << std::endl; 740 return false; 741 } 742 // Just override it with HALS_ONLY because other flags that modify mSerializeFlags 743 // does not interfere with this (except --no-hals). 744 mSerializeFlags = SerializeFlags::HALS_ONLY; 745 mHasSetHalsOnlyFlag = true; 746 return true; 747 } 748 749 bool setNoHals() override { 750 if (mHasSetHalsOnlyFlag) { 751 std::cerr << "Error: Cannot set --hals-only with --no-hals." << std::endl; 752 return false; 753 } 754 mSerializeFlags = mSerializeFlags.disableHals(); 755 mHasSetHalsOnlyFlag = true; 756 return true; 757 } 758 759 bool setNoKernelRequirements() override { 760 mSerializeFlags = mSerializeFlags.disableKernelConfigs().disableKernelMinorRevision(); 761 mCheckFlags = mCheckFlags.disableKernel(); 762 return true; 763 } 764 765 private: 766 std::vector<NamedIstream> mInFiles; 767 Ostream mOutRef; 768 Istream mCheckFile; 769 bool mOutputMatrix = false; 770 bool mHasSetHalsOnlyFlag = false; 771 SerializeFlags::Type mSerializeFlags = SerializeFlags::EVERYTHING; 772 std::map<KernelVersion, std::vector<NamedIstream>> mKernels; 773 std::map<std::string, std::string> mFakeEnv; 774 CheckFlags::Type mCheckFlags = CheckFlags::DEFAULT; 775 }; 776 777 bool AssembleVintf::openOutFile(const std::string& path) { 778 return static_cast<std::ofstream&>(setOutputStream(std::make_unique<std::ofstream>(path))) 779 .is_open(); 780 } 781 782 bool AssembleVintf::openInFile(const std::string& path) { 783 return static_cast<std::ifstream&>(addInputStream(path, std::make_unique<std::ifstream>(path))) 784 .is_open(); 785 } 786 787 bool AssembleVintf::openCheckFile(const std::string& path) { 788 return static_cast<std::ifstream&>(setCheckInputStream(std::make_unique<std::ifstream>(path))) 789 .is_open(); 790 } 791 792 bool AssembleVintf::addKernel(const std::string& kernelArg) { 793 auto tokens = base::Split(kernelArg, ":"); 794 if (tokens.size() <= 1) { 795 std::cerr << "Unrecognized --kernel option '" << kernelArg << "'" << std::endl; 796 return false; 797 } 798 KernelVersion kernelVer; 799 if (!parse(tokens.front(), &kernelVer)) { 800 std::cerr << "Unrecognized kernel version '" << tokens.front() << "'" << std::endl; 801 return false; 802 } 803 if (hasKernelVersion(kernelVer)) { 804 std::cerr << "Multiple --kernel for " << kernelVer << " is specified." << std::endl; 805 return false; 806 } 807 for (auto it = tokens.begin() + 1; it != tokens.end(); ++it) { 808 bool opened = 809 static_cast<std::ifstream&>( 810 addKernelConfigInputStream(kernelVer, *it, std::make_unique<std::ifstream>(*it))) 811 .is_open(); 812 if (!opened) { 813 std::cerr << "Cannot open file '" << *it << "'." << std::endl; 814 return false; 815 } 816 } 817 return true; 818 } 819 820 std::unique_ptr<AssembleVintf> AssembleVintf::newInstance() { 821 return std::make_unique<AssembleVintfImpl>(); 822 } 823 824 } // namespace vintf 825 } // namespace android 826