platform_sensor_chromeos.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/device/generic_sensor/platform_sensor_chromeos.h"
  5. #include <iterator>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/containers/contains.h"
  9. #include "base/ranges/algorithm.h"
  10. #include "base/strings/string_number_conversions.h"
  11. #include "base/time/time.h"
  12. #include "services/device/public/cpp/generic_sensor/sensor_traits.h"
  13. namespace device {
  14. namespace {
  15. constexpr char kAxes[][3] = {"_x", "_y", "_z"};
  16. } // namespace
  17. PlatformSensorChromeOS::PlatformSensorChromeOS(
  18. int32_t iio_device_id,
  19. mojom::SensorType type,
  20. SensorReadingSharedBuffer* reading_buffer,
  21. PlatformSensorProvider* provider,
  22. mojo::ConnectionErrorWithReasonCallback sensor_device_disconnect_callback,
  23. double scale,
  24. mojo::Remote<chromeos::sensors::mojom::SensorDevice> sensor_device_remote)
  25. : PlatformSensor(type, reading_buffer, provider),
  26. iio_device_id_(iio_device_id),
  27. sensor_device_disconnect_callback_(
  28. std::move(sensor_device_disconnect_callback)),
  29. default_configuration_(
  30. PlatformSensorConfiguration(GetSensorMaxAllowedFrequency(type))),
  31. scale_(scale),
  32. sensor_device_remote_(std::move(sensor_device_remote)) {
  33. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  34. DCHECK(sensor_device_remote_.is_bound());
  35. DCHECK_GT(scale_, 0.0);
  36. sensor_device_remote_.set_disconnect_with_reason_handler(
  37. base::BindOnce(&PlatformSensorChromeOS::OnSensorDeviceDisconnect,
  38. weak_factory_.GetWeakPtr()));
  39. sensor_device_remote_->SetTimeout(0);
  40. sensor_device_remote_->GetAllChannelIds(
  41. base::BindOnce(&PlatformSensorChromeOS::GetAllChannelIdsCallback,
  42. weak_factory_.GetWeakPtr()));
  43. }
  44. PlatformSensorChromeOS::~PlatformSensorChromeOS() {
  45. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  46. }
  47. mojom::ReportingMode PlatformSensorChromeOS::GetReportingMode() {
  48. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  49. if (GetType() == mojom::SensorType::AMBIENT_LIGHT)
  50. return mojom::ReportingMode::ON_CHANGE;
  51. return mojom::ReportingMode::CONTINUOUS;
  52. }
  53. void PlatformSensorChromeOS::OnSampleUpdated(
  54. const base::flat_map<int32_t, int64_t>& sample) {
  55. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  56. DCHECK(!channel_indices_.empty());
  57. if (sample.size() != channel_indices_.size()) {
  58. LOG(WARNING) << "Invalid sample with size: " << sample.size();
  59. OnErrorOccurred(chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
  60. return;
  61. }
  62. for (auto index : channel_indices_) {
  63. if (!base::Contains(sample, index)) {
  64. LOG(ERROR) << "Missing channel: " << iio_channel_ids_[index]
  65. << " in sample.";
  66. OnErrorOccurred(chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
  67. return;
  68. }
  69. }
  70. if (num_failed_reads_ > 0 && ++num_recovery_reads_ == kNumRecoveryReads) {
  71. num_recovery_reads_ = 0;
  72. --num_failed_reads_;
  73. }
  74. SensorReading reading;
  75. switch (GetType()) {
  76. case mojom::SensorType::AMBIENT_LIGHT:
  77. DCHECK_EQ(channel_indices_.size(), 2u);
  78. reading.als.value = GetScaledValue(sample.at(channel_indices_[0]));
  79. break;
  80. case mojom::SensorType::PROXIMITY:
  81. DCHECK_EQ(channel_indices_.size(), 2u);
  82. reading.proximity.value = GetScaledValue(sample.at(channel_indices_[0]));
  83. break;
  84. case mojom::SensorType::ACCELEROMETER:
  85. case mojom::SensorType::GRAVITY:
  86. DCHECK_EQ(channel_indices_.size(), 4u);
  87. reading.accel.x = GetScaledValue(sample.at(channel_indices_[0]));
  88. reading.accel.y = GetScaledValue(sample.at(channel_indices_[1]));
  89. reading.accel.z = GetScaledValue(sample.at(channel_indices_[2]));
  90. break;
  91. case mojom::SensorType::GYROSCOPE:
  92. DCHECK_EQ(channel_indices_.size(), 4u);
  93. reading.gyro.x = GetScaledValue(sample.at(channel_indices_[0]));
  94. reading.gyro.y = GetScaledValue(sample.at(channel_indices_[1]));
  95. reading.gyro.z = GetScaledValue(sample.at(channel_indices_[2]));
  96. break;
  97. case mojom::SensorType::MAGNETOMETER:
  98. DCHECK_EQ(channel_indices_.size(), 4u);
  99. reading.magn.x = GetScaledValue(sample.at(channel_indices_[0]));
  100. reading.magn.y = GetScaledValue(sample.at(channel_indices_[1]));
  101. reading.magn.z = GetScaledValue(sample.at(channel_indices_[2]));
  102. break;
  103. default:
  104. break;
  105. }
  106. reading.raw.timestamp =
  107. base::Nanoseconds(sample.at(channel_indices_.back())).InSecondsF();
  108. UpdateSharedBufferAndNotifyClients(reading);
  109. }
  110. void PlatformSensorChromeOS::OnErrorOccurred(
  111. chromeos::sensors::mojom::ObserverErrorType type) {
  112. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  113. switch (type) {
  114. case chromeos::sensors::mojom::ObserverErrorType::ALREADY_STARTED:
  115. LOG(ERROR) << "Sensor " << iio_device_id_
  116. << ": Another observer has already started to read samples";
  117. ResetOnError();
  118. break;
  119. case chromeos::sensors::mojom::ObserverErrorType::FREQUENCY_INVALID:
  120. LOG(ERROR) << "Sensor " << iio_device_id_
  121. << ": Observer started with an invalid frequency";
  122. ResetOnError();
  123. break;
  124. case chromeos::sensors::mojom::ObserverErrorType::NO_ENABLED_CHANNELS:
  125. LOG(ERROR) << "Sensor " << iio_device_id_
  126. << ": Observer started with no channels enabled";
  127. SetChannelsEnabled();
  128. break;
  129. case chromeos::sensors::mojom::ObserverErrorType::SET_FREQUENCY_IO_FAILED:
  130. LOG(ERROR) << "Sensor " << iio_device_id_
  131. << ": Failed to set frequency to the physical device";
  132. break;
  133. case chromeos::sensors::mojom::ObserverErrorType::GET_FD_FAILED:
  134. LOG(ERROR) << "Sensor " << iio_device_id_
  135. << ": Failed to get the device's fd to poll on";
  136. break;
  137. case chromeos::sensors::mojom::ObserverErrorType::READ_FAILED:
  138. LOG(ERROR) << "Sensor " << iio_device_id_ << ": Failed to read a sample";
  139. OnReadFailure();
  140. break;
  141. case chromeos::sensors::mojom::ObserverErrorType::READ_TIMEOUT:
  142. LOG(ERROR) << "Sensor " << iio_device_id_ << ": A read timed out";
  143. break;
  144. default:
  145. LOG(ERROR) << "Sensor " << iio_device_id_ << ": error "
  146. << static_cast<int>(type);
  147. break;
  148. }
  149. }
  150. bool PlatformSensorChromeOS::StartSensor(
  151. const PlatformSensorConfiguration& configuration) {
  152. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  153. if (!sensor_device_remote_.is_bound()) {
  154. LOG(WARNING) << "Unbound sensor_device_remote_, skipping StartSensor.";
  155. return false;
  156. }
  157. if (configuration.frequency() <= 0.0) {
  158. LOG(ERROR) << "Invalid frequency: " << configuration.frequency()
  159. << " in sensor with id: " << iio_device_id_;
  160. return false;
  161. }
  162. if (receiver_.is_bound() &&
  163. configuration.frequency() == current_configuration_.frequency()) {
  164. // Nothing to do.
  165. return true;
  166. }
  167. current_configuration_ = configuration;
  168. StartReadingIfReady();
  169. return true;
  170. }
  171. void PlatformSensorChromeOS::StopSensor() {
  172. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  173. receiver_.reset();
  174. }
  175. bool PlatformSensorChromeOS::CheckSensorConfiguration(
  176. const PlatformSensorConfiguration& configuration) {
  177. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  178. return configuration.frequency() > 0 &&
  179. configuration.frequency() <= default_configuration_.frequency();
  180. }
  181. PlatformSensorConfiguration PlatformSensorChromeOS::GetDefaultConfiguration() {
  182. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  183. return default_configuration_;
  184. }
  185. void PlatformSensorChromeOS::SensorReplaced() {
  186. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  187. VLOG(1) << "SensorReplaced with id: " << iio_device_id_;
  188. ResetReadingBuffer();
  189. ResetOnError();
  190. }
  191. void PlatformSensorChromeOS::ResetOnError() {
  192. LOG(ERROR) << "ResetOnError of sensor with id: " << iio_device_id_;
  193. sensor_device_remote_.reset();
  194. receiver_.reset();
  195. NotifySensorError();
  196. }
  197. void PlatformSensorChromeOS::OnSensorDeviceDisconnect(
  198. uint32_t custom_reason_code,
  199. const std::string& description) {
  200. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  201. auto reason =
  202. static_cast<chromeos::sensors::mojom::SensorDeviceDisconnectReason>(
  203. custom_reason_code);
  204. LOG(ERROR) << "OnSensorDeviceDisconnect, reason: " << reason
  205. << ", description: " << description;
  206. std::move(sensor_device_disconnect_callback_)
  207. .Run(custom_reason_code, description);
  208. ResetOnError();
  209. }
  210. void PlatformSensorChromeOS::StartReadingIfReady() {
  211. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  212. DCHECK(sensor_device_remote_.is_bound());
  213. if (required_channel_ids_.empty() ||
  214. current_configuration_.frequency() <= 0.0) {
  215. // Not ready yet.
  216. return;
  217. }
  218. UpdateSensorDeviceFrequency();
  219. if (receiver_.is_bound())
  220. return;
  221. sensor_device_remote_->StartReadingSamples(BindNewPipeAndPassRemote());
  222. }
  223. mojo::PendingRemote<chromeos::sensors::mojom::SensorDeviceSamplesObserver>
  224. PlatformSensorChromeOS::BindNewPipeAndPassRemote() {
  225. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  226. DCHECK(!receiver_.is_bound());
  227. auto pending_remote = receiver_.BindNewPipeAndPassRemote(main_task_runner());
  228. receiver_.set_disconnect_with_reason_handler(
  229. base::BindOnce(&PlatformSensorChromeOS::OnObserverDisconnect,
  230. weak_factory_.GetWeakPtr()));
  231. return pending_remote;
  232. }
  233. void PlatformSensorChromeOS::OnObserverDisconnect(
  234. uint32_t custom_reason_code,
  235. const std::string& description) {
  236. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  237. DCHECK(receiver_.is_bound());
  238. auto reason =
  239. static_cast<chromeos::sensors::mojom::SensorDeviceDisconnectReason>(
  240. custom_reason_code);
  241. LOG(ERROR) << "OnObserverDisconnect, reason: " << reason
  242. << ", description: " << description;
  243. std::move(sensor_device_disconnect_callback_)
  244. .Run(custom_reason_code, description);
  245. ResetOnError();
  246. }
  247. void PlatformSensorChromeOS::SetRequiredChannels() {
  248. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  249. DCHECK(required_channel_ids_.empty()); // Should only be called once.
  250. absl::optional<std::string> axes_prefix = absl::nullopt;
  251. switch (GetType()) {
  252. case mojom::SensorType::AMBIENT_LIGHT:
  253. required_channel_ids_.push_back(chromeos::sensors::mojom::kLightChannel);
  254. break;
  255. case mojom::SensorType::ACCELEROMETER:
  256. axes_prefix = chromeos::sensors::mojom::kAccelerometerChannel;
  257. break;
  258. case mojom::SensorType::GYROSCOPE:
  259. axes_prefix = chromeos::sensors::mojom::kGyroscopeChannel;
  260. break;
  261. case mojom::SensorType::MAGNETOMETER:
  262. axes_prefix = chromeos::sensors::mojom::kMagnetometerChannel;
  263. break;
  264. case mojom::SensorType::GRAVITY:
  265. axes_prefix = chromeos::sensors::mojom::kGravityChannel;
  266. break;
  267. default:
  268. break;
  269. }
  270. if (axes_prefix.has_value()) {
  271. for (const auto* axis : kAxes)
  272. required_channel_ids_.push_back(axes_prefix.value() + std::string(axis));
  273. }
  274. required_channel_ids_.push_back(chromeos::sensors::mojom::kTimestampChannel);
  275. }
  276. void PlatformSensorChromeOS::GetAllChannelIdsCallback(
  277. const std::vector<std::string>& iio_channel_ids) {
  278. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  279. SetRequiredChannels();
  280. DCHECK(!required_channel_ids_.empty());
  281. iio_channel_ids_ = iio_channel_ids;
  282. for (const std::string& channel : required_channel_ids_) {
  283. auto it = base::ranges::find(iio_channel_ids_, channel);
  284. if (it == iio_channel_ids_.end()) {
  285. LOG(ERROR) << "Missing channel: " << channel;
  286. ResetOnError();
  287. return;
  288. }
  289. channel_indices_.push_back(std::distance(iio_channel_ids_.begin(), it));
  290. }
  291. DCHECK_EQ(channel_indices_.size(), required_channel_ids_.size());
  292. SetChannelsEnabled();
  293. StartReadingIfReady();
  294. }
  295. void PlatformSensorChromeOS::UpdateSensorDeviceFrequency() {
  296. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  297. DCHECK(sensor_device_remote_.is_bound());
  298. sensor_device_remote_->SetFrequency(
  299. current_configuration_.frequency(),
  300. base::BindOnce(&PlatformSensorChromeOS::SetFrequencyCallback,
  301. weak_factory_.GetWeakPtr(),
  302. current_configuration_.frequency()));
  303. }
  304. void PlatformSensorChromeOS::SetFrequencyCallback(double target_frequency,
  305. double result_frequency) {
  306. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  307. if ((target_frequency <= 0.0 && result_frequency <= 0.0) ||
  308. (target_frequency > 0.0 && result_frequency > 0.0)) {
  309. return;
  310. }
  311. LOG(ERROR) << "SetFrequency failed. Target frequency: " << target_frequency
  312. << ", result requency: " << result_frequency;
  313. ResetOnError();
  314. }
  315. void PlatformSensorChromeOS::SetChannelsEnabled() {
  316. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  317. if (!sensor_device_remote_.is_bound()) {
  318. LOG(WARNING)
  319. << "Unbound sensor_device_remote_, skipping SetChannelEnabled.";
  320. return;
  321. }
  322. sensor_device_remote_->SetChannelsEnabled(
  323. channel_indices_, true,
  324. base::BindOnce(&PlatformSensorChromeOS::SetChannelsEnabledCallback,
  325. weak_factory_.GetWeakPtr()));
  326. }
  327. void PlatformSensorChromeOS::SetChannelsEnabledCallback(
  328. const std::vector<int32_t>& failed_indices) {
  329. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  330. if (failed_indices.empty())
  331. return;
  332. for (int32_t index : failed_indices) {
  333. LOG(ERROR) << "Failed to enable channel: " << iio_channel_ids_[index]
  334. << " in sensor with id: " << iio_device_id_;
  335. }
  336. ResetOnError();
  337. }
  338. double PlatformSensorChromeOS::GetScaledValue(int64_t value) const {
  339. return value * scale_;
  340. }
  341. void PlatformSensorChromeOS::OnReadFailure() {
  342. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  343. if (++num_failed_reads_ < kNumFailedReadsBeforeGivingUp) {
  344. LOG(ERROR) << "ReadSamples error #" << num_failed_reads_ << " occurred";
  345. return;
  346. }
  347. num_failed_reads_ = num_recovery_reads_ = 0;
  348. LOG(ERROR) << "Too many failed reads";
  349. ResetOnError();
  350. }
  351. } // namespace device