Commit 0196b312 authored by Harvey Yang's avatar Harvey Yang Committed by Commit Bot

accelerometer: Update Ash Adding AccelerometerProviderMojo

This commit refactors ash/accelerometer that if group iioservice exists,
registering to Sensor Hal Dispatcher and waiting for samples updated
from iioservice instead of reading on sysfs files directly for
accelerometers' data.

BUG=b:172208566, b:172414227, b:168434557
TEST=builds, unit tests, and run on octopus & jacuzzi. Accels' samples
are updated successfully, and the auto-rotate screen is working.

Cq-Depend: chromium:2470222
Change-Id: Icf65705b2b8facb7fe79423edba163639e2ae45f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2345942Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Commit-Queue: Cheng-Hao Yang <chenghaoyang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827626}
parent 706cc012
......@@ -129,10 +129,15 @@ component("ash") {
"accelerators/pre_target_accelerator_handler.h",
"accelerators/spoken_feedback_toggler.cc",
"accelerators/spoken_feedback_toggler.h",
"accelerometer/accelerometer_constants.h",
"accelerometer/accelerometer_file_reader.cc",
"accelerometer/accelerometer_file_reader.h",
"accelerometer/accelerometer_provider_mojo.cc",
"accelerometer/accelerometer_provider_mojo.h",
"accelerometer/accelerometer_reader.cc",
"accelerometer/accelerometer_reader.h",
"accelerometer/accelerometer_samples_observer.cc",
"accelerometer/accelerometer_samples_observer.h",
"accelerometer/accelerometer_types.cc",
"accelerometer/accelerometer_types.h",
"accessibility/accessibility_controller_impl.cc",
......@@ -1763,6 +1768,8 @@ component("ash") {
# TODO(https://crbug.com/644336): Make CrasAudioHandler Chrome or Ash only.
"//chromeos/audio",
"//chromeos/components/multidevice/logging",
"//chromeos/components/sensors:sensors",
"//chromeos/components/sensors/mojom",
"//chromeos/constants",
"//chromeos/dbus",
......@@ -1920,6 +1927,8 @@ test("ash_unittests") {
"accelerators/accelerator_unittest.cc",
"accelerators/magnifier_key_scroller_unittest.cc",
"accelerators/spoken_feedback_toggler_unittest.cc",
"accelerometer/accelerometer_provider_mojo_unittest.cc",
"accelerometer/accelerometer_samples_observer_unittest.cc",
"accessibility/accessibility_controller_unittest.cc",
"accessibility/accessibility_focus_ring_controller_unittest.cc",
"accessibility/accessibility_focus_ring_group_unittest.cc",
......@@ -2366,6 +2375,9 @@ test("ash_unittests") {
"//chromeos/components/bloom/public/cpp",
"//chromeos/components/phonehub:test_support",
"//chromeos/components/quick_answers:quick_answers",
"//chromeos/components/sensors:sensors",
"//chromeos/components/sensors:test_support",
"//chromeos/components/sensors/mojom",
"//chromeos/constants",
"//chromeos/dbus:test_support",
"//chromeos/dbus/audio",
......
......@@ -62,6 +62,7 @@ include_rules = [
"+chromeos/components/proximity_auth/public/mojom",
"+chromeos/components/quick_answers",
"+chromeos/components/security_token_pin",
"+chromeos/components/sensors",
"+chromeos/constants",
# TODO(https://crbug.com/940810): Eliminate this.
"+chromeos/dbus/initialize_dbus_client.h",
......
// 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.
#ifndef ASH_ACCELEROMETER_ACCELEROMETER_CONSTANTS_H_
#define ASH_ACCELEROMETER_ACCELEROMETER_CONSTANTS_H_
#include "ash/accelerometer/accelerometer_types.h"
namespace ash {
const char kAccelerometerChannels[][8] = {"accel_x", "accel_y", "accel_z"};
// The number of axes for which there are accelerometer readings.
constexpr uint32_t kNumberOfAxes = 3u;
// The names of the accelerometers. Matches up with the enum AccelerometerSource
// in ash/accelerometer/accelerometer_types.h.
const char kLocationStrings[ACCELEROMETER_SOURCE_COUNT][5] = {"lid", "base"};
} // namespace ash
#endif // ASH_ACCELEROMETER_ACCELEROMETER_CONSTANTS_H_
......@@ -10,6 +10,7 @@
#include <string>
#include <vector>
#include "ash/accelerometer/accelerometer_constants.h"
#include "ash/public/cpp/tablet_mode_observer.h"
#include "ash/shell.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
......@@ -26,6 +27,8 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
#include "base/threading/platform_thread.h"
......@@ -78,11 +81,6 @@ constexpr char kLegacyAccelerometerScanIndexPathFormatString[] =
constexpr char kAccelerometerScanIndexPathFormatString[] =
"scan_elements/in_accel_%s_index";
// The names of the accelerometers. Matches up with the enum AccelerometerSource
// in ash/accelerometer/accelerometer_types.h.
constexpr char kAccelerometerNames[ACCELEROMETER_SOURCE_COUNT][5] = {"lid",
"base"};
// The axes on each accelerometer. The order was changed on kernel 3.18+.
constexpr char kAccelerometerAxes[][2] = {"x", "y", "z"};
constexpr char kLegacyAccelerometerAxes[][2] = {"y", "x", "z"};
......@@ -93,9 +91,6 @@ constexpr size_t kMaxAsciiUintLength = 21;
// The size of individual values.
constexpr size_t kDataSize = 2;
// The number of axes for which there are acceleration readings.
constexpr int kNumberOfAxes = 3;
// The size of data in one reading of the accelerometers.
constexpr int kSizeOfReading = kDataSize * kNumberOfAxes;
......@@ -150,9 +145,14 @@ AccelerometerFileReader::AccelerometerFileReader()
: observers_(
new base::ObserverListThreadSafe<AccelerometerReader::Observer>()) {}
void AccelerometerFileReader::PrepareAndInitialize(
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) {
task_runner_ = sequenced_task_runner;
void AccelerometerFileReader::PrepareAndInitialize() {
// AccelerometerReader is important for screen orientation so we need
// USER_VISIBLE priority.
// Use CONTINUE_ON_SHUTDOWN to avoid blocking shutdown since the datareading
// could get blocked on certain devices. See https://crbug.com/1023989.
task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
initialization_state_ = State::INITIALIZING;
......@@ -287,8 +287,8 @@ void AccelerometerFileReader::InitializeInternal() {
3 * static_cast<int>(configuration_.count)) {
const char* axis = legacy_cross_accel ? kLegacyAccelerometerAxes[j]
: kAccelerometerAxes[j];
LOG(ERROR) << "Field index for " << kAccelerometerNames[i] << " "
<< axis << " axis out of bounds.";
LOG(ERROR) << "Field index for " << kLocationStrings[i] << " " << axis
<< " axis out of bounds.";
initialization_state_ = State::FAILED;
return;
}
......@@ -438,12 +438,12 @@ bool AccelerometerFileReader::InitializeAccelerometer(
const base::FilePath& name,
const std::string& location) {
size_t config_index = 0;
for (; config_index < base::size(kAccelerometerNames); ++config_index) {
if (location == kAccelerometerNames[config_index])
for (; config_index < base::size(kLocationStrings); ++config_index) {
if (location == kLocationStrings[config_index])
break;
}
if (config_index >= base::size(kAccelerometerNames)) {
if (config_index >= base::size(kLocationStrings)) {
LOG(ERROR) << "Unrecognized location: " << location << " for device "
<< name.MaybeAsASCII() << "\n";
return false;
......@@ -487,11 +487,11 @@ bool AccelerometerFileReader::InitializeLegacyAccelerometers(
base::FilePath(kAccelerometerDevicePath).Append(name.BaseName());
// Read configuration of each accelerometer axis from each accelerometer from
// /sys/bus/iio/devices/iio:deviceX/.
for (size_t i = 0; i < base::size(kAccelerometerNames); ++i) {
for (size_t i = 0; i < base::size(kLocationStrings); ++i) {
configuration_.has[i] = false;
// Read scale of accelerometer.
std::string accelerometer_scale_path = base::StringPrintf(
kLegacyScaleNameFormatString, kAccelerometerNames[i]);
std::string accelerometer_scale_path =
base::StringPrintf(kLegacyScaleNameFormatString, kLocationStrings[i]);
// Read the scale for all axes.
int scale_divisor = 0;
if (!ReadFileToInt(iio_path.Append(accelerometer_scale_path.c_str()),
......@@ -507,9 +507,9 @@ bool AccelerometerFileReader::InitializeLegacyAccelerometers(
configuration_.has[i] = true;
for (size_t j = 0; j < base::size(kLegacyAccelerometerAxes); ++j) {
configuration_.scale[i][j] = base::kMeanGravityFloat / scale_divisor;
std::string accelerometer_index_path = base::StringPrintf(
kLegacyAccelerometerScanIndexPathFormatString,
kLegacyAccelerometerAxes[j], kAccelerometerNames[i]);
std::string accelerometer_index_path =
base::StringPrintf(kLegacyAccelerometerScanIndexPathFormatString,
kLegacyAccelerometerAxes[j], kLocationStrings[i]);
if (!ReadFileToInt(iio_path.Append(accelerometer_index_path.c_str()),
&(configuration_.index[i][j]))) {
configuration_.has[i] = false;
......
......@@ -15,8 +15,6 @@
namespace ash {
enum class State { INITIALIZING, SUCCESS, FAILED };
// Work that runs on a base::TaskRunner. It determines the accelerometer
// configuration, and reads the data. Upon a successful read it will notify
// all observers.
......@@ -28,8 +26,7 @@ class AccelerometerFileReader : public AccelerometerProviderInterface,
AccelerometerFileReader& operator=(const AccelerometerFileReader&) = delete;
// AccelerometerProviderInterface:
void PrepareAndInitialize(
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) override;
void PrepareAndInitialize() override;
void AddObserver(AccelerometerReader::Observer* observer) override;
void RemoveObserver(AccelerometerReader::Observer* observer) override;
void StartListenToTabletModeController() override;
......@@ -48,8 +45,9 @@ class AccelerometerFileReader : public AccelerometerProviderInterface,
// Tracks if accelerometer initialization is completed.
void CheckInitStatus();
// With ChromeOS EC lid angle driver present, accelerometer read is cancelled
// in clamshell mode, and triggered when entering tablet mode.
// With ChromeOS EC lid angle driver present, it's triggered when the device
// is physically used as a tablet (even thought its UI might be in clamshell
// mode), cancelled otherwise.
void TriggerRead();
void CancelRead();
......@@ -130,9 +128,6 @@ class AccelerometerFileReader : public AccelerometerProviderInterface,
void SetEmitEventsInternal(bool emit_events);
// The current initialization state of reader.
State initialization_state_ = State::INITIALIZING;
// True if periodical accelerometer read is on.
bool accelerometer_read_on_ = false;
......
This diff is collapsed.
// 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.
#ifndef ASH_ACCELEROMETER_ACCELEROMETER_PROVIDER_MOJO_H_
#define ASH_ACCELEROMETER_ACCELEROMETER_PROVIDER_MOJO_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "ash/accelerometer/accelerometer_reader.h"
#include "ash/accelerometer/accelerometer_samples_observer.h"
#include "ash/ash_export.h"
#include "ash/public/cpp/tablet_mode_observer.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace ash {
// Work that runs on the UI thread. As a sensor client, it communicates with IIO
// Service, determines the accelerometers' configuration, and waits for the
// accelerometers' samples. Upon receiving a sample, it will notify all
// observers.
class ASH_EXPORT AccelerometerProviderMojo
: public AccelerometerProviderInterface,
public TabletModeObserver,
public chromeos::sensors::mojom::SensorHalClient {
public:
AccelerometerProviderMojo();
AccelerometerProviderMojo(const AccelerometerProviderMojo&) = delete;
AccelerometerProviderMojo& operator=(const AccelerometerProviderMojo&) =
delete;
// AccelerometerProviderInterface:
void PrepareAndInitialize() override;
void AddObserver(AccelerometerReader::Observer* observer) override;
void RemoveObserver(AccelerometerReader::Observer* observer) override;
void StartListenToTabletModeController() override;
void StopListenToTabletModeController() override;
void SetEmitEvents(bool emit_events) override;
// TabletModeObserver:
void OnTabletPhysicalStateChanged() override;
// chromeos::sensors::mojom::SensorHalClient:
void SetUpChannel(mojo::PendingRemote<chromeos::sensors::mojom::SensorService>
pending_remote) override;
// With ChromeOS EC lid angle driver present, it's triggered when the device
// is physically used as a tablet (even thought its UI might be in clamshell
// mode), cancelled otherwise.
void TriggerRead();
void CancelRead();
State GetInitializationStateForTesting() const;
private:
struct AccelerometerData {
AccelerometerData();
~AccelerometerData();
bool ignored = false;
// Temporarily stores the accelerometer remote, waiting for it's scale and
// location information. It'll be passed to |samples_observer| as an
// argument after all information is collected.
mojo::Remote<chromeos::sensors::mojom::SensorDevice> remote;
base::Optional<AccelerometerSource> location;
base::Optional<float> scale;
std::unique_ptr<AccelerometerSamplesObserver> samples_observer;
};
~AccelerometerProviderMojo() override;
// Registers chromeos::sensors::mojom::SensorHalClient to Sensor Hal
// Dispatcher, waiting for the Mojo connection to IIO Service.
void RegisterSensorClient();
void OnSensorHalClientFailure();
void OnSensorServiceDisconnect();
void ResetSensorService();
// Callback of GetDeviceIds(ANGL), containing the lid-angle device's id if it
// exists.
void GetLidAngleIdsCallback(const std::vector<int32_t>& lid_angle_ids);
// Callback of GetDeviceIds(ACCEL), containing all iio_device_ids of
// accelerometers.
void GetAccelerometerIdsCallback(
const std::vector<int32_t>& accelerometer_ids);
// Creates the Mojo channel for the accelerometer, and requests the
// accelerometer's required attributes before creating the
// AccelerometerSamplesObserver of it.
void RegisterAccelerometerWithId(int32_t id);
void OnAccelerometerRemoteDisconnect(int32_t id);
void GetAttributesCallback(
int32_t id,
const std::vector<base::Optional<std::string>>& values);
// Ignores the accelerometer as the attributes are not expected.
void IgnoreAccelerometer(int32_t id);
// Checks and sets |initialization_state_| if all information is retrieved.
void CheckInitialization();
// Creates the AccelerometerSamplesObserver for the accelerometer with |id|.
void CreateAccelerometerSamplesObserver(int32_t id);
// Controls accelerometer reading.
void EnableAccelerometerReading();
void DisableAccelerometerReading();
// Called by |observers_|, containing a sample of the accelerometer.
void OnSampleUpdatedCallback(int iio_device_id, std::vector<float> sample);
void SetEmitEventsOnThread(bool emit_events);
// Sets FAILED to |initialization_state_| due to an error.
void FailedToInitialize();
void AddObserverOnThread(AccelerometerReader::Observer* observer);
// The task runner to use for blocking tasks.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// The Mojo channel connecting to Sensor Hal Dispatcher.
mojo::Receiver<chromeos::sensors::mojom::SensorHalClient> sensor_hal_client_;
// The Mojo channel to query and request for devices.
mojo::Remote<chromeos::sensors::mojom::SensorService> sensor_service_remote_;
// The existence of the accelerometer on the base.
bool has_accelerometer_base_ = false;
// First is the accelerometer's iio device id, second is it's data, mojo
// remote and samples observer.
std::map<int32_t, AccelerometerData> accelerometers_;
// First is the location index, second is the id of the accelerometer being
// used in this reader.
std::map<AccelerometerSource, int32_t> location_to_accelerometer_id_;
// The flag to delay |OnTabletPhysicalStateChanged| until
// |ec_lid_angle_driver_status_| is set.
bool pending_on_tablet_physical_state_changed_ = false;
// One time read upon |AddObserverOnThread|.
// Some observers need to know ECLidAngleDriverStatus, and it's guaranteed to
// be set before reading samples. When adding an observer, trigger at least
// one sample to notify observers that ECLidAngleDriverStatus has been set.
bool one_time_read_ = false;
// True if periodical accelerometer read is on.
bool accelerometer_read_on_ = false;
bool emit_events_ = true;
// The observers to notify of accelerometer updates.
scoped_refptr<base::ObserverListThreadSafe<AccelerometerReader::Observer>>
observers_;
// The last seen accelerometer data.
scoped_refptr<AccelerometerUpdate> update_;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace ash
#endif // ASH_ACCELEROMETER_ACCELEROMETER_PROVIDER_MOJO_H_
// 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 "ash/accelerometer/accelerometer_provider_mojo.h"
#include <memory>
#include <utility>
#include "ash/accelerometer/accelerometer_constants.h"
#include "ash/accelerometer/accelerometer_reader.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/task_environment.h"
#include "chromeos/components/sensors/fake_sensor_device.h"
#include "chromeos/components/sensors/fake_sensor_hal_server.h"
#include "chromeos/components/sensors/sensor_hal_dispatcher.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
constexpr double kFakeScaleValue = 10.0;
constexpr int kFakeLidAccelerometerId = 1;
constexpr int kFakeBaseAccelerometerId = 2;
constexpr int kFakeLidAngleId = 3;
constexpr int64_t kFakeSampleData[] = {1, 2, 3};
class FakeObserver : public AccelerometerReader::Observer {
public:
void OnAccelerometerUpdated(
scoped_refptr<const AccelerometerUpdate> update) override {
if (!update.get())
return;
for (uint32_t index = 0; index < ACCELEROMETER_SOURCE_COUNT; ++index) {
auto source = static_cast<AccelerometerSource>(index);
if (!update->has(source))
continue;
EXPECT_EQ(update->get(source).x, kFakeSampleData[0] * kFakeScaleValue);
EXPECT_EQ(update->get(source).y, kFakeSampleData[1] * kFakeScaleValue);
EXPECT_EQ(update->get(source).z, kFakeSampleData[2] * kFakeScaleValue);
}
update_ = update;
}
scoped_refptr<const AccelerometerUpdate> update_;
};
class AccelerometerProviderMojoTest : public ::testing::Test {
protected:
void SetUp() override {
sensor_hal_server_ =
std::make_unique<chromeos::sensors::FakeSensorHalServer>();
provider_ = new AccelerometerProviderMojo();
chromeos::sensors::SensorHalDispatcher::Initialize();
provider_->PrepareAndInitialize();
provider_->AddObserver(&observer_);
AddDevice(kFakeLidAccelerometerId,
chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kFakeScaleValue),
kLocationStrings[ACCELEROMETER_SOURCE_SCREEN]);
}
void TearDown() override {
chromeos::sensors::SensorHalDispatcher::Shutdown();
}
void AddDevice(int32_t iio_device_id,
chromeos::sensors::mojom::DeviceType type,
base::Optional<std::string> scale,
base::Optional<std::string> location) {
std::set<chromeos::sensors::mojom::DeviceType> types;
types.emplace(type);
std::vector<chromeos::sensors::FakeSensorDevice::ChannelData> channels_data;
if (type == chromeos::sensors::mojom::DeviceType::ACCEL) {
channels_data.resize(kNumberOfAxes);
for (uint32_t i = 0; i < kNumberOfAxes; ++i) {
channels_data[i].id = kAccelerometerChannels[i];
channels_data[i].sample_data = kFakeSampleData[i];
}
}
std::unique_ptr<chromeos::sensors::FakeSensorDevice> sensor_device(
new chromeos::sensors::FakeSensorDevice(std::move(channels_data)));
if (scale.has_value())
sensor_device->SetAttribute(chromeos::sensors::mojom::kScale,
scale.value());
if (location.has_value())
sensor_device->SetAttribute(chromeos::sensors::mojom::kLocation,
location.value());
sensor_hal_server_->GetSensorService()->SetDevice(
iio_device_id, std::move(types), std::move(sensor_device));
}
FakeObserver observer_;
std::unique_ptr<chromeos::sensors::FakeSensorHalServer> sensor_hal_server_;
scoped_refptr<AccelerometerProviderMojo> provider_;
base::test::SingleThreadTaskEnvironment task_environment;
};
TEST_F(AccelerometerProviderMojoTest, CheckNoScale) {
AddDevice(kFakeBaseAccelerometerId,
chromeos::sensors::mojom::DeviceType::ACCEL, base::nullopt,
kLocationStrings[ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD]);
chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer(
sensor_hal_server_->PassRemote());
// Wait until initialization failed.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::FAILED);
}
TEST_F(AccelerometerProviderMojoTest, CheckNoLocation) {
AddDevice(kFakeBaseAccelerometerId,
chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kFakeScaleValue), base::nullopt);
chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer(
sensor_hal_server_->PassRemote());
// Wait until initialization failed.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS);
}
TEST_F(AccelerometerProviderMojoTest, GetSamplesOfOneAccel) {
chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer(
sensor_hal_server_->PassRemote());
// Wait until a sample is received.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS);
EXPECT_TRUE(observer_.update_.get());
EXPECT_TRUE(observer_.update_->has(ACCELEROMETER_SOURCE_SCREEN));
EXPECT_FALSE(observer_.update_->has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD));
observer_.update_.reset();
// Simulate a disconnection of the accelerometer's mojo channel in IIO
// Service.
AddDevice(kFakeLidAccelerometerId,
chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kFakeScaleValue),
kLocationStrings[ACCELEROMETER_SOURCE_SCREEN]);
// Wait until the accelerometer's mojo channel is re-established and a sample
// is received.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(observer_.update_.get());
EXPECT_TRUE(observer_.update_->has(ACCELEROMETER_SOURCE_SCREEN));
EXPECT_FALSE(observer_.update_->has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD));
}
TEST_F(AccelerometerProviderMojoTest, GetSamplesWithNoLidAngle) {
AddDevice(kFakeBaseAccelerometerId,
chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kFakeScaleValue),
kLocationStrings[ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD]);
chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer(
sensor_hal_server_->PassRemote());
// Wait until samples are received.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS);
EXPECT_TRUE(observer_.update_.get());
EXPECT_TRUE(observer_.update_->has(ACCELEROMETER_SOURCE_SCREEN));
EXPECT_TRUE(observer_.update_->has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD));
observer_.update_.reset();
// Simulate a disconnection of the accelerometer's mojo channel in IIO
// Service.
AddDevice(kFakeLidAccelerometerId,
chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kFakeScaleValue),
kLocationStrings[ACCELEROMETER_SOURCE_SCREEN]);
// Wait until the accelerometer's mojo channel is re-established and a sample
// is received.
base::RunLoop().RunUntilIdle();
// Get the second sample from only one accelerometer.
EXPECT_FALSE(observer_.update_.get());
// Simulate a disconnection of the other accelerometer's mojo channel in IIO
// Service.
AddDevice(kFakeBaseAccelerometerId,
chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kFakeScaleValue),
kLocationStrings[ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD]);
// Wait until the other accelerometer's mojo channel is re-established and a
// sample is received.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(observer_.update_.get());
EXPECT_TRUE(observer_.update_->has(ACCELEROMETER_SOURCE_SCREEN));
EXPECT_TRUE(observer_.update_->has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD));
}
TEST_F(AccelerometerProviderMojoTest, GetSamplesWithLidAngle) {
AddDevice(kFakeBaseAccelerometerId,
chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kFakeScaleValue),
kLocationStrings[ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD]);
AddDevice(kFakeLidAngleId, chromeos::sensors::mojom::DeviceType::ANGL,
base::nullopt, base::nullopt);
chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer(
sensor_hal_server_->PassRemote());
// Wait until all setups are finished and the one time read is done.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(provider_->GetInitializationStateForTesting(), State::SUCCESS);
EXPECT_TRUE(observer_.update_.get());
EXPECT_TRUE(observer_.update_->has(ACCELEROMETER_SOURCE_SCREEN));
EXPECT_FALSE(observer_.update_->has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD));
observer_.update_.reset();
provider_->TriggerRead();
// Wait until samples are received.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(observer_.update_.get());
EXPECT_TRUE(observer_.update_->has(ACCELEROMETER_SOURCE_SCREEN));
EXPECT_FALSE(observer_.update_->has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD));
observer_.update_.reset();
// Simulate a disconnection of IIO Service.
sensor_hal_server_->GetSensorService()->OnServiceDisconnect();
sensor_hal_server_->OnServerDisconnect();
// Wait until the disconnect arrives at the dispatcher.
base::RunLoop().RunUntilIdle();
chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer(
sensor_hal_server_->PassRemote());
// Wait until samples are received.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(observer_.update_.get());
EXPECT_TRUE(observer_.update_->has(ACCELEROMETER_SOURCE_SCREEN));
EXPECT_FALSE(observer_.update_->has(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD));
}
} // namespace
} // namespace ash
......@@ -4,22 +4,31 @@
#include "ash/accelerometer/accelerometer_reader.h"
#include <grp.h>
#include "ash/accelerometer/accelerometer_file_reader.h"
#include "ash/accelerometer/accelerometer_provider_mojo.h"
#include "base/memory/singleton.h"
#include "base/posix/eintr_wrapper.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
namespace ash {
namespace {
// Group name of IIO Service, used to check if IIO Service exists.
constexpr char kIioServiceGroupName[] = "iioservice";
} // namespace
// static
AccelerometerReader* AccelerometerReader::GetInstance() {
return base::Singleton<AccelerometerReader>::get();
}
void AccelerometerReader::Initialize(
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) {
DCHECK(sequenced_task_runner.get());
accelerometer_provider_->PrepareAndInitialize(sequenced_task_runner);
void AccelerometerReader::Initialize() {
accelerometer_provider_->PrepareAndInitialize();
}
void AccelerometerReader::AddObserver(Observer* observer) {
......@@ -52,8 +61,19 @@ void AccelerometerReader::SetECLidAngleDriverStatusForTesting(
ec_lid_angle_driver_status);
}
AccelerometerReader::AccelerometerReader()
: accelerometer_provider_(new AccelerometerFileReader()) {}
AccelerometerReader::AccelerometerReader() {
char buf[1024];
struct group result;
struct group* resultp;
if (HANDLE_EINTR(getgrnam_r(kIioServiceGroupName, &result, buf, sizeof(buf),
&resultp)) < 0 ||
!resultp) {
accelerometer_provider_ = new AccelerometerFileReader();
} else {
accelerometer_provider_ = new AccelerometerProviderMojo();
}
}
AccelerometerReader::~AccelerometerReader() = default;
......
......@@ -19,6 +19,8 @@ class SequencedTaskRunner;
namespace ash {
enum class State { INITIALIZING, SUCCESS, FAILED };
enum class ECLidAngleDriverStatus { UNKNOWN, SUPPORTED, NOT_SUPPORTED };
class AccelerometerProviderInterface;
......@@ -39,8 +41,7 @@ class ASH_EXPORT AccelerometerReader {
static AccelerometerReader* GetInstance();
void Initialize(
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner);
void Initialize();
// Add/Remove observers.
void AddObserver(Observer* observer);
......@@ -79,10 +80,8 @@ class ASH_EXPORT AccelerometerReader {
class AccelerometerProviderInterface
: public base::RefCountedThreadSafe<AccelerometerProviderInterface> {
public:
// Prepare and start async initialization. SetSensorClient function
// contains actual code for initialization.
virtual void PrepareAndInitialize(
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) = 0;
// Prepare and start async initialization.
virtual void PrepareAndInitialize() = 0;
// Add/Remove observers.
virtual void AddObserver(AccelerometerReader::Observer* observer) = 0;
......@@ -104,6 +103,9 @@ class AccelerometerProviderInterface
protected:
virtual ~AccelerometerProviderInterface() = default;
// The current initialization state of reader.
State initialization_state_ = State::INITIALIZING;
// State of ChromeOS EC lid angle driver, if SUPPORTED, it means EC can handle
// lid angle calculation.
ECLidAngleDriverStatus ec_lid_angle_driver_status_ =
......
// 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 "ash/accelerometer/accelerometer_samples_observer.h"
#include <utility>
#include "base/bind.h"
namespace ash {
namespace {
constexpr int kTimeoutToleranceInMilliseconds = 500;
constexpr double kReadFrequencyInHz = 10.0;
} // namespace
AccelerometerSamplesObserver::AccelerometerSamplesObserver(
int iio_device_id,
mojo::Remote<chromeos::sensors::mojom::SensorDevice> sensor_device_remote,
float scale,
OnSampleUpdatedCallback on_sample_updated_callback)
: iio_device_id_(iio_device_id),
sensor_device_remote_(std::move(sensor_device_remote)),
scale_(scale),
on_sample_updated_callback_(std::move(on_sample_updated_callback)) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(sensor_device_remote_.is_bound());
sensor_device_remote_->GetAllChannelIds(
base::BindOnce(&AccelerometerSamplesObserver::GetAllChannelIdsCallback,
weak_factory_.GetWeakPtr()));
}
AccelerometerSamplesObserver::~AccelerometerSamplesObserver() = default;
void AccelerometerSamplesObserver::SetEnabled(bool enabled) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (enabled_ == enabled)
return;
enabled_ = enabled;
UpdateSensorDeviceFrequency();
}
void AccelerometerSamplesObserver::OnSampleUpdated(
const base::flat_map<int32_t, int64_t>& sample) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (sample.size() != kNumberOfAxes) {
LOG(ERROR) << "Invalid sample with size: " << sample.size();
OnErrorOccurred(chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
return;
}
std::vector<float> output_sample;
for (size_t axes = 0; axes < kNumberOfAxes; ++axes) {
auto it = sample.find(channel_indices_[axes]);
if (it == sample.end()) {
LOG(ERROR) << "Missing channel: " << kAccelerometerChannels[axes]
<< " in sample";
OnErrorOccurred(chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
return;
}
output_sample.push_back(it->second * scale_);
}
on_sample_updated_callback_.Run(iio_device_id_, output_sample);
}
void AccelerometerSamplesObserver::OnErrorOccurred(
chromeos::sensors::mojom::ObserverErrorType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (type) {
case chromeos::sensors::mojom::ObserverErrorType::ALREADY_STARTED:
LOG(ERROR) << "Device " << iio_device_id_
<< ": Another observer has already started to read samples";
Reset();
break;
case chromeos::sensors::mojom::ObserverErrorType::FREQUENCY_INVALID:
if (!enabled_) // It's normal if this observer is not enabled
break;
LOG(ERROR) << "Device " << iio_device_id_
<< ": Observer started with an invalid frequency";
UpdateSensorDeviceFrequency();
break;
case chromeos::sensors::mojom::ObserverErrorType::NO_ENABLED_CHANNELS:
LOG(ERROR) << "Device " << iio_device_id_
<< ": Observer started with no channels enabled";
if (sensor_device_remote_.is_bound()) {
sensor_device_remote_->SetChannelsEnabled(
std::vector<int32_t>(channel_indices_,
channel_indices_ + kNumberOfAxes),
/*enable=*/true,
base::BindOnce(
&AccelerometerSamplesObserver::SetChannelsEnabledCallback,
weak_factory_.GetWeakPtr()));
}
break;
case chromeos::sensors::mojom::ObserverErrorType::SET_FREQUENCY_IO_FAILED:
LOG(ERROR) << "Device " << iio_device_id_
<< ": Failed to set frequency to the physical device";
break;
case chromeos::sensors::mojom::ObserverErrorType::GET_FD_FAILED:
LOG(ERROR) << "Device " << iio_device_id_
<< ": Failed to get the device's fd to poll on";
break;
case chromeos::sensors::mojom::ObserverErrorType::READ_FAILED:
LOG(ERROR) << "Device " << iio_device_id_ << ": Failed to read a sample";
break;
case chromeos::sensors::mojom::ObserverErrorType::READ_TIMEOUT:
LOG(ERROR) << "Device " << iio_device_id_ << ": A read timed out";
break;
default:
LOG(ERROR) << "Device " << iio_device_id_ << ": error "
<< static_cast<int>(type);
break;
}
}
void AccelerometerSamplesObserver::Reset() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
LOG(ERROR) << "Resetting AccelerometerSamplesObserver: " << iio_device_id_;
receiver_.reset();
sensor_device_remote_.reset();
}
void AccelerometerSamplesObserver::GetAllChannelIdsCallback(
const std::vector<std::string>& iio_channel_ids) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(sensor_device_remote_.is_bound());
iio_channel_ids_ = std::move(iio_channel_ids);
for (size_t axis = 0; axis < kNumberOfAxes; ++axis) {
bool found = false;
for (size_t channel_index = 0; channel_index < iio_channel_ids_.size();
++channel_index) {
if (iio_channel_ids_[channel_index].compare(
kAccelerometerChannels[axis]) == 0) {
found = true;
channel_indices_[axis] = channel_index;
break;
}
}
if (!found) {
LOG(ERROR) << "Missing channel: " << kAccelerometerChannels[axis];
Reset();
return;
}
}
sensor_device_remote_->SetChannelsEnabled(
std::vector<int32_t>(channel_indices_, channel_indices_ + kNumberOfAxes),
/*enable=*/true,
base::BindOnce(&AccelerometerSamplesObserver::SetChannelsEnabledCallback,
weak_factory_.GetWeakPtr()));
StartReading();
}
void AccelerometerSamplesObserver::StartReading() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(sensor_device_remote_.is_bound());
sensor_device_remote_->SetTimeout(kTimeoutToleranceInMilliseconds);
sensor_device_remote_->StartReadingSamples(GetPendingRemote());
}
void AccelerometerSamplesObserver::UpdateSensorDeviceFrequency() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!sensor_device_remote_.is_bound())
return;
sensor_device_remote_->SetFrequency(
enabled_ ? kReadFrequencyInHz : 0.0,
base::BindOnce(&AccelerometerSamplesObserver::SetFrequencyCallback,
weak_factory_.GetWeakPtr()));
}
mojo::PendingRemote<chromeos::sensors::mojom::SensorDeviceSamplesObserver>
AccelerometerSamplesObserver::GetPendingRemote() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto pending_remote = receiver_.BindNewPipeAndPassRemote();
receiver_.set_disconnect_handler(base::BindOnce(
&AccelerometerSamplesObserver::ObserverConnectionErrorCallback,
weak_factory_.GetWeakPtr()));
return pending_remote;
}
void AccelerometerSamplesObserver::ObserverConnectionErrorCallback() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
LOG(ERROR) << "Observer connection error";
receiver_.reset();
if (sensor_device_remote_.is_bound())
StartReading();
}
void AccelerometerSamplesObserver::SetFrequencyCallback(
double result_frequency) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if ((result_frequency > 0.0 && enabled_) ||
(result_frequency == 0.0 && !enabled_)) {
return;
}
LOG(ERROR) << "Failed to set frequency: " << result_frequency
<< " with the samples observer enabled: "
<< (enabled_ ? "true" : "false");
Reset();
}
void AccelerometerSamplesObserver::SetChannelsEnabledCallback(
const std::vector<int32_t>& failed_indices) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (int32_t index : failed_indices)
LOG(ERROR) << "Failed to enable " << iio_channel_ids_[index];
if (!failed_indices.empty())
Reset();
}
} // namespace ash
// 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.
#ifndef ASH_ACCELEROMETER_ACCELEROMETER_SAMPLES_OBSERVER_H_
#define ASH_ACCELEROMETER_ACCELEROMETER_SAMPLES_OBSERVER_H_
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "ash/accelerometer/accelerometer_constants.h"
#include "ash/ash_export.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "chromeos/components/sensors/sensor_hal_dispatcher.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace ash {
// A SamplesObserver for an accelerometer device. When a sample is updated from
// IIO Service, it's sent to the AccelerometerProviderMojo via the callback
// |on_sample_udpated_callback_| registered in the constructor.
// AccelerometerSamplesObserver should only be used on the UI thread.
class ASH_EXPORT AccelerometerSamplesObserver
: public chromeos::sensors::mojom::SensorDeviceSamplesObserver {
public:
using OnSampleUpdatedCallback =
base::RepeatingCallback<void(int iio_device_id,
std::vector<float> sample)>;
AccelerometerSamplesObserver(
int iio_device_id,
mojo::Remote<chromeos::sensors::mojom::SensorDevice> sensor_device_remote,
float scale,
OnSampleUpdatedCallback on_sample_updated_callback);
AccelerometerSamplesObserver(const AccelerometerSamplesObserver&) = delete;
AccelerometerSamplesObserver& operator=(const AccelerometerSamplesObserver&) =
delete;
~AccelerometerSamplesObserver() override;
// Sets the observer |enabled| by setting the frequency to iioservice.
// Should be called on |task_runner_|.
void SetEnabled(bool enabled);
// chromeos::sensors::mojom::SensorDeviceSamplesObserver overrides:
void OnSampleUpdated(const base::flat_map<int32_t, int64_t>& sample) override;
void OnErrorOccurred(
chromeos::sensors::mojom::ObserverErrorType type) override;
private:
void Reset();
void GetAllChannelIdsCallback(
const std::vector<std::string>& iio_channel_ids);
void StartReading();
// Update this sensor device's frequency to kReadFrequencyInHz if |enabled_|
// is true, and to 0 if |enabled_| is false.
void UpdateSensorDeviceFrequency();
mojo::PendingRemote<chromeos::sensors::mojom::SensorDeviceSamplesObserver>
GetPendingRemote();
void ObserverConnectionErrorCallback();
void SetFrequencyCallback(double result_frequency);
void SetChannelsEnabledCallback(const std::vector<int32_t>& failed_indices);
int iio_device_id_;
mojo::Remote<chromeos::sensors::mojom::SensorDevice> sensor_device_remote_;
double scale_;
// Callback to send samples to the owner of this class.
OnSampleUpdatedCallback on_sample_updated_callback_;
// Boolean to indicate if this accelerometer should set a valid frequency and
// keep reading samples.
bool enabled_ = false;
// The list of channel ids retrieved from iioservice. Use channels' indices
// in this list to identify them.
std::vector<std::string> iio_channel_ids_;
// Channel indices (of accel_x, accel_y, and accel_z respectively) to
// enable.
int32_t channel_indices_[kNumberOfAxes];
mojo::Receiver<chromeos::sensors::mojom::SensorDeviceSamplesObserver>
receiver_{this};
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<AccelerometerSamplesObserver> weak_factory_{this};
};
} // namespace ash
#endif // ASH_ACCELEROMETER_ACCELEROMETER_SAMPLES_OBSERVER_H_
// 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 "ash/accelerometer/accelerometer_samples_observer.h"
#include <memory>
#include <utility>
#include "ash/accelerometer/accelerometer_constants.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "chromeos/components/sensors/fake_sensor_device.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
constexpr int kFakeAccelerometerId = 1;
constexpr int64_t kFakeSampleData[] = {1, 2, 3};
constexpr double kFakeScaleValue = 10.0;
class AccelerometerSamplesObserverTest : public ::testing::Test {
protected:
void SetChannels(uint32_t num_of_axes) {
CHECK_LE(num_of_axes, kNumberOfAxes);
std::vector<chromeos::sensors::FakeSensorDevice::ChannelData> channels_data(
num_of_axes);
for (uint32_t i = 0; i < num_of_axes; ++i) {
channels_data[i].id = kAccelerometerChannels[i];
channels_data[i].sample_data = kFakeSampleData[i];
}
sensor_device_ = std::make_unique<chromeos::sensors::FakeSensorDevice>(
std::move(channels_data));
}
void SetObserver(
mojo::Remote<chromeos::sensors::mojom::SensorDevice> accelerometer) {
observer_ = std::make_unique<AccelerometerSamplesObserver>(
kFakeAccelerometerId, std::move(accelerometer), kFakeScaleValue,
base::BindRepeating(
&AccelerometerSamplesObserverTest::OnSampleUpdatedCallback,
base::Unretained(this)));
}
void OnSampleUpdatedCallback(int iio_device_id, std::vector<float> sample) {
EXPECT_EQ(iio_device_id, kFakeAccelerometerId);
EXPECT_EQ(sample.size(), kNumberOfAxes);
for (uint32_t i = 0; i < kNumberOfAxes; ++i)
EXPECT_EQ(sample[i], kFakeSampleData[i] * kFakeScaleValue);
++num_samples_;
}
void DisableFirstChannel() {
sensor_device_->SetChannelsEnabled(
{0}, false,
base::BindOnce(
&AccelerometerSamplesObserverTest::SetChannelsEnabledCallback,
base::Unretained(this)));
}
void SetChannelsEnabledCallback(const std::vector<int32_t>& failed_indices) {
EXPECT_EQ(failed_indices.size(), 0u);
}
std::unique_ptr<chromeos::sensors::FakeSensorDevice> sensor_device_;
std::unique_ptr<AccelerometerSamplesObserver> observer_;
int num_samples_ = 0;
base::test::SingleThreadTaskEnvironment task_environment;
};
TEST_F(AccelerometerSamplesObserverTest, MissingChannels) {
SetChannels(kNumberOfAxes - 1);
mojo::Remote<chromeos::sensors::mojom::SensorDevice> accelerometer;
sensor_device_->AddReceiver(accelerometer.BindNewPipeAndPassReceiver());
SetObserver(std::move(accelerometer));
// Wait until the mojo connection is reset.
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(sensor_device_->HasReceivers());
}
TEST_F(AccelerometerSamplesObserverTest, StartReadingTwiceError) {
SetChannels(kNumberOfAxes);
mojo::Remote<chromeos::sensors::mojom::SensorDevice> accelerometer;
sensor_device_->AddReceiver(accelerometer.BindNewPipeAndPassReceiver());
mojo::PendingRemote<chromeos::sensors::mojom::SensorDeviceSamplesObserver>
pending_remote;
auto null_receiver = pending_remote.InitWithNewPipeAndPassReceiver();
accelerometer->StartReadingSamples(std::move(pending_remote));
SetObserver(std::move(accelerometer));
// Wait until the mojo connection is reset.
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(sensor_device_->HasReceivers());
}
TEST_F(AccelerometerSamplesObserverTest, GetSamples) {
SetChannels(kNumberOfAxes);
mojo::Remote<chromeos::sensors::mojom::SensorDevice> accelerometer;
sensor_device_->AddReceiver(accelerometer.BindNewPipeAndPassReceiver());
SetObserver(std::move(accelerometer));
observer_->SetEnabled(true);
// Wait until a sample is received.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(sensor_device_->HasReceivers());
EXPECT_EQ(num_samples_, 1);
// Simulate a disconnection of the observer's mojo channel in IIO Service.
sensor_device_->StopReadingSamples();
// Wait until the observer's mojo channel is re-established and a sample is
// received.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(sensor_device_->HasReceivers());
EXPECT_EQ(num_samples_, 2);
DisableFirstChannel();
// Wait until a sample is received.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(sensor_device_->HasReceivers());
// The updated sample is not sent to |OnSampleUpdatedCallback|.
EXPECT_EQ(num_samples_, 2);
}
} // namespace
} // namespace ash
......@@ -175,8 +175,6 @@
#include "base/notreached.h"
#include "base/system/sys_info.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h"
#include "chromeos/components/bloom/public/cpp/bloom_controller.h"
#include "chromeos/constants/chromeos_features.h"
......@@ -566,14 +564,7 @@ Shell::Shell(std::unique_ptr<ShellDelegate> shell_delegate)
// Ash doesn't properly remove pre-target-handlers.
ui::EventHandler::DisableCheckTargets();
// AccelerometerReader is important for screen orientation so we need
// USER_VISIBLE priority.
// Use CONTINUE_ON_SHUTDOWN to avoid blocking shutdown since the data reading
// could get blocked on certain devices. See https://crbug.com/1023989.
AccelerometerReader::GetInstance()->Initialize(
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
AccelerometerReader::GetInstance()->Initialize();
login_screen_controller_ =
std::make_unique<LoginScreenController>(system_tray_notifier_.get());
......
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