mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge "Merge Coral/Flame into AOSP master"
This commit is contained in:
@@ -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> ®istered) {
|
||||
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> ®istered) {
|
||||
for (const auto &instance : registered) {
|
||||
sp<ICryptoFactory> cryptoFactory =
|
||||
|
||||
@@ -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_++;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user