Merge "Merge Coral/Flame into AOSP master"

This commit is contained in:
Xin Li
2019-10-27 04:44:29 +00:00
committed by Gerrit Code Review
22 changed files with 981 additions and 350 deletions

View File

@@ -24,7 +24,7 @@
#include <android/hardware/drm/1.0/types.h>
#include <android/hardware/drm/1.1/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <gtest/gtest.h>
#include <hidl/HidlSupport.h>
#include <hidl/ServiceManagement.h>
@@ -129,9 +129,9 @@ public:
ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
test_info->name());
auto manager = android::hardware::defaultServiceManager();
auto manager = android::hardware::defaultServiceManager1_2();
ASSERT_NE(nullptr, manager.get());
manager->listByInterface(IDrmFactory::descriptor,
manager->listManifestByInterface(IDrmFactory::descriptor,
[&](const hidl_vec<hidl_string> &registered) {
for (const auto &instance : registered) {
sp<IDrmFactory> drmFactory =
@@ -144,7 +144,7 @@ public:
}
);
manager->listByInterface(ICryptoFactory::descriptor,
manager->listManifestByInterface(ICryptoFactory::descriptor,
[&](const hidl_vec<hidl_string> &registered) {
for (const auto &instance : registered) {
sp<ICryptoFactory> cryptoFactory =

View File

@@ -16,10 +16,16 @@
#define LOG_TAG "GnssHalTest"
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/ServiceManagement.h>
#include <gnss_hal_test.h>
#include <chrono>
#include "Utils.h"
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::gnss::common::Utils;
// Implementations for the main test class for GNSS HAL
@@ -149,6 +155,28 @@ void GnssHalTest::StartAndCheckLocations(int count) {
}
}
bool GnssHalTest::IsGnssHalVersion_1_1() const {
using ::android::hidl::manager::V1_2::IServiceManager;
sp<IServiceManager> manager = ::android::hardware::defaultServiceManager1_2();
bool hasGnssHalVersion_1_1 = false;
manager->listManifestByInterface(
"android.hardware.gnss@1.1::IGnss",
[&hasGnssHalVersion_1_1](const hidl_vec<hidl_string>& registered) {
ASSERT_EQ(1, registered.size());
hasGnssHalVersion_1_1 = true;
});
bool hasGnssHalVersion_2_0 = false;
manager->listManifestByInterface(
"android.hardware.gnss@2.0::IGnss",
[&hasGnssHalVersion_2_0](const hidl_vec<hidl_string>& registered) {
hasGnssHalVersion_2_0 = registered.size() != 0;
});
return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
}
void GnssHalTest::notify() {
std::unique_lock<std::mutex> lock(mtx_);
notify_count_++;

View File

@@ -145,6 +145,12 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
*/
void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
/*
* IsGnssHalVersion_1_1:
* returns true if the GNSS HAL version is exactly 1.1.
*/
bool IsGnssHalVersion_1_1() const;
sp<IGnss> gnss_hal_; // GNSS HAL to call into
sp<IGnssCallback> gnss_cb_; // Primary callback interface

View File

@@ -24,6 +24,9 @@
using android::hardware::hidl_vec;
using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
using android::hardware::gnss::V1_0::GnssConstellationType;
using android::hardware::gnss::V1_0::GnssLocation;
using android::hardware::gnss::V1_0::IGnssDebug;
@@ -43,11 +46,15 @@ TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
* Gets the GnssMeasurementExtension and verify that it returns an actual extension.
*/
TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_1_1();
ASSERT_TRUE(gnssMeasurement.isOk());
auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
ASSERT_TRUE(gnssMeasurement_1_1.isOk());
auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
ASSERT_TRUE(gnssMeasurement_1_0.isOk());
if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
sp<IGnssMeasurement> iGnssMeas = gnssMeasurement;
EXPECT_NE(iGnssMeas, nullptr);
sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
// At least one interface must be non-null.
ASSERT_TRUE(iGnssMeas_1_1 != nullptr || iGnssMeas_1_0 != nullptr);
}
}
@@ -59,6 +66,11 @@ TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
* each received location.
*/
TEST_F(GnssHalTest, GetLocationLowPower) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
return;
}
const int kMinIntervalMsec = 5000;
const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
@@ -202,6 +214,11 @@ IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
* formerly strongest satellite
*/
TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1.");
return;
}
const int kLocationsToAwait = 3;
const int kRetriesToUnBlacklist = 10;
@@ -323,6 +340,11 @@ TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
TEST_F(GnssHalTest, BlacklistConstellation) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
return;
}
const int kLocationsToAwait = 3;
StartAndCheckLocations(kLocationsToAwait);

View File

@@ -23,7 +23,6 @@ int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
GnssHidlEnvironment::Instance()->init(&argc, argv);
// TODO (b/122463165): Expand coverage to include 1.1 and 1.0 VTS tests.
int status = RUN_ALL_TESTS();
ALOGI("Test result = %d", status);
return status;

View File

@@ -152,7 +152,7 @@ GnssHalTest::GnssCallback::GnssCallback()
name_cbq_("name"),
capabilities_cbq_("capabilities"),
location_cbq_("location"),
sv_info_cbq_("sv_info") {}
sv_info_list_cbq_("sv_info") {}
Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
const IGnssCallback_1_0::GnssSystemInfo& info) {
@@ -204,7 +204,7 @@ Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(const IGnssCallback_1_0::
Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb_2_0(
const hidl_vec<IGnssCallback_2_0::GnssSvInfo>& svInfoList) {
ALOGI("gnssSvStatusCb_2_0. Size = %d", (int)svInfoList.size());
sv_info_cbq_.store(svInfoList);
sv_info_list_cbq_.store(svInfoList);
return Void();
}

View File

@@ -23,6 +23,7 @@
#include <condition_variable>
#include <deque>
#include <list>
#include <mutex>
using android::hardware::hidl_vec;
@@ -85,6 +86,14 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
*/
bool retrieve(T& event, int timeout_seconds);
/*
* Removes parameter count number of callack events at the front of the queue, stores
* them in event_list parameter and returns the number of events retrieved. Waits up to
* timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
* items retrieved which will be less than count.
*/
int retrieve(list<T>& event_list, int count, int timeout_seconds);
/* Returns the number of events pending to be retrieved from the callback event queue. */
int size() const;
@@ -117,7 +126,7 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
CallbackQueue<android::hardware::hidl_string> name_cbq_;
CallbackQueue<uint32_t> capabilities_cbq_;
CallbackQueue<GnssLocation_2_0> location_cbq_;
CallbackQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_cbq_;
CallbackQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_list_cbq_;
GnssCallback();
virtual ~GnssCallback() = default;
@@ -264,6 +273,19 @@ bool GnssHalTest::CallbackQueue<T>::retrieve(T& event, int timeout_seconds) {
return true;
}
template <class T>
int GnssHalTest::CallbackQueue<T>::retrieve(list<T>& event_list, int count, int timeout_seconds) {
for (int i = 0; i < count; ++i) {
T event;
if (!retrieve(event, timeout_seconds)) {
return i;
}
event_list.push_back(event);
}
return count;
}
template <class T>
int GnssHalTest::CallbackQueue<T>::size() const {
std::unique_lock<std::recursive_mutex> lock(mtx_);

View File

@@ -23,7 +23,10 @@
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil;
using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
@@ -33,15 +36,12 @@ using IAGnssRil_1_0 = android::hardware::gnss::V1_0::IAGnssRil;
using IAGnss_2_0 = android::hardware::gnss::V2_0::IAGnss;
using IAGnss_1_0 = android::hardware::gnss::V1_0::IAGnss;
using IAGnssCallback_2_0 = android::hardware::gnss::V2_0::IAGnssCallback;
using IGnssBatching_V1_0 = android::hardware::gnss::V1_0::IGnssBatching;
using IGnssBatching_V2_0 = android::hardware::gnss::V2_0::IGnssBatching;
using android::hardware::gnss::common::Utils;
using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
using android::hardware::gnss::V1_0::IGnssNi;
using android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
using android::hardware::gnss::V2_0::GnssConstellationType;
using android::hardware::gnss::V2_0::IGnssCallback;
using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
@@ -209,9 +209,9 @@ TEST_F(GnssHalTest, TestGnssMeasurementFields) {
// Verify ConstellationType is valid.
ASSERT_TRUE(static_cast<uint8_t>(measurement.constellation) >=
static_cast<uint8_t>(GnssConstellationType::UNKNOWN) &&
static_cast<uint8_t>(GnssConstellationType_2_0::UNKNOWN) &&
static_cast<uint8_t>(measurement.constellation) <=
static_cast<uint8_t>(GnssConstellationType::IRNSS));
static_cast<uint8_t>(GnssConstellationType_2_0::IRNSS));
// Verify State is valid.
ASSERT_TRUE(
@@ -414,3 +414,423 @@ TEST_F(GnssHalTest, TestGnssBatchingExtension) {
auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0();
ASSERT_TRUE(gnssBatching_2_0.isOk());
}
/*
* GetLocationLowPower:
* Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
* between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
* NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
* each received location.
*/
TEST_F(GnssHalTest, GetLocationLowPower) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) {
ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported.");
return;
}
const int kMinIntervalMsec = 5000;
const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
const int kLocationsToCheck = 5;
const bool kLowPowerMode = true;
// Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToCheck);
StopAndClearLocations();
gnss_cb_->location_cbq_.reset();
// Start of Low Power Mode test
SetPositionMode(kMinIntervalMsec, kLowPowerMode);
// Don't expect true - as without AGPS access
if (!StartAndCheckFirstLocation()) {
ALOGW("GetLocationLowPower test - no first low power location received.");
}
for (int i = 1; i < kLocationsToCheck; i++) {
// Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
// ensure that no location is received yet
gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
const int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
// Tolerate (ignore) one extra location right after the first one
// to handle startup edge case scheduling limitations in some implementations
if ((i == 1) && (locationCalledCount == 2)) {
CheckLocation(gnss_cb_->last_location_, true);
continue; // restart the quiet wait period after this too-fast location
}
EXPECT_LE(locationCalledCount, i);
if (locationCalledCount != i) {
ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
locationCalledCount, i);
}
if (!gnss_cb_->location_cbq_.retrieve(
gnss_cb_->last_location_,
kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
} else {
CheckLocation(gnss_cb_->last_location_, true);
}
}
StopAndClearLocations();
}
/*
* MapConstellationType:
* Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
* GnssConstellationType_1_0 type constellation. For constellations that do not have
* an equivalent value, maps to GnssConstellationType_1_0::UNKNOWN
*/
GnssConstellationType_1_0 MapConstellationType(GnssConstellationType_2_0 constellation) {
switch (constellation) {
case GnssConstellationType_2_0::GPS:
return GnssConstellationType_1_0::GPS;
case GnssConstellationType_2_0::SBAS:
return GnssConstellationType_1_0::SBAS;
case GnssConstellationType_2_0::GLONASS:
return GnssConstellationType_1_0::GLONASS;
case GnssConstellationType_2_0::QZSS:
return GnssConstellationType_1_0::QZSS;
case GnssConstellationType_2_0::BEIDOU:
return GnssConstellationType_1_0::BEIDOU;
case GnssConstellationType_2_0::GALILEO:
return GnssConstellationType_1_0::GALILEO;
default:
return GnssConstellationType_1_0::UNKNOWN;
}
}
/*
* FindStrongFrequentNonGpsSource:
*
* Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
*
* returns the strongest source,
* or a source with constellation == UNKNOWN if none are found sufficient times
*/
IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource(
const list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
const int min_observations) {
struct ComparableBlacklistedSource {
IGnssConfiguration_1_1::BlacklistedSource id;
ComparableBlacklistedSource() {
id.constellation = GnssConstellationType_1_0::UNKNOWN;
id.svid = 0;
}
bool operator<(const ComparableBlacklistedSource& compare) const {
return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
(id.constellation < compare.id.constellation)));
}
};
struct SignalCounts {
int observations;
float max_cn0_dbhz;
};
std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
for (const auto& sv_info_list : sv_info_lists) {
for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
(sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
(sv_info.constellation != GnssConstellationType_2_0::GPS)) {
ComparableBlacklistedSource source;
source.id.svid = sv_info.v1_0.svid;
source.id.constellation = MapConstellationType(sv_info.constellation);
const auto& itSignal = mapSignals.find(source);
if (itSignal == mapSignals.end()) {
SignalCounts counts;
counts.observations = 1;
counts.max_cn0_dbhz = sv_info.v1_0.cN0Dbhz;
mapSignals.insert(
std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
} else {
itSignal->second.observations++;
if (itSignal->second.max_cn0_dbhz < sv_info.v1_0.cN0Dbhz) {
itSignal->second.max_cn0_dbhz = sv_info.v1_0.cN0Dbhz;
}
}
}
}
}
float max_cn0_dbhz_with_sufficient_count = 0.;
int total_observation_count = 0;
int blacklisted_source_count_observation = 0;
ComparableBlacklistedSource source_to_blacklist; // initializes to zero = UNKNOWN constellation
for (auto const& pairSignal : mapSignals) {
total_observation_count += pairSignal.second.observations;
if ((pairSignal.second.observations >= min_observations) &&
(pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
source_to_blacklist = pairSignal.first;
blacklisted_source_count_observation = pairSignal.second.observations;
max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
}
}
ALOGD("Among %d observations, chose svid %d, constellation %d, "
"with %d observations at %.1f max CNo",
total_observation_count, source_to_blacklist.id.svid,
(int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
max_cn0_dbhz_with_sufficient_count);
return source_to_blacklist.id;
}
/*
* BlacklistIndividualSatellites:
*
* 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus for common satellites (strongest and one other.)
* 2a & b) Turns off location, and blacklists common satellites.
* 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus does not use those satellites.
* 4a & b) Turns off location, and send in empty blacklist.
* 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus does re-use at least the previously strongest satellite
* 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
* formerly strongest satellite
*/
TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
" not supported.");
return;
}
const int kLocationsToAwait = 3;
const int kRetriesToUnBlacklist = 10;
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate 1 less sv status to handle edge cases in reporting.
int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
/*
* Identify strongest SV seen at least kLocationsToAwait -1 times
* Why -1? To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
* observability (one epoch RF null)
*/
const int kGnssSvStatusTimeout = 2;
list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, sv_info_list_cbq_size,
kGnssSvStatusTimeout);
ASSERT_EQ(count, sv_info_list_cbq_size);
IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist =
FindStrongFrequentNonGpsSource(sv_info_lists, kLocationsToAwait - 1);
if (source_to_blacklist.constellation == GnssConstellationType_1_0::UNKNOWN) {
// Cannot find a non-GPS satellite. Let the test pass.
return;
}
// Stop locations, blacklist the common SV
StopAndClearLocations();
auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
ASSERT_TRUE(gnss_configuration_hal_return.isOk());
sp<IGnssConfiguration_1_1> gnss_configuration_hal = gnss_configuration_hal_return;
ASSERT_NE(gnss_configuration_hal, nullptr);
hidl_vec<IGnssConfiguration_1_1::BlacklistedSource> sources;
sources.resize(1);
sources[0] = source_to_blacklist;
auto result = gnss_configuration_hal->setBlacklist(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
// retry and ensure satellite not used
gnss_cb_->sv_info_list_cbq_.reset();
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// early exit if test is being run with insufficient signal
location_called_count = gnss_cb_->location_cbq_.calledCount();
if (location_called_count == 0) {
ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
}
ASSERT_TRUE(location_called_count > 0);
// Tolerate 1 less sv status to handle edge cases in reporting.
sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
auto constellation = MapConstellationType(sv_info.constellation);
EXPECT_FALSE((sv_info.v1_0.svid == source_to_blacklist.svid) &&
(constellation == source_to_blacklist.constellation) &&
(sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
}
}
// clear blacklist and restart - this time updating the blacklist while location is still on
sources.resize(0);
result = gnss_configuration_hal->setBlacklist(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
bool strongest_sv_is_reobserved = false;
// do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
int unblacklist_loops_remaining = kRetriesToUnBlacklist;
while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
StopAndClearLocations();
gnss_cb_->sv_info_list_cbq_.reset();
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// early exit loop if test is being run with insufficient signal
location_called_count = gnss_cb_->location_cbq_.calledCount();
if (location_called_count == 0) {
ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
}
ASSERT_TRUE(location_called_count > 0);
// Tolerate 1 less sv status to handle edge cases in reporting.
sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
", tries remaining %d",
sv_info_list_cbq_size, kLocationsToAwait, unblacklist_loops_remaining);
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
auto constellation = MapConstellationType(sv_info.constellation);
if ((sv_info.v1_0.svid == source_to_blacklist.svid) &&
(constellation == source_to_blacklist.constellation) &&
(sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
strongest_sv_is_reobserved = true;
break;
}
}
if (strongest_sv_is_reobserved) break;
}
}
EXPECT_TRUE(strongest_sv_is_reobserved);
StopAndClearLocations();
}
/*
* BlacklistConstellation:
*
* 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus for any non-GPS constellations.
* 2a & b) Turns off location, and blacklist first non-GPS constellations.
* 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
TEST_F(GnssHalTest, BlacklistConstellation) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
return;
}
const int kLocationsToAwait = 3;
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
const int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate 1 less sv status to handle edge cases in reporting.
int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
// Find first non-GPS constellation to blacklist. Exclude IRNSS in GnssConstellationType_2_0
// as blacklisting of this constellation is not supported in gnss@2.0.
const int kGnssSvStatusTimeout = 2;
GnssConstellationType_1_0 constellation_to_blacklist = GnssConstellationType_1_0::UNKNOWN;
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
(sv_info.constellation != GnssConstellationType_2_0::UNKNOWN) &&
(sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
(sv_info.constellation != GnssConstellationType_2_0::GPS)) {
// found a non-GPS V1_0 constellation
constellation_to_blacklist = MapConstellationType(sv_info.constellation);
break;
}
}
if (constellation_to_blacklist != GnssConstellationType_1_0::UNKNOWN) {
break;
}
}
if (constellation_to_blacklist == GnssConstellationType_1_0::UNKNOWN) {
ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
// Proceed functionally to blacklist something.
constellation_to_blacklist = GnssConstellationType_1_0::GLONASS;
}
IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist;
source_to_blacklist.constellation = constellation_to_blacklist;
source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation
auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
ASSERT_TRUE(gnss_configuration_hal_return.isOk());
sp<IGnssConfiguration_1_1> gnss_configuration_hal = gnss_configuration_hal_return;
ASSERT_NE(gnss_configuration_hal, nullptr);
hidl_vec<IGnssConfiguration_1_1::BlacklistedSource> sources;
sources.resize(1);
sources[0] = source_to_blacklist;
auto result = gnss_configuration_hal->setBlacklist(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
// retry and ensure constellation not used
gnss_cb_->sv_info_list_cbq_.reset();
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// Tolerate 1 less sv status to handle edge cases in reporting.
sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size,
kLocationsToAwait);
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
auto constellation = MapConstellationType(sv_info.constellation);
EXPECT_FALSE((constellation == source_to_blacklist.constellation) &&
(sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
}
}
// clean up
StopAndClearLocations();
sources.resize(0);
result = gnss_configuration_hal->setBlacklist(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
}

View File

@@ -14,7 +14,6 @@
* limitations under the License.
*/
#include <android/hardware/radio/1.1/IRadio.h>
#include <radio_hidl_hal_utils_v1_2.h>
void RadioHidlTest_v1_2::SetUp() {
@@ -154,25 +153,7 @@ void RadioHidlTest_v1_2::updateSimCardStatus() {
}
void RadioHidlTest_v1_2::stopNetworkScan() {
sp<::android::hardware::radio::V1_1::IRadio> radio_v1_1;
radio_v1_1 = ::testing::VtsHalHidlTargetTestBase::getService<
::android::hardware::radio::V1_1::IRadio>(
RadioHidlEnvironment::Instance()
->getServiceName<::android::hardware::radio::V1_1::IRadio>(
hidl_string(RADIO_SERVICE_NAME)));
if (radio_v1_1 == NULL) {
sleep(60);
radio_v1_1 = ::testing::VtsHalHidlTargetTestBase::getService<
::android::hardware::radio::V1_1::IRadio>(
RadioHidlEnvironment::Instance()
->getServiceName<::android::hardware::radio::V1_1::IRadio>(
hidl_string(RADIO_SERVICE_NAME)));
}
ASSERT_NE(nullptr, radio_v1_1.get());
serial = GetRandomSerialNumber();
radio_v1_1->stopNetworkScan(serial);
radio_v1_2->stopNetworkScan(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
}

View File

@@ -169,6 +169,11 @@ TEST_F(RadioHidlTest_v1_4, setPreferredNetworkTypeBitmap) {
/*
* Test IRadio.startNetworkScan() for the response returned.
*
* REQUEST_NOT_SUPPORTED is temporarily returned because of vendors failed to fully implement
* startNetworkScan in HAL @1.4 (see b/137298570 and b/135595082). Starting from @1.5, however,
* REQUEST_NOT_SUPPORTED will be disallowed for all tests. Modems have "GSM" rat scan need to
* support scanning requests combined with some parameters.
*/
TEST_F(RadioHidlTest_v1_4, startNetworkScan) {
serial = GetRandomSerialNumber();
@@ -196,10 +201,17 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan) {
if (cardStatus.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::SIM_ABSENT}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
// OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do not support the
// required manual GSM search functionality. This is tracked in b/112206766.
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED}));
// OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do
// not support the required manual GSM search functionality. This is
// tracked in b/112206766. REQUEST_NOT_SUPPORTED is temporarily added back
// because of vendors failed to implement startNetworkScan in HAL 1.4 (see
// b/137298570 and b/135595082). Starting from 1.5, however,
// REQUEST_NOT_SUPPORTED will be disallowed. Modems have "GSM" rat scan
// need to support scanning requests combined with some parameters.
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED,
RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -225,8 +237,9 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidArgument) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_4->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -261,8 +274,9 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidInterval1) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_4->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -296,8 +310,9 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidInterval2) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_4->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -331,8 +346,9 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidMaxSearchTime1) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_4->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -366,8 +382,9 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidMaxSearchTime2) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_4->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -401,8 +418,9 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidPeriodicity1) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_4->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -436,8 +454,9 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan_InvalidPeriodicity2) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_4->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -473,8 +492,10 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan_GoodRequest1) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::INVALID_ARGUMENTS,
RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -512,8 +533,10 @@ TEST_F(RadioHidlTest_v1_4, startNetworkScan_GoodRequest2) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::INVALID_ARGUMENTS,
RadioError::REQUEST_NOT_SUPPORTED}));
}
}

