1// Copyright (c) 2012 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 "chrome/browser/chromeos/camera_detector.h"
6
7#include "base/bind.h"
8#include "base/files/file_enumerator.h"
9#include "base/files/file_util.h"
10#include "base/location.h"
11#include "base/strings/string_split.h"
12#include "base/strings/string_util.h"
13#include "base/task_runner_util.h"
14#include "base/threading/sequenced_worker_pool.h"
15#include "components/storage_monitor/udev_util_linux.h"
16#include "content/public/browser/browser_thread.h"
17
18namespace chromeos {
19
20namespace {
21
22// Sysfs directory containing V4L devices.
23const char kV4LSubsystemDir[] = "/sys/class/video4linux/";
24// Name of the udev property with V4L capabilities.
25const char kV4LCapabilities[] = "ID_V4L_CAPABILITIES";
26// Delimiter character for udev V4L capabilities.
27const char kV4LCapabilitiesDelim = ':';
28// V4L capability that denotes a capture-enabled device.
29const char kV4LCaptureCapability[] = "capture";
30
31}  // namespace
32
33using content::BrowserThread;
34
35// static
36CameraDetector::CameraPresence CameraDetector::camera_presence_ =
37    CameraDetector::kCameraPresenceUnknown;
38
39// static
40bool CameraDetector::presence_check_in_progress_ = false;
41
42// static
43void CameraDetector::StartPresenceCheck(const base::Closure& callback) {
44  DCHECK(BrowserThread::CurrentlyOn(content::BrowserThread::UI));
45  if (presence_check_in_progress_)
46    return;
47  DVLOG(1) << "Starting camera presence check";
48  presence_check_in_progress_ = true;
49  base::PostTaskAndReplyWithResult(
50      BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
51          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(),
52      FROM_HERE,
53      base::Bind(&CameraDetector::CheckPresence),
54      base::Bind(&CameraDetector::OnPresenceCheckDone, callback));
55}
56
57// static
58void CameraDetector::OnPresenceCheckDone(const base::Closure& callback,
59                                         bool present) {
60  DCHECK(BrowserThread::CurrentlyOn(content::BrowserThread::UI));
61  camera_presence_ = present ? kCameraPresent : kCameraAbsent;
62  presence_check_in_progress_ = false;
63  callback.Run();
64}
65
66// static
67bool CameraDetector::CheckPresence() {
68  // We do a quick check using udev database because opening each /dev/videoX
69  // device may trigger costly device initialization.
70  base::FileEnumerator file_enum(
71      base::FilePath(kV4LSubsystemDir), false /* not recursive */,
72      base::FileEnumerator::FILES | base::FileEnumerator::SHOW_SYM_LINKS);
73  for (base::FilePath path = file_enum.Next(); !path.empty();
74       path = file_enum.Next()) {
75    std::string v4l_capabilities;
76    if (storage_monitor::GetUdevDevicePropertyValueByPath(
77            path, kV4LCapabilities, &v4l_capabilities)) {
78      std::vector<std::string> caps;
79      base::SplitString(v4l_capabilities, kV4LCapabilitiesDelim, &caps);
80      if (find(caps.begin(), caps.end(), kV4LCaptureCapability) != caps.end()) {
81        return true;
82      }
83    }
84  }
85  return false;
86}
87
88}  // namespace chromeos
89