Commit 492d11dd authored by Harvey Yang's avatar Harvey Yang Committed by Commit Bot

sensors: Support Multiple Clients in chromeos::sensors::FakeSensorDevice

As some clients, such as generic sensor, may connect to the same
SensorDevice multiple times, this commit refactors
chromeos::sensors::FakeSensorDevice to support that.

BUG=chromium:1006141
TEST=builds and unit tests of generic sensor

Change-Id: Ie792ab60daae8d9941d00fce6c7d3a248f9b8c57
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2491767
Commit-Queue: Cheng-Hao Yang <chenghaoyang@chromium.org>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#820675}
parent 47de9950
......@@ -4,11 +4,11 @@
#include "chromeos/components/sensors/fake_sensor_device.h"
#include <algorithm>
#include <utility>
#include "base/bind.h"
#include "base/containers/flat_map.h"
#include "base/ranges/algorithm.h"
#include "base/threading/sequenced_task_runner_handle.h"
namespace chromeos {
......@@ -21,34 +21,54 @@ FakeSensorDevice::ChannelData& FakeSensorDevice::ChannelData::operator=(
const FakeSensorDevice::ChannelData&) = default;
FakeSensorDevice::ChannelData::~ChannelData() = default;
FakeSensorDevice::FakeSensorDevice() {
FakeSensorDevice::FakeSensorDevice(const std::vector<ChannelData>& channels)
: channels_(channels) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto& client : clients_)
client.second.channels_enabled.assign(channels_.size(), false);
}
FakeSensorDevice::~FakeSensorDevice() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
bool FakeSensorDevice::is_bound() {
mojo::ReceiverId FakeSensorDevice::AddReceiver(
mojo::PendingReceiver<mojom::SensorDevice> pending_receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return receiver_.is_bound();
auto id = receiver_set_.Add(this, std::move(pending_receiver));
DCHECK(clients_.find(id) == clients_.end());
clients_[id].channels_enabled.assign(channels_.size(), false);
return id;
}
void FakeSensorDevice::Bind(
mojo::PendingReceiver<mojom::SensorDevice> pending_receiver) {
void FakeSensorDevice::RemoveReceiver(mojo::ReceiverId id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(receiver_set_.HasReceiver(id));
clients_.erase(id);
receiver_set_.Remove(id);
}
void FakeSensorDevice::ClearReceivers() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!is_bound());
receiver_.Bind(std::move(pending_receiver));
receiver_.set_disconnect_handler(base::BindOnce(
&FakeSensorDevice::OnDeviceDisconnect, base::Unretained(this)));
clients_.clear();
receiver_set_.Clear();
}
void FakeSensorDevice::OnDeviceDisconnect() {
bool FakeSensorDevice::HasReceivers() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
receiver_.reset();
return !receiver_set_.empty();
}
size_t FakeSensorDevice::SizeOfReceivers() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return receiver_set_.size();
}
void FakeSensorDevice::SetAttribute(const std::string& attr_name,
......@@ -58,12 +78,14 @@ void FakeSensorDevice::SetAttribute(const std::string& attr_name,
attributes_[attr_name] = attr_value;
}
void FakeSensorDevice::SetChannels(const std::vector<ChannelData>& channels) {
void FakeSensorDevice::ResetObserverRemote(mojo::ReceiverId id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(channels_.empty());
channels_ = channels;
channels_enabled_.assign(channels_.size(), false);
auto it = clients_.find(id);
if (it == clients_.end())
return;
it->second.observer.reset();
}
void FakeSensorDevice::GetAttributes(const std::vector<std::string>& attr_names,
......@@ -91,19 +113,23 @@ void FakeSensorDevice::SetFrequency(double frequency,
if (frequency < 0.0)
frequency = 0.0;
frequency_ = frequency;
auto& client = clients_[receiver_set_.current_receiver()];
client.frequency = frequency;
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(frequency)));
if (ReadyToSendSample())
SendSample();
SendSampleIfReady(client);
}
void FakeSensorDevice::StartReadingSamples(
mojo::PendingRemote<mojom::SensorDeviceSamplesObserver> observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (observer_.is_bound()) {
auto id = receiver_set_.current_receiver();
auto& client = clients_[id];
if (client.observer.is_bound()) {
mojo::Remote<mojom::SensorDeviceSamplesObserver> remote(
std::move(observer));
remote->OnErrorOccurred(mojom::ObserverErrorType::ALREADY_STARTED);
......@@ -111,27 +137,30 @@ void FakeSensorDevice::StartReadingSamples(
return;
}
observer_.Bind(std::move(observer));
// Reuse StopReadingSamples to reset |observer_|.
observer_.set_disconnect_handler(base::BindOnce(
&FakeSensorDevice::StopReadingSamples, base::Unretained(this)));
client.observer.Bind(std::move(observer));
client.observer.set_disconnect_handler(base::BindOnce(
&FakeSensorDevice::ResetObserverRemote, base::Unretained(this), id));
if (!frequency_.has_value() || frequency_.value() <= 0.0) {
observer_->OnErrorOccurred(mojom::ObserverErrorType::FREQUENCY_INVALID);
if (!client.frequency.has_value() || client.frequency.value() <= 0.0) {
client.observer->OnErrorOccurred(
mojom::ObserverErrorType::FREQUENCY_INVALID);
return;
}
if (!std::any_of(channels_enabled_.begin(), channels_enabled_.end(),
[](bool en) { return en; }))
observer_->OnErrorOccurred(mojom::ObserverErrorType::NO_ENABLED_CHANNELS);
if (base::ranges::none_of(client.channels_enabled,
[](bool enabled) { return enabled; })) {
client.observer->OnErrorOccurred(
mojom::ObserverErrorType::NO_ENABLED_CHANNELS);
return;
}
if (ReadyToSendSample())
SendSample();
SendSampleIfReady(client);
}
void FakeSensorDevice::StopReadingSamples() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
observer_.reset();
clients_[receiver_set_.current_receiver()].observer.reset();
}
void FakeSensorDevice::GetAllChannelIds(GetAllChannelIdsCallback callback) {
......@@ -151,22 +180,23 @@ void FakeSensorDevice::SetChannelsEnabled(
SetChannelsEnabledCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto& client = clients_[receiver_set_.current_receiver()];
std::vector<int32_t> failed_indices;
for (int32_t index : iio_chn_indices) {
if (static_cast<size_t>(index) >= channels_enabled_.size()) {
if (static_cast<size_t>(index) >= client.channels_enabled.size()) {
failed_indices.push_back(index);
continue;
}
channels_enabled_[index] = en;
client.channels_enabled[index] = en;
}
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), std::move(failed_indices)));
if (ReadyToSendSample())
SendSample();
SendSampleIfReady(client);
}
void FakeSensorDevice::GetChannelsEnabled(
......@@ -174,14 +204,16 @@ void FakeSensorDevice::GetChannelsEnabled(
GetChannelsEnabledCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto& client = clients_[receiver_set_.current_receiver()];
std::vector<bool> enabled;
for (int32_t index : iio_chn_indices) {
if (static_cast<size_t>(index) >= channels_enabled_.size()) {
if (static_cast<size_t>(index) >= client.channels_enabled.size()) {
enabled.push_back(false);
continue;
}
enabled.push_back(channels_enabled_[index]);
enabled.push_back(client.channels_enabled[index]);
}
base::SequencedTaskRunnerHandle::Get()->PostTask(
......@@ -210,33 +242,31 @@ void FakeSensorDevice::GetChannelsAttributes(
FROM_HERE, base::BindOnce(std::move(callback), std::move(attrs)));
}
bool FakeSensorDevice::ReadyToSendSample() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!observer_.is_bound())
return false;
FakeSensorDevice::ClientData::ClientData() = default;
FakeSensorDevice::ClientData::~ClientData() = default;
if (!frequency_.has_value() || frequency_.value() <= 0.0)
return false;
void FakeSensorDevice::SendSampleIfReady(ClientData& client) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(channels_.size(), client.channels_enabled.size());
return std::any_of(channels_enabled_.begin(), channels_enabled_.end(),
[](bool en) { return en; });
}
if (!client.observer.is_bound())
return;
void FakeSensorDevice::SendSample() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(ReadyToSendSample());
CHECK_EQ(channels_.size(), channels_enabled_.size());
if (!client.frequency.has_value() || client.frequency.value() <= 0.0)
return;
base::flat_map<int32_t, int64_t> sample;
for (size_t i = 0; i < channels_.size(); ++i) {
if (!channels_enabled_[i])
if (!client.channels_enabled[i])
continue;
sample[i] = channels_[i].sample_data;
}
observer_->OnSampleUpdated(std::move(sample));
if (sample.empty())
return;
client.observer->OnSampleUpdated(std::move(sample));
}
} // namespace sensors
......
......@@ -13,7 +13,7 @@
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "chromeos/components/sensors/mojom/sensor.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace chromeos {
......@@ -32,19 +32,23 @@ class FakeSensorDevice final : public mojom::SensorDevice {
int64_t sample_data;
};
FakeSensorDevice();
explicit FakeSensorDevice(const std::vector<ChannelData>& channels);
FakeSensorDevice(const FakeSensorDevice&) = delete;
FakeSensorDevice& operator=(const FakeSensorDevice&) = delete;
~FakeSensorDevice() override;
bool is_bound();
void Bind(mojo::PendingReceiver<mojom::SensorDevice> pending_receiver);
void OnDeviceDisconnect();
mojo::ReceiverId AddReceiver(
mojo::PendingReceiver<mojom::SensorDevice> pending_receiver);
void RemoveReceiver(mojo::ReceiverId id);
void ClearReceivers();
bool HasReceivers() const;
size_t SizeOfReceivers() const;
void SetAttribute(const std::string& attr_name,
const std::string& attr_value);
void SetChannels(const std::vector<ChannelData>& channels);
void ResetObserverRemote(mojo::ReceiverId id);
// Implementation of mojom::SensorDevice.
void SetTimeout(uint32_t timeout) override {}
......@@ -66,17 +70,25 @@ class FakeSensorDevice final : public mojom::SensorDevice {
GetChannelsAttributesCallback callback) override;
private:
bool ReadyToSendSample();
void SendSample();
struct ClientData {
ClientData();
~ClientData();
base::Optional<double> frequency;
std::vector<bool> channels_enabled;
mojo::Remote<mojom::SensorDeviceSamplesObserver> observer;
};
void SendSampleIfReady(ClientData& client);
std::map<std::string, std::string> attributes_;
base::Optional<double> frequency_;
std::vector<ChannelData> channels_;
std::vector<bool> channels_enabled_;
const std::vector<ChannelData> channels_;
mojo::Remote<mojom::SensorDeviceSamplesObserver> observer_;
mojo::ReceiverSet<mojom::SensorDevice> receiver_set_;
mojo::Receiver<mojom::SensorDevice> receiver_{this};
// First is the client's id from |receiver_set_|, second is the client's
// states and observer remote.
std::map<mojo::ReceiverId, ClientData> clients_;
SEQUENCE_CHECKER(sequence_checker_);
};
......
......@@ -94,7 +94,7 @@ void FakeSensorService::GetDevice(
if (it == devices_.end())
return;
it->second.sensor_device->Bind(std::move(device_request));
it->second.sensor_device->AddReceiver(std::move(device_request));
}
FakeSensorService::DeviceData::DeviceData() = default;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment