Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: device/generic_sensor/platform_sensor_manager_linux.cc

Issue 2533793002: [sensors](CrOS/Linux) Implement Sensor device manager for sensors (Closed)
Patch Set: fix build.gn Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "device/generic_sensor/platform_sensor_manager_linux.h"
6
7 #include "base/strings/string_number_conversions.h"
8 #include "base/threading/thread_restrictions.h"
9 #include "base/threading/thread_task_runner_handle.h"
10 #include "device/generic_sensor/linux/platform_sensor_reader_linux.h"
11 #include "device/generic_sensor/linux/sensor_data_linux.h"
12 #include "device/generic_sensor/platform_sensor_provider_linux.h"
13
14 namespace device {
15
16 namespace {
17
18 std::string StringOrEmptyIfNull(const char* value) {
19 return value ? value : std::string();
20 }
21
22 } // namespace
23
24 SensorDeviceLinux::SensorDeviceLinux(
25 const std::string& sensor_device_node,
26 double sensor_device_frequency,
27 double sensor_device_scaling_value,
28 double sensor_device_offset_value,
29 mojom::ReportingMode mode,
30 SensorDataLinux::ReaderFunctor scaling_func,
31 std::vector<base::FilePath> device_reading_files)
32 : device_node(sensor_device_node),
33 device_frequency(sensor_device_frequency),
34 device_scaling_value(sensor_device_scaling_value),
35 device_offset_value(sensor_device_offset_value),
36 reporting_mode(mode),
37 apply_scaling_func(scaling_func),
38 device_reading_files(std::move(device_reading_files)) {}
39
40 SensorDeviceLinux::~SensorDeviceLinux() = default;
41
42 SensorDeviceService::SensorDeviceService(
43 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
44 : observer_(this), manager_(nullptr), task_runner_(task_runner) {
Mikhail 2016/11/30 12:29:36 nit: move(task_runner)
maksims (do not use this acc) 2016/12/05 13:06:59 not needed any more.
45 thread_checker_.DetachFromThread();
46 }
47
48 SensorDeviceService::~SensorDeviceService() {
49 DCHECK(thread_checker_.CalledOnValidThread());
50 }
51
52 void SensorDeviceService::Start(
53 base::WeakPtr<SensorDeviceManager> manager,
54 SensorDeviceManager::OnDeviceAddedCallback device_added_callback,
55 SensorDeviceManager::OnDeviceRemovedCallback device_removed_callback) {
56 base::ThreadRestrictions::AssertIOAllowed();
57 DCHECK(thread_checker_.CalledOnValidThread());
58
59 manager_ = manager;
60 device_added_callback_ = device_added_callback;
61 device_removed_callback_ = device_removed_callback;
62
63 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance();
64 observer_.Add(monitor);
65 monitor->Enumerate(
66 base::Bind(&SensorDeviceService::OnDeviceAdded, base::Unretained(this)));
67
68 task_runner_->PostTask(
Mikhail 2016/11/30 12:29:36 could be done on upper call frame
69 FROM_HERE,
70 base::Bind(&SensorDeviceManager::SetEnumerationReady, manager_));
71 }
72
73 std::string SensorDeviceService::UdevDeviceGetSubsystem(udev_device* dev) {
Mikhail 2016/11/30 12:29:36 nit: Get..
maksims (do not use this acc) 2016/12/05 13:06:59 Done.
74 return StringOrEmptyIfNull(udev_device_get_subsystem(dev));
75 }
76
77 std::string SensorDeviceService::UdevDeviceGetSyspath(udev_device* dev) {
78 return StringOrEmptyIfNull(udev_device_get_syspath(dev));
79 }
80
81 std::string SensorDeviceService::UdevDeviceGetSysattrValue(
82 udev_device* dev,
83 const std::string& attribute) {
84 return StringOrEmptyIfNull(
85 udev_device_get_sysattr_value(dev, attribute.c_str()));
86 }
87
88 std::string SensorDeviceService::UdevDeviceGetDevnode(udev_device* dev) {
89 return StringOrEmptyIfNull(udev_device_get_devnode(dev));
90 }
91
92 void SensorDeviceService::OnDeviceAdded(udev_device* dev) {
93 const std::string subsystem = UdevDeviceGetSubsystem(dev);
94 if (subsystem.empty() || strcmp(subsystem.c_str(), "iio") != 0)
Mikhail 2016/11/30 12:29:36 subsystem.compare()
maksims (do not use this acc) 2016/12/05 13:06:59 Done.
95 return;
96
97 const std::string sysfs_path = UdevDeviceGetSyspath(dev);
98 if (sysfs_path.empty())
99 return;
100
101 const std::string device_node = UdevDeviceGetDevnode(dev);
102 if (device_node.empty())
103 return;
104
105 const uint32_t first = static_cast<uint32_t>(mojom::SensorType::FIRST);
106 const uint32_t last = static_cast<uint32_t>(mojom::SensorType::LAST);
107 for (uint32_t i = first; i < last; ++i) {
108 SensorDataLinux data;
109 mojom::SensorType type = static_cast<mojom::SensorType>(i);
110 if (!InitSensorData(type, &data)) {
111 continue;
112 }
113
114 std::vector<base::FilePath> sensor_file_names;
115 for (auto const& names : data.sensor_file_names) {
116 for (auto const& name : names) {
117 const std::string value = UdevDeviceGetSysattrValue(dev, name.c_str());
118 if (value.empty())
119 continue;
120 base::FilePath full_path = base::FilePath(sysfs_path).Append(name);
121 sensor_file_names.push_back(full_path);
122 break;
123 }
124 }
125
126 if (sensor_file_names.empty())
127 continue;
128
129 const std::string scaling_value =
130 UdevDeviceGetSysattrValue(dev, data.sensor_scale_name.c_str());
131 // If scaling value is not found, treat it as 1.
132 double sensor_scaling_value = 1;
133 if (!scaling_value.empty())
134 base::StringToDouble(scaling_value, &sensor_scaling_value);
135
136 const std::string offset_vallue =
137 UdevDeviceGetSysattrValue(dev, data.sensor_offset_file_name.c_str());
138 // If offset value is not found, treat it as 0.
139 double sensor_offset_value = 0;
140 if (!offset_vallue.empty())
141 base::StringToDouble(offset_vallue, &sensor_offset_value);
142
143 const std::string frequency_value =
144 UdevDeviceGetSysattrValue(dev, data.sensor_frequency_file_name.c_str());
145 // If frequency is not found, use default one from SensorDataLinux struct.
146 double sensor_frequency_value = data.default_configuration.frequency();
147 // By default, |reporting_mode| is ON_CHANGE. But if platform provides
148 // sampling frequency, the reporting mode is CONTINUOUS.
149 mojom::ReportingMode reporting_mode = mojom::ReportingMode::ON_CHANGE;
150 if (!frequency_value.empty()) {
151 base::StringToDouble(frequency_value, &sensor_frequency_value);
152 reporting_mode = mojom::ReportingMode::CONTINUOUS;
153 }
154
155 // One |dev| can represent more than one sensor.
156 // For example, there is an accelerometer and gyroscope represented by one
157 // |dev| in Chrome OS, kernel < 3.18. Thus, iterate through all possible
158 // types of sensors.
159 std::unique_ptr<SensorDeviceLinux> device(new SensorDeviceLinux(
160 device_node, sensor_frequency_value, sensor_scaling_value,
161 sensor_offset_value, reporting_mode, data.apply_scaling_func,
162 std::move(sensor_file_names)));
163 task_runner_->PostTask(
164 FROM_HERE,
165 base::Bind(device_added_callback_, data.type, base::Passed(&device)));
166 }
167 }
168
169 void SensorDeviceService::OnDeviceRemoved(udev_device* dev) {
170 const char* subsystem = udev_device_get_subsystem(dev);
171 if (!subsystem || strcmp(subsystem, "iio") != 0)
172 return;
173
174 const char* value = udev_device_get_devnode(dev);
175 if (!value)
176 return;
177 const std::string device_node = value;
178
179 const uint32_t first = static_cast<uint32_t>(mojom::SensorType::FIRST);
180 const uint32_t last = static_cast<uint32_t>(mojom::SensorType::LAST);
181 for (uint32_t i = first; i < last; ++i) {
Mikhail 2016/11/30 12:29:36 better to cache sensor nodes instead of running th
maksims (do not use this acc) 2016/12/05 13:06:59 Done.
182 SensorDataLinux data;
183 mojom::SensorType type = static_cast<mojom::SensorType>(i);
184 if (!InitSensorData(type, &data))
185 continue;
186
187 std::vector<base::FilePath> sensor_file_names;
188 for (auto const& names : data.sensor_file_names) {
189 for (auto const& name : names) {
190 const char* value = udev_device_get_sysattr_value(dev, name.c_str());
191 if (value)
192 break;
193 }
194 break;
195 }
196
197 // One |dev| can represent more than one sensor.
198 // For example, there is an accelerometer and gyroscope represented by one
199 // |dev| in Chrome OS, kernel < 3.18. Thus, iterate through all possible
200 // type of sensors.
201 task_runner_->PostTask(FROM_HERE, base::Bind(device_removed_callback_,
202 data.type, device_node));
203 }
204 }
205
206 SensorDeviceManager::SensorDeviceManager()
207 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
208 enumeration_ready_(false),
209 sensor_device_service_started_(false),
210 weak_factory_(this) {}
211
212 SensorDeviceManager::~SensorDeviceManager() {
213 DCHECK(!sensor_device_service_);
214 }
215
216 void SensorDeviceManager::Shutdown() {
217 DCHECK(task_runner_->BelongsToCurrentThread());
218 const bool did_post_task = file_task_runner_->DeleteSoon(
219 FROM_HERE, sensor_device_service_.release());
220 DCHECK(did_post_task);
221 enumeration_ready_ = false;
222 sensor_device_service_started_ = false;
223 sensor_device_map_.clear();
224 }
225
226 void SensorDeviceManager::GetSensorDevice(
227 mojom::SensorType type,
228 const GetSensorDeviceCallback& callback) {
229 DCHECK(task_runner_->BelongsToCurrentThread());
230 if (!InitializeService()) {
231 callback.Run(nullptr);
232 return;
233 }
234 // Enumeration is not ready yet.
235 // Store callbacks and run them when ready.
236 if (!enumeration_ready()) {
237 DCHECK(!base::ContainsKey(get_device_callbacks_, type));
238 get_device_callbacks_[type] = callback;
239 return;
240 }
241 SensorDeviceLinux* device = nullptr;
242 if (base::ContainsKey(sensor_device_map_, type))
243 device = sensor_device_map_[type].get();
244 callback.Run(device);
245 }
246
247 void SensorDeviceManager::GetAllSensorDevices(
248 const GetSensorDeviceCallback& callback) {
249 DCHECK(task_runner_->BelongsToCurrentThread());
250 // TODO(maksims): implement this method once we have discovery API.
251 NOTIMPLEMENTED();
252 }
253
254 void SensorDeviceManager::SetSensorDeviceServiceForTesting(
255 std::unique_ptr<SensorDeviceService> service) {
256 Shutdown();
257 sensor_device_service_ = std::move(service);
258 }
259
260 void SensorDeviceManager::SetBlockingTaskRunner(
261 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
262 file_task_runner_ = task_runner;
263 }
264
265 bool SensorDeviceManager::InitializeService() {
266 if (!sensor_device_service_) {
267 sensor_device_service_ =
268 base::MakeUnique<SensorDeviceService>(task_runner_);
269 }
270 if (!sensor_device_service_started_) {
271 OnDeviceAddedCallback device_added_callback = base::Bind(
272 &SensorDeviceManager::OnDeviceAdded, weak_factory_.GetWeakPtr());
273 OnDeviceRemovedCallback device_removed_callback = base::Bind(
274 &SensorDeviceManager::OnDeviceRemoved, weak_factory_.GetWeakPtr());
275
276 SetServiceStarted();
277 return file_task_runner_->PostTask(
278 FROM_HERE,
279 base::Bind(&SensorDeviceService::Start,
280 base::Unretained(sensor_device_service_.get()),
281 weak_factory_.GetWeakPtr(), std::move(device_added_callback),
282 std::move(device_removed_callback)));
283 }
284
285 return sensor_device_service_started_;
286 }
287
288 void SensorDeviceManager::SetServiceStarted() {
289 DCHECK(task_runner_->BelongsToCurrentThread());
290 DCHECK(!sensor_device_service_started_);
291 sensor_device_service_started_ = true;
292 }
293
294 void SensorDeviceManager::OnDeviceAdded(
295 mojom::SensorType type,
296 std::unique_ptr<SensorDeviceLinux> sensor_device) {
297 DCHECK(task_runner_->BelongsToCurrentThread());
298 // At the moment, we support only one device per type.
299 if (base::ContainsKey(sensor_device_map_, type))
300 return;
301 sensor_device_map_[type] = std::move(sensor_device);
302 }
303
304 void SensorDeviceManager::OnDeviceRemoved(mojom::SensorType type,
305 const std::string& device_node) {
306 DCHECK(task_runner_->BelongsToCurrentThread());
307 auto it = sensor_device_map_.find(type);
308 if (it == sensor_device_map_.end())
309 return;
310 if (it->second->device_node == device_node)
311 sensor_device_map_.erase(it);
312 }
313
314 void SensorDeviceManager::SetEnumerationReady() {
315 DCHECK(task_runner_->BelongsToCurrentThread());
316 DCHECK(!enumeration_ready());
317 enumeration_ready_ = true;
318 TriggerCallbacks();
319 }
320
321 void SensorDeviceManager::TriggerCallbacks() {
322 DCHECK(task_runner_->BelongsToCurrentThread());
323
324 CallbackToTypeMap::iterator cb_it = get_device_callbacks_.begin();
Mikhail 2016/11/30 12:29:36 I think we can avoid caching callbacks here, if in
maksims (do not use this acc) 2016/12/05 13:06:59 As long as I've merged this class with the provide
325 while (cb_it != get_device_callbacks_.end()) {
326 SensorDeviceLinux* device = nullptr;
327 mojom::SensorType type = cb_it->first;
328 auto dev_it = sensor_device_map_.find(type);
329 if (dev_it != sensor_device_map_.end())
330 device = dev_it->second.get();
331
332 GetSensorDeviceCallback cb = cb_it->second;
333 cb_it->second.Reset();
334 if (!cb.is_null())
335 cb.Run(device);
336 ++cb_it;
337 }
338 get_device_callbacks_.clear();
339 }
340
341 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698