View File

@@ -16,6 +16,7 @@
cc_test {
name: "VtsHalSensorsV1_0TargetTest",
cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"SensorsHidlEnvironmentV1_0.cpp",
@@ -23,7 +24,10 @@ cc_test {
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
"VtsHalSensorsTargetTestUtils",
],

View File

@@ -14,8 +14,6 @@
* limitations under the License.
*/
#define LOG_TAG "sensors_hidl_hal_test"
#include "SensorsHidlEnvironmentV1_0.h"
#include "sensors-vts-utils/SensorsHidlTestBase.h"

View File

@@ -16,6 +16,7 @@
cc_test {
name: "VtsHalSensorsV2_0TargetTest",
cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"SensorsHidlEnvironmentV2_0.cpp",
@@ -23,7 +24,10 @@ cc_test {
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"libfmq",

View File

@@ -38,6 +38,13 @@ constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType valu
constexpr size_t SensorsHidlEnvironmentV2_0::MAX_RECEIVE_BUFFER_EVENT_COUNT;
void SensorsHalDeathRecipient::serviceDied(
uint64_t /* cookie */,
const ::android::wp<::android::hidl::base::V1_0::IBase>& /* service */) {
ALOGE("Sensors HAL died (likely crashed) during test");
FAIL() << "Sensors HAL died during test";
}
struct SensorsCallback : ISensorsCallback {
Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& /* sensorInfos */) {
return Return<void>();
@@ -56,6 +63,7 @@ bool SensorsHidlEnvironmentV2_0::resetHal() {
if (mSensors == nullptr) {
break;
}
mSensors->linkToDeath(mDeathRecipient, 0 /* cookie */);
// Initialize FMQs
mEventQueue = std::make_unique<EventMessageQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,

View File

@@ -32,6 +32,13 @@ using ::android::sp;
using ::android::hardware::MessageQueue;
class SensorsHidlTest;
class SensorsHalDeathRecipient : public ::android::hardware::hidl_death_recipient {
virtual void serviceDied(
uint64_t cookie,
const ::android::wp<::android::hidl::base::V1_0::IBase>& service) override;
};
class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase {
public:
using Event = ::android::hardware::sensors::V1_0::Event;
@@ -83,6 +90,11 @@ class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase {
*/
sp<android::hardware::sensors::V2_0::ISensors> mSensors;
/**
* Monitors the HAL for crashes, triggering test failure if seen
*/
sp<SensorsHalDeathRecipient> mDeathRecipient = new SensorsHalDeathRecipient();
/**
* Type used to simplify the creation of the Event FMQ
*/

View File

@@ -14,8 +14,6 @@
* limitations under the License.
*/
#define LOG_TAG "sensors_hidl_hal_test"
#include "SensorsHidlEnvironmentV2_0.h"
#include "sensors-vts-utils/SensorsHidlTestBase.h"
#include "sensors-vts-utils/SensorsTestSharedMemory.h"
@@ -40,6 +38,10 @@ using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
using ::android::hardware::sensors::V1_0::SensorStatus;
using ::android::hardware::sensors::V1_0::SharedMemType;
using ::android::hardware::sensors::V1_0::Vec3;
using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::milliseconds;
using std::chrono::nanoseconds;
constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
@@ -69,9 +71,9 @@ class EventCallback : public IEventCallback {
}
void waitForFlushEvents(const std::vector<SensorInfo>& sensorsToWaitFor,
int32_t numCallsToFlush, int64_t timeoutMs) {
int32_t numCallsToFlush, milliseconds timeout) {
std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
mFlushCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
mFlushCV.wait_for(lock, timeout,
[&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
}
@@ -80,10 +82,9 @@ class EventCallback : public IEventCallback {
return mEventMap[sensorHandle];
}
void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t timeoutMs) {
void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor, milliseconds timeout) {
std::unique_lock<std::recursive_mutex> lock(mEventMutex);
mEventCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
[&] { return eventsReceived(sensorsToWaitFor); });
mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); });
}
protected:
@@ -117,7 +118,13 @@ class EventCallback : public IEventCallback {
// The main test class for SENSORS HIDL HAL.
class SensorsHidlTest : public SensorsHidlTestBase {
protected:
public:
virtual void SetUp() override {
// Ensure that we have a valid environment before performing tests
ASSERT_NE(getSensors(), nullptr);
}
protected:
SensorInfo defaultSensorByType(SensorType type) override;
std::vector<SensorInfo> getSensorsList();
// implementation wrapper
@@ -169,19 +176,21 @@ class SensorsHidlTest : public SensorsHidlTestBase {
// Helper functions
void activateAllSensors(bool enable);
std::vector<SensorInfo> getNonOneShotSensors();
std::vector<SensorInfo> getNonOneShotAndNonSpecialSensors();
std::vector<SensorInfo> getOneShotSensors();
std::vector<SensorInfo> getInjectEventSensors();
int32_t getInvalidSensorHandle();
bool getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType, RateLevel* rate);
void verifyDirectChannel(SharedMemType memType);
void verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
std::shared_ptr<SensorsTestSharedMemory> mem,
int32_t* directChannelHandle);
void verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
int32_t* directChannelHandle, bool supportsSharedMemType,
bool supportsAnyDirectChannel);
void verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
int32_t directChannelHandle);
void verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
int32_t directChannelHandle);
int32_t directChannelHandle, bool directChannelSupported);
void verifyUnregisterDirectChannel(int32_t directChannelHandle, bool directChannelSupported);
void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel);
void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
bool* supportsAnyDirectChannel);
};
Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -250,6 +259,18 @@ std::vector<SensorInfo> SensorsHidlTest::getNonOneShotSensors() {
return sensors;
}
std::vector<SensorInfo> SensorsHidlTest::getNonOneShotAndNonSpecialSensors() {
std::vector<SensorInfo> sensors;
for (const SensorInfo& info : getSensorsList()) {
SensorFlagBits reportMode = extractReportMode(info.flags);
if (reportMode != SensorFlagBits::ONE_SHOT_MODE &&
reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) {
sensors.push_back(info);
}
}
return sensors;
}
std::vector<SensorInfo> SensorsHidlTest::getOneShotSensors() {
std::vector<SensorInfo> sensors;
for (const SensorInfo& info : getSensorsList()) {
@@ -368,7 +389,7 @@ TEST_F(SensorsHidlTest, InjectSensorEventData) {
}
// Wait for events to be written back to the Event FMQ
callback.waitForEvents(sensors, 1000 /* timeoutMs */);
callback.waitForEvents(sensors, milliseconds(1000) /* timeout */);
for (const auto& s : sensors) {
auto events = callback.getEvents(s.sensorHandle);
@@ -614,6 +635,9 @@ TEST_F(SensorsHidlTest, CallInitializeTwice) {
std::unique_ptr<SensorsHidlEnvironmentTest> newEnv =
std::make_unique<SensorsHidlEnvironmentTest>();
newEnv->HidlSetUp();
if (HasFatalFailure()) {
return; // Exit early if setting up the new environment failed
}
activateAllSensors(true);
// Verify that the old environment does not receive any events
@@ -626,8 +650,11 @@ TEST_F(SensorsHidlTest, CallInitializeTwice) {
newEnv->HidlTearDown();
// Restore the test environment for future tests
SensorsHidlEnvironmentV2_0::Instance()->HidlTearDown();
SensorsHidlEnvironmentV2_0::Instance()->HidlSetUp();
getEnvironment()->HidlTearDown();
getEnvironment()->HidlSetUp();
if (HasFatalFailure()) {
return; // Exit early if resetting the environment failed
}
// Ensure that the original environment is receiving events
activateAllSensors(true);
@@ -646,8 +673,11 @@ TEST_F(SensorsHidlTest, CleanupConnectionsOnInitialize) {
// Clear the active sensor handles so they are not disabled during TearDown
auto handles = mSensorHandles;
mSensorHandles.clear();
getEnvironment()->TearDown();
getEnvironment()->SetUp();
getEnvironment()->HidlTearDown();
getEnvironment()->HidlSetUp();
if (HasFatalFailure()) {
return; // Exit early if resetting the environment failed
}
// Verify no events are received until sensors are re-activated
ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0);
@@ -686,7 +716,7 @@ void SensorsHidlTest::runFlushTest(const std::vector<SensorInfo>& sensors, bool
}
// Wait up to one second for the flush events
callback.waitForFlushEvents(sensors, flushCalls, 1000 /* timeoutMs */);
callback.waitForFlushEvents(sensors, flushCalls, milliseconds(1000) /* timeout */);
// Deactivate all sensors after waiting for flush events so pending flush events are not
// abandoned by the HAL.
@@ -761,7 +791,12 @@ TEST_F(SensorsHidlTest, Batch) {
activateAllSensors(false /* enable */);
for (const SensorInfo& sensor : getSensorsList()) {
// Call batch on inactive sensor
ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
// One shot sensors have minDelay set to -1 which is an invalid
// parameter. Use 0 instead to avoid errors.
int64_t samplingPeriodNs = extractReportMode(sensor.flags) == SensorFlagBits::ONE_SHOT_MODE
? 0
: sensor.minDelay;
ASSERT_EQ(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */),
Result::OK);
// Activate the sensor
@@ -807,17 +842,19 @@ TEST_F(SensorsHidlTest, Activate) {
}
TEST_F(SensorsHidlTest, NoStaleEvents) {
constexpr int64_t kFiveHundredMilliseconds = 500 * 1000;
constexpr int64_t kOneSecond = 1000 * 1000;
constexpr milliseconds kFiveHundredMs(500);
constexpr milliseconds kOneSecond(1000);
// Register the callback to receive sensor events
EventCallback callback;
getEnvironment()->registerCallback(&callback);
const std::vector<SensorInfo> sensors = getSensorsList();
int32_t maxMinDelay = 0;
for (const SensorInfo& sensor : getSensorsList()) {
maxMinDelay = std::max(maxMinDelay, sensor.minDelay);
// This test is not valid for one-shot or special-report-mode sensors
const std::vector<SensorInfo> sensors = getNonOneShotAndNonSpecialSensors();
milliseconds maxMinDelay(0);
for (const SensorInfo& sensor : sensors) {
milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
}
// Activate the sensors so that they start generating events
@@ -826,33 +863,46 @@ TEST_F(SensorsHidlTest, NoStaleEvents) {
// According to the CDD, the first sample must be generated within 400ms + 2 * sample_time
// and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount
// of time to guarantee that a sample has arrived.
callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay));
callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
activateAllSensors(false);
// Save the last received event for each sensor
std::map<int32_t, int64_t> lastEventTimestampMap;
for (const SensorInfo& sensor : sensors) {
ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
lastEventTimestampMap[sensor.sensorHandle] =
callback.getEvents(sensor.sensorHandle).back().timestamp;
// Some on-change sensors may not report an event without stimulus
if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) {
ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
}
if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
lastEventTimestampMap[sensor.sensorHandle] =
callback.getEvents(sensor.sensorHandle).back().timestamp;
}
}
// Allow some time to pass, reset the callback, then reactivate the sensors
usleep(kOneSecond + (5 * maxMinDelay));
usleep(duration_cast<microseconds>(kOneSecond + (5 * maxMinDelay)).count());
callback.reset();
activateAllSensors(true);
callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay));
callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
activateAllSensors(false);
for (const SensorInfo& sensor : sensors) {
// Skip sensors that did not previously report an event
if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
continue;
}
// Skip on-change sensors that do not consistently report an initial event
if (callback.getEvents(sensor.sensorHandle).size() < 1) {
continue;
}
// Ensure that the first event received is not stale by ensuring that its timestamp is
// sufficiently different from the previous event
const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
int64_t delta = newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle];
ASSERT_GE(delta, kFiveHundredMilliseconds + (3 * sensor.minDelay));
milliseconds delta = duration_cast<milliseconds>(
nanoseconds(newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
milliseconds sensorMinDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay));
}
getEnvironment()->unregisterCallback();
}
void SensorsHidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
@@ -861,21 +911,43 @@ void SensorsHidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directCha
[&](Result result, int32_t reportToken) {
if (isDirectReportRateSupported(sensor, rateLevel)) {
ASSERT_EQ(result, Result::OK);
ASSERT_GT(reportToken, 0);
if (rateLevel != RateLevel::STOP) {
ASSERT_GT(reportToken, 0);
}
} else {
ASSERT_EQ(result, Result::BAD_VALUE);
}
});
}
void SensorsHidlTest::verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
std::shared_ptr<SensorsTestSharedMemory> mem,
int32_t* directChannelHandle) {
void SensorsHidlTest::queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
bool* supportsAnyDirectChannel) {
*supportsSharedMemType = false;
*supportsAnyDirectChannel = false;
for (const SensorInfo& curSensor : getSensorsList()) {
if (isDirectChannelTypeSupported(curSensor, memType)) {
*supportsSharedMemType = true;
}
if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM) ||
isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
*supportsAnyDirectChannel = true;
}
if (*supportsSharedMemType && *supportsAnyDirectChannel) {
break;
}
}
}
void SensorsHidlTest::verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
int32_t* directChannelHandle,
bool supportsSharedMemType,
bool supportsAnyDirectChannel) {
char* buffer = mem->getBuffer();
memset(buffer, 0xff, mem->getSize());
registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
if (isDirectChannelTypeSupported(sensor, memType)) {
if (supportsSharedMemType) {
ASSERT_EQ(result, Result::OK);
ASSERT_GT(channelHandle, 0);
@@ -884,7 +956,9 @@ void SensorsHidlTest::verifyRegisterDirectChannel(const SensorInfo& sensor, Shar
ASSERT_EQ(buffer[i], 0x00);
}
} else {
ASSERT_EQ(result, Result::INVALID_OPERATION);
Result expectedResult =
supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
ASSERT_EQ(result, expectedResult);
ASSERT_EQ(channelHandle, -1);
}
*directChannelHandle = channelHandle;
@@ -892,7 +966,7 @@ void SensorsHidlTest::verifyRegisterDirectChannel(const SensorInfo& sensor, Shar
}
void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
int32_t directChannelHandle) {
int32_t directChannelHandle, bool supportsAnyDirectChannel) {
if (isDirectChannelTypeSupported(sensor, memType)) {
// Verify that each rate level is properly supported
checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);
@@ -908,22 +982,22 @@ void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType me
-1 /* sensorHandle */, directChannelHandle, RateLevel::STOP,
[](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
} else {
// Direct channel is not supported for this SharedMemType
// directChannelHandle will be -1 here, HAL should either reject it as a bad value if there
// is some level of direct channel report, otherwise return INVALID_OPERATION if direct
// channel is not supported at all
Result expectedResult =
supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL,
[](Result result, int32_t /* reportToken */) {
ASSERT_EQ(result, Result::INVALID_OPERATION);
[expectedResult](Result result, int32_t /* reportToken */) {
ASSERT_EQ(result, expectedResult);
});
}
}
void SensorsHidlTest::verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
int32_t directChannelHandle) {
Result result = unregisterDirectChannel(directChannelHandle);
if (isDirectChannelTypeSupported(sensor, memType)) {
ASSERT_EQ(result, Result::OK);
} else {
ASSERT_EQ(result, Result::INVALID_OPERATION);
}
void SensorsHidlTest::verifyUnregisterDirectChannel(int32_t directChannelHandle,
bool supportsAnyDirectChannel) {
Result expectedResult = supportsAnyDirectChannel ? Result::OK : Result::INVALID_OPERATION;
ASSERT_EQ(unregisterDirectChannel(directChannelHandle), expectedResult);
}
void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
@@ -934,11 +1008,16 @@ void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
SensorsTestSharedMemory::create(memType, kMemSize));
ASSERT_NE(mem, nullptr);
bool supportsSharedMemType;
bool supportsAnyDirectChannel;
queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel);
for (const SensorInfo& sensor : getSensorsList()) {
int32_t directChannelHandle = 0;
verifyRegisterDirectChannel(sensor, memType, mem, &directChannelHandle);
verifyConfigure(sensor, memType, directChannelHandle);
verifyUnregisterDirectChannel(sensor, memType, directChannelHandle);
verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType,
supportsAnyDirectChannel);
verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel);
verifyUnregisterDirectChannel(directChannelHandle, supportsAnyDirectChannel);
}
}
@@ -1030,8 +1109,11 @@ TEST_F(SensorsHidlTest, CleanupDirectConnectionOnInitialize) {
// Clear the active direct connections so they are not stopped during TearDown
auto handles = mDirectChannelHandles;
mDirectChannelHandles.clear();
getEnvironment()->TearDown();
getEnvironment()->SetUp();
getEnvironment()->HidlTearDown();
getEnvironment()->HidlSetUp();
if (HasFatalFailure()) {
return; // Exit early if resetting the environment failed
}
// Attempt to configure the direct channel and expect it to fail
configDirectReport(

View File

@@ -16,6 +16,7 @@
cc_library_static {
name: "VtsHalSensorsTargetTestUtils",
cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
srcs: [
"GrallocWrapper.cpp",
"SensorsHidlEnvironmentBase.cpp",
@@ -30,7 +31,10 @@ cc_library_static {
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
"VtsHalHidlTargetTestBase",
],

View File

@@ -14,211 +14,264 @@
* limitations under the License.
*/
#define LOG_TAG "GrallocWrapper"
#include "GrallocWrapper.h"
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.1/IMapper.h>
#include <android/hardware/graphics/mapper/3.0/IMapper.h>
#include <utils/Log.h>
#include <cinttypes>
#include <type_traits>
using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
using ::android::hardware::graphics::common::V1_0::BufferUsage;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
// This is a typedef to the same underlying type across v2.0 and v3.0
using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
namespace android {
GrallocWrapper::GrallocWrapper() {
init();
// Since we use the same APIs across allocator/mapper HALs but they have major
// version differences (meaning they are not related through inheritance), we
// create a common interface abstraction for the IAllocator + IMapper combination
// (major versions need to match in the current HALs, e.g. IAllocator 3.0 needs to
// be paired with IMapper 3.0, so these are tied together)
class IGrallocHalWrapper {
public:
virtual ~IGrallocHalWrapper() = default;
// IAllocator
virtual std::string dumpDebugInfo() = 0;
virtual native_handle_t* allocate(uint32_t size) = 0;
virtual void freeBuffer(native_handle_t* bufferHandle) = 0;
// IMapper
virtual void* lock(native_handle_t* bufferHandle) = 0;
virtual void unlock(native_handle_t* bufferHandle) = 0;
};
namespace {
bool failed(Error2 error) {
return (error != Error2::NONE);
}
bool failed(Error3 error) {
return (error != Error3::NONE);
}
void GrallocWrapper::init() {
mAllocator = allocator2::IAllocator::getService();
if (mAllocator == nullptr) {
ALOGE("Failed to get allocator service");
}
mMapper = mapper2::IMapper::getService();
if (mMapper == nullptr) {
ALOGE("Failed to get mapper service");
}
if (mMapper->isRemote()) {
ALOGE("Mapper is not in passthrough mode");
}
}
GrallocWrapper::~GrallocWrapper() {
for (auto bufferHandle : mClonedBuffers) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
native_handle_close(buffer);
native_handle_delete(buffer);
}
mClonedBuffers.clear();
for (auto bufferHandle : mImportedBuffers) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
if (mMapper->freeBuffer(buffer) != mapper2::Error::NONE) {
ALOGE("Failed to free buffer %p", buffer);
// Since all the type and function names are the same for the things we use across the major HAL
// versions, we use template magic to avoid repeating ourselves.
template <typename AllocatorT, typename MapperT>
class GrallocHalWrapper : public IGrallocHalWrapper {
public:
GrallocHalWrapper(const sp<AllocatorT>& allocator, const sp<MapperT>& mapper)
: mAllocator(allocator), mMapper(mapper) {
if (mapper->isRemote()) {
ALOGE("Mapper is in passthrough mode");
}
}
mImportedBuffers.clear();
}
sp<allocator2::IAllocator> GrallocWrapper::getAllocator() const {
return mAllocator;
}
virtual std::string dumpDebugInfo() override;
virtual native_handle_t* allocate(uint32_t size) override;
virtual void freeBuffer(native_handle_t* bufferHandle) override;
std::string GrallocWrapper::dumpDebugInfo() {
virtual void* lock(native_handle_t* bufferHandle) override;
virtual void unlock(native_handle_t* bufferHandle) override;
private:
static constexpr uint64_t kBufferUsage =
static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
sp<AllocatorT> mAllocator;
sp<MapperT> mMapper;
BufferDescriptor getDescriptor(uint32_t size);
native_handle_t* importBuffer(const hidl_handle& rawHandle);
};
template <typename AllocatorT, typename MapperT>
std::string GrallocHalWrapper<AllocatorT, MapperT>::dumpDebugInfo() {
std::string debugInfo;
mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
mAllocator->dumpDebugInfo([&](const hidl_string& tmpDebugInfo) { debugInfo = tmpDebugInfo; });
return debugInfo;
}
const native_handle_t* GrallocWrapper::cloneBuffer(const hardware::hidl_handle& rawHandle) {
const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
template <typename AllocatorT, typename MapperT>
native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::allocate(uint32_t size) {
constexpr uint32_t kBufferCount = 1;
BufferDescriptor descriptor = getDescriptor(size);
native_handle_t* bufferHandle = nullptr;
if (bufferHandle) {
mClonedBuffers.insert(bufferHandle);
}
auto callback = [&](auto error, uint32_t /*stride*/, const hidl_vec<hidl_handle>& buffers) {
if (failed(error)) {
ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error));
} else if (buffers.size() != kBufferCount) {
ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", buffers.size(),
kBufferCount);
} else {
bufferHandle = importBuffer(buffers[0]);
}
};
mAllocator->allocate(descriptor, kBufferCount, callback);
return bufferHandle;
}
std::vector<const native_handle_t*> GrallocWrapper::allocate(
const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import, uint32_t* outStride) {
std::vector<const native_handle_t*> bufferHandles;
bufferHandles.reserve(count);
mAllocator->allocate(descriptor, count,
[&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
if (mapper2::Error::NONE != tmpError) {
ALOGE("Failed to allocate buffers");
}
if (count != tmpBuffers.size()) {
ALOGE("Invalid buffer array");
}
for (uint32_t i = 0; i < count; i++) {
if (import) {
bufferHandles.push_back(importBuffer(tmpBuffers[i]));
} else {
bufferHandles.push_back(cloneBuffer(tmpBuffers[i]));
}
}
if (outStride) {
*outStride = tmpStride;
}
});
return bufferHandles;
template <typename AllocatorT, typename MapperT>
void GrallocHalWrapper<AllocatorT, MapperT>::freeBuffer(native_handle_t* bufferHandle) {
auto error = mMapper->freeBuffer(bufferHandle);
if (!error.isOk() || failed(error)) {
ALOGE("Failed to free buffer %p", bufferHandle);
}
}
const native_handle_t* GrallocWrapper::allocate(
const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
uint32_t* outStride) {
mapper2::BufferDescriptor descriptor = createDescriptor(descriptorInfo);
auto buffers = allocate(descriptor, 1, import, outStride);
return buffers[0];
}
template <typename AllocatorT, typename MapperT>
BufferDescriptor GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) {
typename MapperT::BufferDescriptorInfo descriptorInfo = {
.width = size,
.height = 1,
.layerCount = 1,
.usage = kBufferUsage,
.format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
};
sp<mapper2::IMapper> GrallocWrapper::getMapper() const {
return mMapper;
}
mapper2::BufferDescriptor GrallocWrapper::createDescriptor(
const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo) {
mapper2::BufferDescriptor descriptor;
mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
if (tmpError != mapper2::Error::NONE) {
ALOGE("Failed to create descriptor");
BufferDescriptor descriptor;
auto callback = [&](auto error, const BufferDescriptor& tmpDescriptor) {
if (failed(error)) {
ALOGE("Failed to create descriptor: %" PRId32, static_cast<int32_t>(error));
} else {
descriptor = tmpDescriptor;
}
descriptor = tmpDescriptor;
});
};
mMapper->createDescriptor(descriptorInfo, callback);
return descriptor;
}
const native_handle_t* GrallocWrapper::importBuffer(const hardware::hidl_handle& rawHandle) {
const native_handle_t* bufferHandle = nullptr;
mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
if (tmpError != mapper2::Error::NONE) {
ALOGE("Failed to import buffer %p", rawHandle.getNativeHandle());
}
bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
});
template <typename AllocatorT, typename MapperT>
native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::importBuffer(
const hidl_handle& rawHandle) {
native_handle_t* bufferHandle = nullptr;
if (bufferHandle) {
mImportedBuffers.insert(bufferHandle);
}
mMapper->importBuffer(rawHandle, [&](auto error, void* tmpBuffer) {
if (failed(error)) {
ALOGE("Failed to import buffer %p: %" PRId32, rawHandle.getNativeHandle(),
static_cast<int32_t>(error));
} else {
bufferHandle = static_cast<native_handle_t*>(tmpBuffer);
}
});
return bufferHandle;
}
void GrallocWrapper::freeBuffer(const native_handle_t* bufferHandle) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
if (mImportedBuffers.erase(bufferHandle)) {
mapper2::Error error = mMapper->freeBuffer(buffer);
if (error != mapper2::Error::NONE) {
ALOGE("Failed to free %p", buffer);
}
} else {
mClonedBuffers.erase(bufferHandle);
native_handle_close(buffer);
native_handle_delete(buffer);
}
}
void* GrallocWrapper::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const mapper2::IMapper::Rect& accessRegion, int acquireFence) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
hardware::hidl_handle acquireFenceHandle;
if (acquireFence >= 0) {
auto h = native_handle_init(acquireFenceStorage, 1, 0);
h->data[0] = acquireFence;
acquireFenceHandle = h;
}
template <typename AllocatorT, typename MapperT>
void* GrallocHalWrapper<AllocatorT, MapperT>::lock(native_handle_t* bufferHandle) {
// Per the HAL, all-zeros Rect means the entire buffer
typename MapperT::Rect accessRegion = {};
hidl_handle acquireFenceHandle; // No fence needed, already safe to lock
void* data = nullptr;
mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
[&](const auto& tmpError, const auto& tmpData) {
if (tmpError != mapper2::Error::NONE) {
ALOGE("Failed to lock buffer %p", buffer);
mMapper->lock(bufferHandle, kBufferUsage, accessRegion, acquireFenceHandle,
[&](auto error, void* tmpData, ...) { // V3_0 passes extra args we don't use
if (failed(error)) {
ALOGE("Failed to lock buffer %p: %" PRId32, bufferHandle,
static_cast<int32_t>(error));
} else {
data = tmpData;
}
data = tmpData;
});
if (acquireFence >= 0) {
close(acquireFence);
}
return data;
}
int GrallocWrapper::unlock(const native_handle_t* bufferHandle) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
int releaseFence = -1;
mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
if (tmpError != mapper2::Error::NONE) {
ALOGE("Failed to unlock buffer %p", buffer);
}
auto fenceHandle = tmpReleaseFence.getNativeHandle();
if (fenceHandle) {
if (fenceHandle->numInts != 0) {
ALOGE("Invalid fence handle %p", fenceHandle);
}
if (fenceHandle->numFds == 1) {
releaseFence = dup(fenceHandle->data[0]);
if (releaseFence < 0) {
ALOGE("Failed to dup fence fd");
}
} else {
if (fenceHandle->numFds != 0) {
ALOGE("Invalid fence handle %p", fenceHandle);
}
}
template <typename AllocatorT, typename MapperT>
void GrallocHalWrapper<AllocatorT, MapperT>::unlock(native_handle_t* bufferHandle) {
mMapper->unlock(bufferHandle, [&](auto error, const hidl_handle& /*releaseFence*/) {
if (failed(error)) {
ALOGE("Failed to unlock buffer %p: %" PRId32, bufferHandle,
static_cast<int32_t>(error));
}
});
}
return releaseFence;
} // anonymous namespace
GrallocWrapper::GrallocWrapper() {
sp<IAllocator3> allocator3 = IAllocator3::getService();
sp<IMapper3> mapper3 = IMapper3::getService();
if (allocator3 != nullptr && mapper3 != nullptr) {
mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
new GrallocHalWrapper<IAllocator3, IMapper3>(allocator3, mapper3));
} else {
ALOGD("Graphics HALs 3.0 not found (allocator %d mapper %d), falling back to 2.x",
(allocator3 != nullptr), (mapper3 != nullptr));
sp<IAllocator2> allocator2 = IAllocator2::getService();
sp<IMapper2> mapper2 = IMapper2_1::getService();
if (mapper2 == nullptr) {
mapper2 = IMapper2::getService();
}
if (allocator2 != nullptr && mapper2 != nullptr) {
mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
new GrallocHalWrapper<IAllocator2, IMapper2>(allocator2, mapper2));
} else {
ALOGE("Couldn't open 2.x/3.0 graphics HALs (2.x allocator %d mapper %d)",
(allocator2 != nullptr), (mapper2 != nullptr));
}
}
}
GrallocWrapper::~GrallocWrapper() {
for (auto bufferHandle : mAllocatedBuffers) {
mGrallocHal->unlock(bufferHandle);
mGrallocHal->freeBuffer(bufferHandle);
}
mAllocatedBuffers.clear();
}
std::string GrallocWrapper::dumpDebugInfo() {
return mGrallocHal->dumpDebugInfo();
}
std::pair<native_handle_t*, void*> GrallocWrapper::allocate(uint32_t size) {
native_handle_t* bufferHandle = mGrallocHal->allocate(size);
void* buffer = nullptr;
if (bufferHandle) {
buffer = mGrallocHal->lock(bufferHandle);
if (buffer) {
mAllocatedBuffers.insert(bufferHandle);
} else {
mGrallocHal->freeBuffer(bufferHandle);
bufferHandle = nullptr;
}
}
return std::make_pair<>(bufferHandle, buffer);
}
void GrallocWrapper::freeBuffer(native_handle_t* bufferHandle) {
if (mAllocatedBuffers.erase(bufferHandle)) {
mGrallocHal->unlock(bufferHandle);
mGrallocHal->freeBuffer(bufferHandle);
}
}
} // namespace android

View File

@@ -29,7 +29,9 @@ void SensorsHidlEnvironmentBase::HidlSetUp() {
void SensorsHidlEnvironmentBase::HidlTearDown() {
mStopThread = true;
mPollThread.detach();
if (mPollThread.joinable()) {
mPollThread.detach();
}
}
void SensorsHidlEnvironmentBase::catEvents(std::vector<Event>* output) {

View File

@@ -119,32 +119,13 @@ SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size
}
case SharedMemType::GRALLOC: {
mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
if (mGrallocWrapper->getAllocator() == nullptr ||
mGrallocWrapper->getMapper() == nullptr) {
if (!mGrallocWrapper->isInitialized()) {
break;
}
using android::hardware::graphics::common::V1_0::BufferUsage;
using android::hardware::graphics::common::V1_0::PixelFormat;
mapper2::IMapper::BufferDescriptorInfo buf_desc_info = {
.width = static_cast<uint32_t>(size),
.height = 1,
.layerCount = 1,
.usage = static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA |
BufferUsage::CPU_READ_OFTEN),
.format = PixelFormat::BLOB};
handle = const_cast<native_handle_t*>(mGrallocWrapper->allocate(buf_desc_info));
if (handle != nullptr) {
mapper2::IMapper::Rect region{0, 0, static_cast<int32_t>(buf_desc_info.width),
static_cast<int32_t>(buf_desc_info.height)};
buffer = static_cast<char*>(
mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1));
if (buffer != nullptr) {
break;
}
mGrallocWrapper->freeBuffer(handle);
handle = nullptr;
}
std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
handle = buf.first;
buffer = static_cast<char*>(buf.second);
break;
}
default:
@@ -175,9 +156,7 @@ SensorsTestSharedMemory::~SensorsTestSharedMemory() {
}
case SharedMemType::GRALLOC: {
if (mSize != 0) {
mGrallocWrapper->unlock(mNativeHandle);
mGrallocWrapper->freeBuffer(mNativeHandle);
mNativeHandle = nullptr;
mSize = 0;
}

View File

@@ -14,66 +14,47 @@
* limitations under the License.
*/
#ifndef GRALLO_WRAPPER_H_
#define GRALLO_WRAPPER_H_
#pragma once
#include <utils/NativeHandle.h>
#include <memory>
#include <string>
#include <unordered_set>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
namespace allocator2 = ::android::hardware::graphics::allocator::V2_0;
namespace mapper2 = ::android::hardware::graphics::mapper::V2_0;
#include <utility>
namespace android {
// Modified from hardware/interfaces/graphics/mapper/2.0/vts/functional/
class IGrallocHalWrapper;
// Reference: hardware/interfaces/graphics/mapper/2.0/vts/functional/
class GrallocWrapper {
public:
GrallocWrapper();
~GrallocWrapper();
sp<allocator2::IAllocator> getAllocator() const;
sp<mapper2::IMapper> getMapper() const;
// After constructing this object, this function must be called to check the result. If it
// returns false, other methods are not safe to call.
bool isInitialized() const { return (mGrallocHal != nullptr); };
std::string dumpDebugInfo();
// When import is false, this simply calls IAllocator::allocate. When import
// is true, the returned buffers are also imported into the mapper.
//
// Either case, the returned buffers must be freed with freeBuffer.
std::vector<const native_handle_t*> allocate(const mapper2::BufferDescriptor& descriptor,
uint32_t count, bool import = true,
uint32_t* outStride = nullptr);
const native_handle_t* allocate(const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo,
bool import = true, uint32_t* outStride = nullptr);
// Allocates a gralloc buffer suitable for direct channel sensors usage with the given size.
// The buffer should be freed using freeBuffer when it's not needed anymore; otherwise it'll
// be freed when this object is destroyed.
// Returns a handle to the buffer, and a CPU-accessible pointer for reading. On failure, both
// will be set to nullptr.
std::pair<native_handle_t*, void*> allocate(uint32_t size);
mapper2::BufferDescriptor createDescriptor(
const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo);
// Releases a gralloc buffer previously returned by allocate()
void freeBuffer(native_handle_t* bufferHandle);
const native_handle_t* importBuffer(const hardware::hidl_handle& rawHandle);
void freeBuffer(const native_handle_t* bufferHandle);
// We use fd instead of hardware::hidl_handle in these functions to pass fences
// in and out of the mapper. The ownership of the fd is always transferred
// with each of these functions.
void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const mapper2::IMapper::Rect& accessRegion, int acquireFence);
int unlock(const native_handle_t* bufferHandle);
private:
void init();
const native_handle_t* cloneBuffer(const hardware::hidl_handle& rawHandle);
sp<allocator2::IAllocator> mAllocator;
sp<mapper2::IMapper> mMapper;
private:
std::unique_ptr<IGrallocHalWrapper> mGrallocHal;
// Keep track of all cloned and imported handles. When a test fails with
// ASSERT_*, the destructor will free the handles for the test.
std::unordered_set<const native_handle_t*> mClonedBuffers;
std::unordered_set<const native_handle_t*> mImportedBuffers;
std::unordered_set<native_handle_t*> mAllocatedBuffers;
};
} // namespace android
#endif // GRALLO_WRAPPER_H_

View File

@@ -56,6 +56,9 @@ class HostapdHidlTest : public ::testing::VtsHalHidlTargetTestBase {
protected:
std::string getPrimaryWlanIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
auto res = property_get("ro.vendor.wifi.sap.interface",
buffer.data(), nullptr);
if (res > 0) return buffer.data();
property_get("wifi.interface", buffer.data(), "wlan0");
return buffer.data();
}