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
5 #include "services/device/generic_sensor/platform_sensor_provider_chromeos.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/optional.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/test/bind.h"
14 #include "base/test/task_environment.h"
15 #include "chromeos/components/sensors/fake_sensor_device.h"
16 #include "chromeos/components/sensors/fake_sensor_hal_server.h"
17 #include "chromeos/components/sensors/sensor_hal_dispatcher.h"
18 #include "services/device/public/cpp/generic_sensor/sensor_traits.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace device {
22
23 namespace {
24
25 constexpr int kFakeDeviceId = 1;
26
27 constexpr double kScaleValue = 10.0;
28 constexpr char kWrongScale[] = "10..0";
29
30 constexpr char kWrongLocation[] = "basee";
31
32 } // namespace
33
34 class PlatformSensorProviderChromeOSTest : public ::testing::Test {
35 protected:
SetUp()36 void SetUp() override {
37 chromeos::sensors::SensorHalDispatcher::Initialize();
38
39 sensor_hal_server_ =
40 std::make_unique<chromeos::sensors::FakeSensorHalServer>();
41 provider_ = std::make_unique<PlatformSensorProviderChromeOS>();
42 }
43
TearDown()44 void TearDown() override {
45 chromeos::sensors::SensorHalDispatcher::Shutdown();
46 }
47
AddDevice(int32_t iio_device_id,chromeos::sensors::mojom::DeviceType type,const base::Optional<std::string> & scale,const base::Optional<std::string> & location)48 void AddDevice(int32_t iio_device_id,
49 chromeos::sensors::mojom::DeviceType type,
50 const base::Optional<std::string>& scale,
51 const base::Optional<std::string>& location) {
52 AddDevice(iio_device_id,
53 std::set<chromeos::sensors::mojom::DeviceType>{type},
54 std::move(scale), std::move(location));
55 }
56
AddDevice(int32_t iio_device_id,std::set<chromeos::sensors::mojom::DeviceType> types,const base::Optional<std::string> & scale,const base::Optional<std::string> & location)57 void AddDevice(int32_t iio_device_id,
58 std::set<chromeos::sensors::mojom::DeviceType> types,
59 const base::Optional<std::string>& scale,
60 const base::Optional<std::string>& location) {
61 auto sensor_device = std::make_unique<chromeos::sensors::FakeSensorDevice>(
62 std::vector<chromeos::sensors::FakeSensorDevice::ChannelData>{});
63
64 if (scale.has_value()) {
65 sensor_device->SetAttribute(chromeos::sensors::mojom::kScale,
66 scale.value());
67 }
68 if (location.has_value()) {
69 sensor_device->SetAttribute(chromeos::sensors::mojom::kLocation,
70 location.value());
71 }
72
73 sensor_devices_.push_back(sensor_device.get());
74
75 sensor_hal_server_->GetSensorService()->SetDevice(
76 iio_device_id, std::move(types), std::move(sensor_device));
77 }
78
79 // Sensor creation is asynchronous, therefore inner loop is used to wait for
80 // PlatformSensorProvider::CreateSensorCallback completion.
CreateSensor(mojom::SensorType type)81 scoped_refptr<PlatformSensor> CreateSensor(mojom::SensorType type) {
82 scoped_refptr<PlatformSensor> sensor;
83 base::RunLoop run_loop;
84 provider_->CreateSensor(type,
85 base::BindLambdaForTesting(
86 [&](scoped_refptr<PlatformSensor> new_sensor) {
87 if (new_sensor)
88 EXPECT_EQ(type, new_sensor->GetType());
89
90 sensor = std::move(new_sensor);
91 run_loop.Quit();
92 }));
93 run_loop.Run();
94 return sensor;
95 }
96
StartConnection()97 void StartConnection() {
98 chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer(
99 sensor_hal_server_->PassRemote());
100 }
101
ResetClient()102 void ResetClient() {
103 // Similar to provider_->OnSensorHalClientFailure, but without the delay.
104 provider_->ResetSensorService();
105 provider_->sensor_hal_client_.reset();
106 provider_->RegisterSensorClient();
107 }
108
109 std::unique_ptr<chromeos::sensors::FakeSensorHalServer> sensor_hal_server_;
110 std::vector<chromeos::sensors::FakeSensorDevice*> sensor_devices_;
111
112 std::unique_ptr<PlatformSensorProviderChromeOS> provider_;
113
114 base::test::SingleThreadTaskEnvironment task_environment_;
115 };
116
TEST_F(PlatformSensorProviderChromeOSTest,CheckUnsupportedTypes)117 TEST_F(PlatformSensorProviderChromeOSTest, CheckUnsupportedTypes) {
118 int fake_id = 1;
119 // Containing at least one supported device type.
120 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ACCEL,
121 base::NumberToString(kScaleValue),
122 chromeos::sensors::mojom::kLocationBase);
123 AddDevice(fake_id++,
124 std::set<chromeos::sensors::mojom::DeviceType>{
125 chromeos::sensors::mojom::DeviceType::ANGLVEL,
126 chromeos::sensors::mojom::DeviceType::COUNT},
127 base::NumberToString(kScaleValue),
128 chromeos::sensors::mojom::kLocationBase);
129
130 // All device types are unsupported.
131 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::COUNT,
132 base::NumberToString(kScaleValue),
133 chromeos::sensors::mojom::kLocationBase);
134 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ANGL,
135 base::NumberToString(kScaleValue),
136 chromeos::sensors::mojom::kLocationBase);
137 AddDevice(fake_id++,
138 std::set<chromeos::sensors::mojom::DeviceType>{
139 chromeos::sensors::mojom::DeviceType::ANGL,
140 chromeos::sensors::mojom::DeviceType::BARO},
141 base::NumberToString(kScaleValue),
142 chromeos::sensors::mojom::kLocationBase);
143
144 StartConnection();
145
146 EXPECT_TRUE(CreateSensor(mojom::SensorType::ACCELEROMETER));
147
148 EXPECT_FALSE(provider_->sensors_[1].ignored);
149 EXPECT_FALSE(provider_->sensors_[2].ignored);
150 EXPECT_TRUE(provider_->sensors_[3].ignored);
151 EXPECT_TRUE(provider_->sensors_[4].ignored);
152 EXPECT_TRUE(provider_->sensors_[5].ignored);
153 }
154
TEST_F(PlatformSensorProviderChromeOSTest,MissingScale)155 TEST_F(PlatformSensorProviderChromeOSTest, MissingScale) {
156 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
157 /*scale=*/base::nullopt, chromeos::sensors::mojom::kLocationBase);
158
159 StartConnection();
160
161 EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
162 }
163
TEST_F(PlatformSensorProviderChromeOSTest,MissingLocation)164 TEST_F(PlatformSensorProviderChromeOSTest, MissingLocation) {
165 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
166 base::NumberToString(kScaleValue),
167 /*location=*/base::nullopt);
168
169 StartConnection();
170
171 EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
172 }
173
TEST_F(PlatformSensorProviderChromeOSTest,WrongScale)174 TEST_F(PlatformSensorProviderChromeOSTest, WrongScale) {
175 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
176 kWrongScale, chromeos::sensors::mojom::kLocationBase);
177
178 StartConnection();
179
180 EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
181 }
182
TEST_F(PlatformSensorProviderChromeOSTest,WrongLocation)183 TEST_F(PlatformSensorProviderChromeOSTest, WrongLocation) {
184 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
185 base::NumberToString(kScaleValue), kWrongLocation);
186
187 StartConnection();
188
189 EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
190 }
191
TEST_F(PlatformSensorProviderChromeOSTest,CheckMainLocationBase)192 TEST_F(PlatformSensorProviderChromeOSTest, CheckMainLocationBase) {
193 int fake_id = 1;
194 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ACCEL,
195 base::NumberToString(kScaleValue),
196 chromeos::sensors::mojom::kLocationBase);
197
198 // Will not be used.
199 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ACCEL,
200 base::NumberToString(kScaleValue),
201 chromeos::sensors::mojom::kLocationLid);
202
203 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ANGLVEL,
204 base::NumberToString(kScaleValue),
205 chromeos::sensors::mojom::kLocationBase);
206
207 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::MAGN,
208 base::NumberToString(kScaleValue),
209 chromeos::sensors::mojom::kLocationBase);
210
211 StartConnection();
212
213 EXPECT_TRUE(CreateSensor(mojom::SensorType::GYROSCOPE));
214
215 // Wait until the disconnect of the gyroscope arrives at FakeSensorDevice.
216 base::RunLoop().RunUntilIdle();
217
218 // Remote stored in |provider_|.
219 EXPECT_TRUE(sensor_devices_[0]->HasReceivers());
220 EXPECT_TRUE(sensor_devices_[3]->HasReceivers());
221 // Removed in |provider_| as it'll never be used.
222 EXPECT_FALSE(sensor_devices_[1]->HasReceivers());
223 }
224
TEST_F(PlatformSensorProviderChromeOSTest,CheckMainLocationLid)225 TEST_F(PlatformSensorProviderChromeOSTest, CheckMainLocationLid) {
226 int fake_id = 1;
227 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ACCEL,
228 base::NumberToString(kScaleValue),
229 chromeos::sensors::mojom::kLocationBase);
230 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ACCEL,
231 base::NumberToString(kScaleValue),
232 chromeos::sensors::mojom::kLocationLid);
233
234 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ANGLVEL,
235 base::NumberToString(kScaleValue),
236 chromeos::sensors::mojom::kLocationBase);
237 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ANGLVEL,
238 base::NumberToString(kScaleValue),
239 chromeos::sensors::mojom::kLocationLid);
240
241 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::MAGN,
242 base::NumberToString(kScaleValue),
243 chromeos::sensors::mojom::kLocationCamera);
244
245 StartConnection();
246
247 // Wait until the disconnect of the first gyroscope arrives at
248 // FakeSensorDevice.
249 base::RunLoop().RunUntilIdle();
250
251 // Removed in |provider_| as they'll never be used.
252 EXPECT_FALSE(sensor_devices_[0]->HasReceivers());
253 EXPECT_FALSE(sensor_devices_[2]->HasReceivers());
254 EXPECT_FALSE(sensor_devices_[4]->HasReceivers());
255 // Remote stored in |provider_|.
256 EXPECT_TRUE(sensor_devices_[1]->HasReceivers());
257 EXPECT_TRUE(sensor_devices_[3]->HasReceivers());
258 }
259
TEST_F(PlatformSensorProviderChromeOSTest,CheckMainLocationLidWithMultitypeSensor)260 TEST_F(PlatformSensorProviderChromeOSTest,
261 CheckMainLocationLidWithMultitypeSensor) {
262 int fake_id = 1;
263 AddDevice(fake_id++,
264 std::set<chromeos::sensors::mojom::DeviceType>{
265 chromeos::sensors::mojom::DeviceType::ACCEL,
266 chromeos::sensors::mojom::DeviceType::ANGLVEL},
267 base::NumberToString(kScaleValue),
268 chromeos::sensors::mojom::kLocationLid);
269
270 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ANGLVEL,
271 base::NumberToString(kScaleValue),
272 chromeos::sensors::mojom::kLocationBase);
273
274 StartConnection();
275
276 // Wait until the disconnect of the gyroscope arrives at FakeSensorDevice.
277 base::RunLoop().RunUntilIdle();
278
279 // Remote stored in |provider_|.
280 EXPECT_TRUE(sensor_devices_[0]->HasReceivers());
281 // Removed in |provider_| as it'll never be used.
282 EXPECT_FALSE(sensor_devices_[1]->HasReceivers());
283
284 EXPECT_TRUE(CreateSensor(mojom::SensorType::ACCELEROMETER));
285 EXPECT_TRUE(CreateSensor(mojom::SensorType::GYROSCOPE));
286 }
287
TEST_F(PlatformSensorProviderChromeOSTest,CheckAmbientLightSensorLocationLid)288 TEST_F(PlatformSensorProviderChromeOSTest, CheckAmbientLightSensorLocationLid) {
289 int fake_id = 1;
290 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::LIGHT,
291 base::NumberToString(kScaleValue),
292 chromeos::sensors::mojom::kLocationBase);
293 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::LIGHT,
294 base::NumberToString(kScaleValue),
295 chromeos::sensors::mojom::kLocationLid);
296
297 StartConnection();
298
299 // Wait until the disconnect of the first ambient light sensor arrives at
300 // FakeSensorDevice.
301 base::RunLoop().RunUntilIdle();
302
303 // Removed in |provider_| as it'll never be used.
304 EXPECT_FALSE(sensor_devices_[0]->HasReceivers());
305 // Remote stored in |provider_|.
306 EXPECT_TRUE(sensor_devices_[1]->HasReceivers());
307 }
308
TEST_F(PlatformSensorProviderChromeOSTest,CheckAmbientLightSensorLocationBase)309 TEST_F(PlatformSensorProviderChromeOSTest,
310 CheckAmbientLightSensorLocationBase) {
311 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::LIGHT,
312 base::NumberToString(kScaleValue),
313 chromeos::sensors::mojom::kLocationBase);
314
315 StartConnection();
316
317 EXPECT_TRUE(CreateSensor(mojom::SensorType::AMBIENT_LIGHT));
318 }
319
TEST_F(PlatformSensorProviderChromeOSTest,Reconnect)320 TEST_F(PlatformSensorProviderChromeOSTest, Reconnect) {
321 int fake_id = 1;
322
323 // Will not be used.
324 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ACCEL,
325 base::NumberToString(kScaleValue),
326 chromeos::sensors::mojom::kLocationBase);
327
328 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ANGLVEL,
329 base::NumberToString(kScaleValue),
330 chromeos::sensors::mojom::kLocationLid);
331
332 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::LIGHT,
333 base::NumberToString(kScaleValue),
334 chromeos::sensors::mojom::kLocationBase);
335
336 StartConnection();
337
338 EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
339
340 // Simulate a disconnection between |provider_| and the dispatcher.
341 ResetClient();
342
343 EXPECT_TRUE(CreateSensor(mojom::SensorType::GYROSCOPE));
344
345 // Simulate a disconnection of IIO Service.
346 sensor_hal_server_->GetSensorService()->OnServiceDisconnect();
347 sensor_hal_server_->OnServerDisconnect();
348 // Remove the stored Mojo remote of the ambient light sensor.
349 sensor_devices_.back()->ClearReceivers();
350
351 // Wait until the disconnect arrives at the dispatcher.
352 base::RunLoop().RunUntilIdle();
353
354 StartConnection();
355
356 EXPECT_TRUE(CreateSensor(mojom::SensorType::AMBIENT_LIGHT));
357 }
358
TEST_F(PlatformSensorProviderChromeOSTest,CheckLinearAccelerationSensorNotCreatedIfNoAccelerometer)359 TEST_F(PlatformSensorProviderChromeOSTest,
360 CheckLinearAccelerationSensorNotCreatedIfNoAccelerometer) {
361 StartConnection();
362
363 EXPECT_FALSE(CreateSensor(mojom::SensorType::LINEAR_ACCELERATION));
364 }
365
TEST_F(PlatformSensorProviderChromeOSTest,CheckLinearAcceleration)366 TEST_F(PlatformSensorProviderChromeOSTest, CheckLinearAcceleration) {
367 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
368 base::NumberToString(kScaleValue),
369 chromeos::sensors::mojom::kLocationBase);
370
371 StartConnection();
372
373 EXPECT_TRUE(CreateSensor(mojom::SensorType::LINEAR_ACCELERATION));
374 }
375
TEST_F(PlatformSensorProviderChromeOSTest,CheckAbsoluteOrientationSensorNotCreatedIfNoAccelerometerAndNoMagnetometer)376 TEST_F(
377 PlatformSensorProviderChromeOSTest,
378 CheckAbsoluteOrientationSensorNotCreatedIfNoAccelerometerAndNoMagnetometer) {
379 StartConnection();
380
381 EXPECT_FALSE(
382 CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
383 EXPECT_FALSE(
384 CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION));
385 }
386
TEST_F(PlatformSensorProviderChromeOSTest,CheckAbsoluteOrientationSensorNotCreatedIfNoAccelerometer)387 TEST_F(PlatformSensorProviderChromeOSTest,
388 CheckAbsoluteOrientationSensorNotCreatedIfNoAccelerometer) {
389 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::MAGN,
390 base::NumberToString(kScaleValue),
391 chromeos::sensors::mojom::kLocationBase);
392
393 StartConnection();
394
395 EXPECT_FALSE(
396 CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
397 EXPECT_FALSE(
398 CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION));
399 }
400
TEST_F(PlatformSensorProviderChromeOSTest,CheckAbsoluteOrientationSensorNotCreatedIfNoMagnetometer)401 TEST_F(PlatformSensorProviderChromeOSTest,
402 CheckAbsoluteOrientationSensorNotCreatedIfNoMagnetometer) {
403 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
404 base::NumberToString(kScaleValue),
405 chromeos::sensors::mojom::kLocationBase);
406
407 StartConnection();
408
409 EXPECT_FALSE(
410 CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
411 EXPECT_FALSE(
412 CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION));
413 }
414
TEST_F(PlatformSensorProviderChromeOSTest,CheckAbsoluteOrientationSensors)415 TEST_F(PlatformSensorProviderChromeOSTest, CheckAbsoluteOrientationSensors) {
416 int fake_id = 1;
417
418 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ACCEL,
419 base::NumberToString(kScaleValue),
420 chromeos::sensors::mojom::kLocationBase);
421 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::MAGN,
422 base::NumberToString(kScaleValue),
423 chromeos::sensors::mojom::kLocationBase);
424
425 StartConnection();
426
427 EXPECT_TRUE(
428 CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
429 EXPECT_TRUE(CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION));
430 }
431
TEST_F(PlatformSensorProviderChromeOSTest,CheckRelativeOrientationSensorNotCreatedIfNoAccelerometerAndNoGyroscope)432 TEST_F(
433 PlatformSensorProviderChromeOSTest,
434 CheckRelativeOrientationSensorNotCreatedIfNoAccelerometerAndNoGyroscope) {
435 StartConnection();
436
437 EXPECT_FALSE(
438 CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES));
439 EXPECT_FALSE(
440 CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION));
441 }
442
TEST_F(PlatformSensorProviderChromeOSTest,CheckRelativeOrientationSensorNotCreatedIfNoAccelerometer)443 TEST_F(PlatformSensorProviderChromeOSTest,
444 CheckRelativeOrientationSensorNotCreatedIfNoAccelerometer) {
445 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ANGLVEL,
446 base::NumberToString(kScaleValue),
447 chromeos::sensors::mojom::kLocationBase);
448
449 StartConnection();
450
451 EXPECT_FALSE(
452 CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES));
453 EXPECT_FALSE(
454 CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION));
455 }
456
TEST_F(PlatformSensorProviderChromeOSTest,CheckRelativeOrientationSensorUsingAccelerometer)457 TEST_F(PlatformSensorProviderChromeOSTest,
458 CheckRelativeOrientationSensorUsingAccelerometer) {
459 AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
460 base::NumberToString(kScaleValue),
461 chromeos::sensors::mojom::kLocationBase);
462
463 StartConnection();
464
465 EXPECT_TRUE(
466 CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES));
467 EXPECT_TRUE(CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION));
468 }
469
TEST_F(PlatformSensorProviderChromeOSTest,CheckRelativeOrientationSensorUsingAccelerometerAndGyroscope)470 TEST_F(PlatformSensorProviderChromeOSTest,
471 CheckRelativeOrientationSensorUsingAccelerometerAndGyroscope) {
472 int fake_id = 1;
473 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ANGLVEL,
474 base::NumberToString(kScaleValue),
475 chromeos::sensors::mojom::kLocationBase);
476 AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ACCEL,
477 base::NumberToString(kScaleValue),
478 chromeos::sensors::mojom::kLocationBase);
479
480 StartConnection();
481
482 EXPECT_TRUE(
483 CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES));
484 EXPECT_TRUE(CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION));
485 }
486
487 } // namespace device
488