blob: 3a226cbab062b38d62d812656b993abe0e674f31 [file] [log] [blame]
// Copyright 2022 The Chromium OS 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 "iioservice/iioservice_simpleclient/observer.h"
#include <utility>
#include <base/bind.h>
#include <base/time/time.h>
#include "iioservice/include/common.h"
namespace iioservice {
namespace {
constexpr int kSetUpChannelTimeoutInMilliseconds = 3000;
// Set the base latency tolerance to half of 100 ms, according to
// https://source.android.com/compatibility/android-cdd#7_3_sensors, as the
// samples may go through a VM and Android sensormanager.
constexpr base::TimeDelta kMaximumBaseLatencyTolerance = base::Milliseconds(50);
} // namespace
Observer::Observer(scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
QuitCallback quit_callback,
int device_id,
cros::mojom::DeviceType device_type,
int num)
: SensorClient(std::move(ipc_task_runner), std::move(quit_callback)),
device_id_(device_id),
device_type_(device_type),
num_(num) {
ipc_task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&Observer::SetUpChannelTimeout,
weak_factory_.GetWeakPtr()),
base::Milliseconds(kSetUpChannelTimeoutInMilliseconds));
}
void Observer::Start() {
if (device_id_ < 0)
GetDeviceIdsByType();
else
GetSensorDevice();
}
void Observer::OnDeviceDisconnect() {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
LOGF(ERROR) << "SensorDevice disconnected";
Reset();
}
void Observer::OnObserverDisconnect() {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
LOGF(ERROR) << "Observer diconnected";
Reset();
}
void Observer::GetDeviceIdsByType() {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
DCHECK_NE(device_type_, cros::mojom::DeviceType::NONE);
sensor_service_remote_->GetDeviceIds(
device_type_, base::BindOnce(&Observer::GetDeviceIdsCallback,
weak_factory_.GetWeakPtr()));
}
void Observer::GetDeviceIdsCallback(
const std::vector<int32_t>& iio_device_ids) {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
if (iio_device_ids.empty()) {
LOGF(ERROR) << "No device found give device type: " << device_type_;
Reset();
}
// Take the first id.
device_id_ = iio_device_ids.front();
GetSensorDevice();
}
void Observer::GetSensorDevice() {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
if (!sensor_device_remote_.is_bound()) {
sensor_service_remote_->GetDevice(
device_id_, sensor_device_remote_.BindNewPipeAndPassReceiver());
sensor_device_remote_.set_disconnect_handler(base::BindOnce(
&Observer::OnDeviceDisconnect, weak_factory_.GetWeakPtr()));
}
}
void Observer::AddTimestamp(int64_t timestamp) {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
struct timespec ts = {};
if (clock_gettime(CLOCK_BOOTTIME, &ts) < 0) {
PLOGF(ERROR) << "clock_gettime(CLOCK_BOOTTIME) failed";
return;
}
auto latency =
base::Nanoseconds(static_cast<int64_t>(ts.tv_sec) * 1000 * 1000 * 1000 +
ts.tv_nsec - timestamp);
LOGF(INFO) << "Latency: " << latency;
total_latency_ += latency;
latencies_.push_back(latency);
}
void Observer::AddSuccessRead() {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
if (++num_success_reads_ < num_)
return;
// Don't Change: Used as a check sentence in the tast test.
LOGF(INFO) << "Number of success reads " << num_ << " achieved";
// Calculate the latencies only when timestamp channel is enabled.
if (!latencies_.empty()) {
base::TimeDelta latency_tolerance = GetLatencyTolerance();
size_t n = latencies_.size();
std::nth_element(latencies_.begin(), latencies_.begin(), latencies_.end());
base::TimeDelta min_latency = latencies_[0];
std::nth_element(latencies_.begin(), latencies_.begin() + n / 2,
latencies_.end());
base::TimeDelta median_latency = latencies_[n / 2];
std::nth_element(latencies_.begin(), --latencies_.end(), latencies_.end());
base::TimeDelta max_latency = *(--latencies_.end());
if (max_latency > latency_tolerance) {
// Don't Change: Used as a check sentence in the tast test.
LOGF(ERROR) << "Max latency exceeds latency tolerance.";
LOGF(ERROR) << "Latency tolerance: " << latency_tolerance;
LOGF(ERROR) << "Max latency : " << max_latency;
} else {
LOGF(INFO) << "Latency tolerance: " << latency_tolerance;
LOGF(INFO) << "Max latency : " << max_latency;
}
if (min_latency < base::Seconds(0.0)) {
// Don't Change: Used as a check sentence in the tast test.
LOGF(ERROR)
<< "Min latency less than zero: a timestamp was set in the past.";
LOGF(ERROR) << "Min latency : " << min_latency;
} else {
LOGF(INFO) << "Min latency : " << min_latency;
}
LOGF(INFO) << "Median latency : " << median_latency;
LOGF(INFO) << "Mean latency : " << total_latency_ / n;
}
Reset();
}
base::TimeDelta Observer::GetLatencyTolerance() const {
return kMaximumBaseLatencyTolerance;
}
} // namespace iioservice