C++程序  |  301行  |  10.44 KB

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#define LOG_TAG "VtsTestabilityChecker"

#include "VtsTestabilityChecker.h"

#include <algorithm>
#include <iostream>
#include <set>

#include <android-base/strings.h>
#include <vintf/parse_string.h>

using android::base::Join;
using android::vintf::Arch;
using android::vintf::CompatibilityMatrix;
using android::vintf::gArchStrings;
using android::vintf::HalManifest;
using android::vintf::ManifestHal;
using android::vintf::ManifestInstance;
using android::vintf::MatrixHal;
using android::vintf::MatrixInstance;
using android::vintf::toFQNameString;
using android::vintf::Transport;
using android::vintf::Version;
using android::vintf::operator<<;
using std::set;
using std::string;
using std::vector;

namespace android {
namespace vts {

bool VtsTestabilityChecker::CheckHalForComplianceTest(
    const string& hal_package_name, const Version& hal_version,
    const string& hal_interface_name, const Arch& arch,
    set<string>* instances) {
  CHECK(instances) << "instances set should not be NULL.";
  set<string> famework_hal_instances;
  set<string> vendor_hal_instances;
  bool check_framework_hal = CheckFrameworkManifestHal(
      hal_package_name, hal_version, hal_interface_name, arch,
      &famework_hal_instances);
  bool check_vendor_hal =
      CheckVendorManifestHal(hal_package_name, hal_version, hal_interface_name,
                             arch, &vendor_hal_instances);
  set_union(famework_hal_instances.begin(), famework_hal_instances.end(),
            vendor_hal_instances.begin(), vendor_hal_instances.end(),
            std::inserter(*instances, instances->begin()));
  return check_framework_hal || check_vendor_hal;
}

bool VtsTestabilityChecker::CheckHalForNonComplianceTest(
    const string& hal_package_name, const Version& hal_version,
    const string& hal_interface_name, const Arch& arch,
    set<string>* instances) {
  CHECK(instances) << "instances set should not be NULL.";
  set<string> vendor_hal_instances;
  set<string> test_hal_instances;
  bool check_vendor_hal =
      CheckVendorManifestHal(hal_package_name, hal_version, hal_interface_name,
                             arch, &vendor_hal_instances);

  bool check_test_hal = CheckTestHalWithHwManager(
      hal_package_name, hal_version, hal_interface_name, &test_hal_instances);

  set_union(vendor_hal_instances.begin(), vendor_hal_instances.end(),
            test_hal_instances.begin(), test_hal_instances.end(),
            std::inserter(*instances, instances->begin()));
  return check_vendor_hal || check_test_hal;
}

vector<const ManifestInstance*> VtsTestabilityChecker::FindInstance(
    const vector<ManifestInstance>& manifest_instances,
    const MatrixInstance& matrix_instance) {
  vector<const ManifestInstance*> ret;
  for (const auto& e : manifest_instances) {
    if (matrix_instance.matchInstance(e.instance())) {
      ret.push_back(&e);
    }
  }
  return ret;
}

vector<const ManifestInstance*> VtsTestabilityChecker::FindInterface(
    const vector<ManifestInstance>& manifest_instances,
    const MatrixInstance& matrix_instance) {
  vector<const ManifestInstance*> ret;
  for (const auto& e : manifest_instances) {
    if (e.interface() == matrix_instance.interface()) {
      ret.push_back(&e);
    }
  }
  return ret;
}

bool VtsTestabilityChecker::CheckFrameworkCompatibleHal(
    const string& hal_package_name, const Version& hal_version,
    const string& hal_interface_name, const Arch& arch,
    set<string>* instances) {
  CHECK(instances) << "instances set should not be NULL.";

  auto matrix_instances = framework_comp_matrix_->getFqInstances(
      hal_package_name, hal_version, hal_interface_name);
  auto manifest_instances = device_hal_manifest_->getFqInstances(
      hal_package_name, hal_version, hal_interface_name);

  bool testable = false;

  for (const auto& matrix_instance : matrix_instances) {
    const auto& matched_instances =
        FindInstance(manifest_instances, matrix_instance);
    if (!matrix_instance.optional() && matched_instances.empty()) {
      // In matrix but not in manifest.
      // The test should still run, but expect the test
      // to fail (due to incompatible vendor and framework HAL).
      LOG(ERROR) << "Compatibility error. Hal " << hal_package_name
                 << " is required by framework but not supported by vendor";
      if (!hal_interface_name.empty()) {
        if (!matrix_instance.isRegex()) {
          instances->insert(matrix_instance.exactInstance());
        } else {
          LOG(ERROR) << "Ignore regex-instance '"
                     << matrix_instance.regexPattern();
        }
      }
      testable |= true;
      continue;
    }

    if (hal_interface_name.empty()) {
      testable |= !matched_instances.empty();
      continue;
    }

    auto get_testable_instances =
        [&](const vector<const vintf::ManifestInstance*>& manifest_instances) {
          vector<string> ret;
          for (const auto& manifest_instance : manifest_instances) {
            if ((manifest_instance->transport() == Transport::PASSTHROUGH &&
                 CheckPassthroughManifestArch(manifest_instance->arch(),
                                              arch)) ||
                manifest_instance->transport() == Transport::HWBINDER) {
              ret.push_back(manifest_instance->instance());
            }
          }
          return ret;
        };

    auto testable_instances = get_testable_instances(matched_instances);
    if (!testable_instances.empty()) {
      instances->insert(testable_instances.begin(), testable_instances.end());
      testable |= true;
      continue;
    }

    // Special case: if a.h.foo@1.0::IFoo/default is in matrix but /custom
    // is in manifest, the interface is still testable, but /default should
    // not be added to instances.
    const auto& matched_interface_instances =
        FindInterface(manifest_instances, matrix_instance);
    auto testable_interfaces =
        get_testable_instances(matched_interface_instances);
    if (!testable_interfaces.empty()) {
      testable |= true;
      continue;
    }
  }
  if (instances->empty()) {
    LOG(ERROR) << "Hal "
               << toFQNameString(hal_package_name, hal_version,
                                 hal_interface_name)
               << " has no testable instance";
  }
  return testable;
}

bool VtsTestabilityChecker::CheckPassthroughManifestArch(
    const Arch& manifest_arch, const Arch& arch) {
  switch (arch) {
    case Arch::ARCH_32: {
      if (android::vintf::has32(manifest_arch)) {
        return true;
      }
      break;
    }
    case Arch::ARCH_64: {
      if (android::vintf::has64(manifest_arch)) {
        return true;
      }
      break;
    }
    default: {
      LOG(ERROR) << "Unexpected arch to check: " << arch;
      break;
    }
  }
  return false;
}

bool VtsTestabilityChecker::CheckFrameworkManifestHal(
    const string& hal_package_name, const Version& hal_version,
    const string& hal_interface_name, const Arch& arch,
    set<string>* instances) {
  return CheckManifestHal(framework_hal_manifest_, hal_package_name,
                          hal_version, hal_interface_name, arch, instances);
}

bool VtsTestabilityChecker::CheckVendorManifestHal(
    const string& hal_package_name, const Version& hal_version,
    const string& hal_interface_name, const Arch& arch,
    set<string>* instances) {
  return CheckManifestHal(device_hal_manifest_, hal_package_name, hal_version,
                          hal_interface_name, arch, instances);
}

bool VtsTestabilityChecker::CheckManifestHal(const HalManifest* hal_manifest,
                                             const string& hal_package_name,
                                             const Version& hal_version,
                                             const string& hal_interface_name,
                                             const Arch& arch,
                                             set<string>* instances) {
  CHECK(instances) << "instances set should not be NULL.";

  const auto& manifest_instances = hal_manifest->getFqInstances(
      hal_package_name, hal_version, hal_interface_name);

  const auto& fq_instance_name =
      toFQNameString(hal_package_name, hal_version, hal_interface_name);

  if (manifest_instances.empty()) {
    LOG(DEBUG) << "Does not find instances for " << fq_instance_name
               << " in manifest file";
    return false;
  }

  bool testable = false;
  for (const auto& manifest_instance : manifest_instances) {
    if (manifest_instance.transport() == Transport::PASSTHROUGH &&
        !CheckPassthroughManifestArch(manifest_instance.arch(), arch)) {
      LOG(DEBUG) << "Manifest HAL " << fq_instance_name
                 << " is passthrough and does not support arch " << arch;
      continue;  // skip this instance
    }
    if (!hal_interface_name.empty()) {
      instances->insert(manifest_instance.instance());
    }
    testable = true;
  }
  return testable;
}

bool VtsTestabilityChecker::CheckTestHalWithHwManager(
    const string& hal_package_name, const Version& hal_version,
    const string& hal_interface_name, set<string>* instances) {
  CHECK(instances) << "instances set should not be NULL.";

  string fqName =
      toFQNameString(hal_package_name, hal_version, hal_interface_name);
  bool registered = false;
  hardware::Return<void> res;
  if (!hal_interface_name.empty()) {
    res = sm_->listByInterface(fqName, [&](const auto& registered_instances) {
      for (const string& instance : registered_instances) {
        registered = true;
        instances->insert(instance);
      }
    });
  } else {  // handle legacy data without interface info.
    res = sm_->list([&](const auto& services) {
      for (const string& service : services) {
        if (service.find(fqName) == 0) {
          registered = true;
          break;
        }
      }
    });
  }
  if (!res.isOk()) {
    LOG(ERROR) << "failed to check services: " << res.description();
    return false;
  }
  return registered;
}

}  // namespace vts
}  // namespace android