123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "services/device/generic_sensor/platform_sensor_chromeos.h"
- #include <memory>
- #include <utility>
- #include "base/memory/scoped_refptr.h"
- #include "base/run_loop.h"
- #include "base/test/gmock_callback_support.h"
- #include "base/test/task_environment.h"
- #include "base/time/time.h"
- #include "chromeos/components/sensors/fake_sensor_device.h"
- #include "services/device/generic_sensor/fake_platform_sensor_and_provider.h"
- #include "services/device/generic_sensor/platform_sensor_util.h"
- #include "services/device/public/cpp/generic_sensor/sensor_traits.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace device {
- namespace {
- constexpr int kFakeDeviceId = 1;
- constexpr char kAccelerometerChannels[][10] = {"accel_x", "accel_y", "accel_z"};
- constexpr char kGyroscopeChannels[][10] = {"anglvel_x", "anglvel_y",
- "anglvel_z"};
- constexpr char kMagnetometerChannels[][10] = {"magn_x", "magn_y", "magn_z"};
- constexpr char kGravityChannels[][10] = {"gravity_x", "gravity_y", "gravity_z"};
- constexpr double kScaleValue = 10.0;
- // The number of axes for which there are accelerometer readings.
- constexpr uint32_t kNumberOfAxes = 3u;
- constexpr int64_t kFakeSampleData = 1;
- constexpr int64_t kFakeAxesSampleData[] = {1, 2, 3};
- constexpr int64_t kFakeTimestampData = 163176689212344ll;
- } // namespace
- class PlatformSensorChromeOSTestBase {
- protected:
- void SetUpBase() {
- provider_ = std::make_unique<FakePlatformSensorProvider>();
- pending_receiver_ = sensor_device_remote_.BindNewPipeAndPassReceiver();
- }
- void InitSensorDevice(
- std::vector<chromeos::sensors::FakeSensorDevice::ChannelData>
- channels_data) {
- sensor_device_ = std::make_unique<chromeos::sensors::FakeSensorDevice>(
- std::move(channels_data));
- receiver_id_ = sensor_device_->AddReceiver(std::move(pending_receiver_));
- }
- void DisableFirstChannel() {
- DCHECK(sensor_device_.get());
- sensor_device_->SetChannelsEnabledWithId(receiver_id_, {0}, false);
- }
- void OnSensorDeviceDisconnect(uint32_t custom_reason_code,
- const std::string& description) {
- custom_reason_code_ = custom_reason_code;
- }
- std::unique_ptr<chromeos::sensors::FakeSensorDevice> sensor_device_;
- std::unique_ptr<FakePlatformSensorProvider> provider_;
- scoped_refptr<PlatformSensorChromeOS> sensor_;
- mojo::ReceiverId receiver_id_;
- mojo::Remote<chromeos::sensors::mojom::SensorDevice> sensor_device_remote_;
- mojo::PendingReceiver<chromeos::sensors::mojom::SensorDevice>
- pending_receiver_;
- absl::optional<uint32_t> custom_reason_code_;
- base::test::SingleThreadTaskEnvironment task_environment;
- };
- class PlatformSensorChromeOSOneChannelTest
- : public PlatformSensorChromeOSTestBase,
- public ::testing::TestWithParam<
- std::pair<mojom::SensorType, const char*>> {
- protected:
- void SetUp() override {
- SetUpBase();
- auto type = GetParam().first;
- sensor_ = base::MakeRefCounted<PlatformSensorChromeOS>(
- kFakeDeviceId, type, provider_->GetSensorReadingBuffer(type),
- provider_.get(),
- base::BindOnce(
- &PlatformSensorChromeOSOneChannelTest::OnSensorDeviceDisconnect,
- base::Unretained(this)),
- kScaleValue, std::move(sensor_device_remote_));
- EXPECT_EQ(sensor_->GetReportingMode(),
- type == mojom::SensorType::AMBIENT_LIGHT
- ? mojom::ReportingMode::ON_CHANGE
- : mojom::ReportingMode::CONTINUOUS);
- EXPECT_EQ(sensor_->GetDefaultConfiguration().frequency(),
- GetSensorMaxAllowedFrequency(type));
- }
- void SetChannels(const char channel[], bool set_first_channel) {
- std::vector<chromeos::sensors::FakeSensorDevice::ChannelData> channels_data(
- set_first_channel ? 2 : 1);
- if (set_first_channel) {
- channels_data.front().id = channel;
- channels_data.front().sample_data = kFakeSampleData;
- }
- channels_data.back().id = chromeos::sensors::mojom::kTimestampChannel;
- channels_data.back().sample_data = kFakeTimestampData;
- InitSensorDevice(std::move(channels_data));
- }
- SensorReadingSingle& GetSensorReadingSingle(SensorReading& reading) {
- switch (GetParam().first) {
- case mojom::SensorType::AMBIENT_LIGHT:
- return reading.als;
- default:
- LOG(FATAL) << "Invalid type: " << GetParam().first;
- return reading.als;
- }
- }
- void GetRoundedSensorReadingSingle(SensorReadingSingle* reading_single) {
- reading_single->value = kFakeSampleData * kScaleValue;
- reading_single->timestamp =
- base::Nanoseconds(kFakeTimestampData).InSecondsF();
- // No need to do rounding for these types of sensors.
- }
- void WaitForAndCheckReading(
- testing::NiceMock<MockPlatformSensorClient>* client) {
- base::RunLoop loop;
- // Wait until a sample is received.
- EXPECT_CALL(*client, OnSensorReadingChanged(GetParam().first))
- .WillOnce(base::test::RunOnceClosure(loop.QuitClosure()));
- loop.Run();
- SensorReading reading;
- EXPECT_TRUE(sensor_->GetLatestReading(&reading));
- const auto& reading_single = GetSensorReadingSingle(reading);
- SensorReadingSingle rounded_reading_single;
- GetRoundedSensorReadingSingle(&rounded_reading_single);
- EXPECT_EQ(reading_single.value, rounded_reading_single.value);
- EXPECT_EQ(reading_single.timestamp, rounded_reading_single.timestamp);
- }
- };
- TEST_P(PlatformSensorChromeOSOneChannelTest, MissingChannels) {
- SetChannels(GetParam().second, /*set_first_channel=*/false);
- auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>();
- sensor_->AddClient(client.get());
- sensor_->StartListening(client.get(),
- PlatformSensorConfiguration(
- GetSensorMaxAllowedFrequency(GetParam().first)));
- EXPECT_TRUE(sensor_->IsActiveForTesting());
- EXPECT_CALL(*client.get(), OnSensorReadingChanged(GetParam().first)).Times(0);
- // Wait until all tasks done and no samples updated.
- base::RunLoop().RunUntilIdle();
- sensor_->RemoveClient(client.get());
- }
- TEST_P(PlatformSensorChromeOSOneChannelTest, GetSamples) {
- SetChannels(GetParam().second, /*set_first_channel=*/true);
- auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>();
- sensor_->AddClient(client.get());
- double frequency = GetSensorMaxAllowedFrequency(GetParam().first);
- sensor_->StartListening(client.get(), PlatformSensorConfiguration(frequency));
- EXPECT_TRUE(sensor_->IsActiveForTesting());
- WaitForAndCheckReading(client.get());
- sensor_->StopListening(client.get(), PlatformSensorConfiguration(frequency));
- sensor_->StartListening(client.get(), PlatformSensorConfiguration(frequency));
- WaitForAndCheckReading(client.get());
- DisableFirstChannel();
- EXPECT_CALL(*client.get(), OnSensorReadingChanged(GetParam().first)).Times(0);
- // Wait until a sample without the first channel is received.
- base::RunLoop().RunUntilIdle();
- // No reading updated.
- sensor_device_->ResetObserverRemoteWithReason(
- receiver_id_,
- chromeos::sensors::mojom::SensorDeviceDisconnectReason::DEVICE_REMOVED,
- "Device was removed");
- base::RunLoop loop;
- // Wait until the disconnect arrives at |sensor_|.
- EXPECT_CALL(*client.get(), OnSensorError())
- .WillOnce(base::test::RunOnceClosure(loop.QuitClosure()));
- loop.Run();
- EXPECT_EQ(
- custom_reason_code_,
- static_cast<uint32_t>(chromeos::sensors::mojom::
- SensorDeviceDisconnectReason::DEVICE_REMOVED));
- sensor_->RemoveClient(client.get());
- }
- TEST_P(PlatformSensorChromeOSOneChannelTest, ResetOnTooManyFailures) {
- SetChannels(GetParam().second, /*set_first_channel=*/true);
- auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>();
- sensor_->AddClient(client.get());
- sensor_->StartListening(client.get(),
- PlatformSensorConfiguration(
- GetSensorMaxAllowedFrequency(GetParam().first)));
- EXPECT_TRUE(sensor_->IsActiveForTesting());
- WaitForAndCheckReading(client.get());
- EXPECT_CALL(*client.get(), OnSensorError()).Times(0);
- for (size_t i = 0;
- i < PlatformSensorChromeOS::kNumFailedReadsBeforeGivingUp - 1; ++i) {
- sensor_->OnErrorOccurred(
- chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
- }
- base::flat_map<int32_t, int64_t> sample;
- sample[0] = kFakeSampleData;
- sample[1] = kFakeTimestampData;
- for (size_t i = 0; i < PlatformSensorChromeOS::kNumRecoveryReads; ++i)
- sensor_->OnSampleUpdated(sample);
- // |num_failed_reads_| is recovered by 1.
- sensor_->OnErrorOccurred(
- chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
- EXPECT_CALL(*client.get(), OnSensorError()).Times(1);
- sensor_->OnErrorOccurred(
- chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
- sensor_->RemoveClient(client.get());
- }
- INSTANTIATE_TEST_SUITE_P(
- PlatformSensorChromeOSOneChannelTestRun,
- PlatformSensorChromeOSOneChannelTest,
- ::testing::Values(std::make_pair(mojom::SensorType::AMBIENT_LIGHT,
- chromeos::sensors::mojom::kLightChannel)));
- class PlatformSensorChromeOSAxesTest
- : public PlatformSensorChromeOSTestBase,
- public ::testing::TestWithParam<
- std::pair<mojom::SensorType, const char (*)[10]>> {
- protected:
- void SetUp() override {
- SetUpBase();
- auto type = GetParam().first;
- sensor_ = base::MakeRefCounted<PlatformSensorChromeOS>(
- kFakeDeviceId, type, provider_->GetSensorReadingBuffer(type), nullptr,
- base::BindOnce(
- &PlatformSensorChromeOSAxesTest::OnSensorDeviceDisconnect,
- base::Unretained(this)),
- kScaleValue, std::move(sensor_device_remote_));
- EXPECT_EQ(sensor_->GetReportingMode(), mojom::ReportingMode::CONTINUOUS);
- EXPECT_EQ(sensor_->GetDefaultConfiguration().frequency(),
- GetSensorMaxAllowedFrequency(type));
- }
- void SetChannelsWithAxes(const char channels[][10], uint32_t num_of_axes) {
- CHECK_LE(num_of_axes, kNumberOfAxes);
- std::vector<chromeos::sensors::FakeSensorDevice::ChannelData> channels_data(
- num_of_axes + 1);
- for (uint32_t i = 0; i < num_of_axes; ++i) {
- channels_data[i].id = channels[i];
- channels_data[i].sample_data = kFakeAxesSampleData[i];
- }
- channels_data.back().id = chromeos::sensors::mojom::kTimestampChannel;
- channels_data.back().sample_data = kFakeTimestampData;
- InitSensorDevice(std::move(channels_data));
- }
- SensorReadingXYZ& GetSensorReadingXYZ(SensorReading& reading) {
- switch (GetParam().first) {
- case mojom::SensorType::ACCELEROMETER:
- case mojom::SensorType::GRAVITY:
- return reading.accel;
- case mojom::SensorType::GYROSCOPE:
- return reading.gyro;
- case mojom::SensorType::MAGNETOMETER:
- return reading.magn;
- default:
- LOG(FATAL) << "Invalid type: " << GetParam().first;
- return reading.accel;
- }
- }
- void GetRoundedSensorReadingXYZ(SensorReadingXYZ* reading_xyz) {
- reading_xyz->x = kFakeAxesSampleData[0] * kScaleValue;
- reading_xyz->y = kFakeAxesSampleData[1] * kScaleValue;
- reading_xyz->z = kFakeAxesSampleData[2] * kScaleValue;
- reading_xyz->timestamp = base::Nanoseconds(kFakeTimestampData).InSecondsF();
- switch (GetParam().first) {
- case mojom::SensorType::ACCELEROMETER:
- case mojom::SensorType::GRAVITY:
- RoundAccelerometerReading(reading_xyz);
- break;
- case mojom::SensorType::GYROSCOPE:
- RoundGyroscopeReading(reading_xyz);
- break;
- case mojom::SensorType::MAGNETOMETER:
- break;
- default:
- LOG(FATAL) << "Invalid type: " << GetParam().first;
- break;
- }
- }
- void WaitForAndCheckReading(
- testing::NiceMock<MockPlatformSensorClient>* client) {
- base::RunLoop loop;
- // Wait until a sample is received.
- EXPECT_CALL(*client, OnSensorReadingChanged(GetParam().first))
- .WillOnce(base::test::RunOnceClosure(loop.QuitClosure()));
- loop.Run();
- SensorReading reading;
- EXPECT_TRUE(sensor_->GetLatestReading(&reading));
- const auto& reading_xyz = GetSensorReadingXYZ(reading);
- SensorReadingXYZ rounded_reading_xyz;
- GetRoundedSensorReadingXYZ(&rounded_reading_xyz);
- EXPECT_EQ(reading_xyz.x, rounded_reading_xyz.x);
- EXPECT_EQ(reading_xyz.y, rounded_reading_xyz.y);
- EXPECT_EQ(reading_xyz.z, rounded_reading_xyz.z);
- EXPECT_EQ(reading_xyz.timestamp, rounded_reading_xyz.timestamp);
- }
- };
- TEST_P(PlatformSensorChromeOSAxesTest, MissingChannels) {
- SetChannelsWithAxes(GetParam().second, kNumberOfAxes - 1);
- auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>();
- sensor_->AddClient(client.get());
- sensor_->StartListening(client.get(),
- PlatformSensorConfiguration(
- GetSensorMaxAllowedFrequency(GetParam().first)));
- EXPECT_TRUE(sensor_->IsActiveForTesting());
- EXPECT_CALL(*client.get(), OnSensorReadingChanged(GetParam().first)).Times(0);
- // Wait until all tasks done and no samples updated.
- base::RunLoop().RunUntilIdle();
- sensor_->RemoveClient(client.get());
- }
- TEST_P(PlatformSensorChromeOSAxesTest, GetSamples) {
- SetChannelsWithAxes(GetParam().second, kNumberOfAxes);
- auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>();
- sensor_->AddClient(client.get());
- double frequency = GetSensorMaxAllowedFrequency(GetParam().first);
- sensor_->StartListening(client.get(), PlatformSensorConfiguration(frequency));
- EXPECT_TRUE(sensor_->IsActiveForTesting());
- WaitForAndCheckReading(client.get());
- sensor_->StopListening(client.get(), PlatformSensorConfiguration(frequency));
- sensor_->StartListening(client.get(), PlatformSensorConfiguration(frequency));
- WaitForAndCheckReading(client.get());
- DisableFirstChannel();
- EXPECT_CALL(*client.get(), OnSensorReadingChanged(GetParam().first)).Times(0);
- // Wait until a sample without the first channel is received.
- base::RunLoop().RunUntilIdle();
- // No reading updated.
- sensor_device_->RemoveReceiver(receiver_id_);
- base::RunLoop loop;
- // Wait until the disconnect arrives at |sensor_|.
- EXPECT_CALL(*client.get(), OnSensorError())
- .WillOnce(base::test::RunOnceClosure(loop.QuitClosure()));
- loop.Run();
- sensor_->RemoveClient(client.get());
- }
- INSTANTIATE_TEST_SUITE_P(
- PlatformSensorChromeOSAxesTestRun,
- PlatformSensorChromeOSAxesTest,
- ::testing::Values(
- std::make_pair(mojom::SensorType::ACCELEROMETER,
- kAccelerometerChannels),
- std::make_pair(mojom::SensorType::GYROSCOPE, kGyroscopeChannels),
- std::make_pair(mojom::SensorType::MAGNETOMETER, kMagnetometerChannels),
- std::make_pair(mojom::SensorType::GRAVITY, kGravityChannels)));
- } // namespace device
|