blob: 8035cb8be0d06e830bf06b408f6f3e47e996a433 [file] [log] [blame]
// Copyright 2017 The Chromium OS 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 "cfm-device-monitor/camera-monitor/huddly_monitor.h"
#include <base/logging.h>
#include <base/strings/string_util.h>
#include <base/sys_info.h>
#include <base/time/time.h>
#include <base/threading/platform_thread.h>
#include <dbus/message.h>
#include <dbus/permission_broker/dbus-constants.h>
#include <dbus/scoped_dbus_error.h>
#include <fstream>
#include <memory>
#include <sstream>
#include <string>
#include "cfm-device-monitor/camera-monitor/tools.h"
using permission_broker::kPermissionBrokerInterface;
using permission_broker::kPermissionBrokerServiceName;
using permission_broker::kPermissionBrokerServicePath;
using permission_broker::kPowerCycleUsbPorts;
namespace huddly_monitor {
namespace {
const char kError[] = "uvcvideo: Failed";
const char kErrorException[] = "uvcvideo: Failed to resubmit video URB";
} // namespace
// TODO(felixe): Using popen() to get a FILE* here and then using fileno() is
// not safe. Rewrite this to use base/process/launch.h.
HuddlyMonitor::HuddlyMonitor(bool init_wait_val, uint32_t sleep_time)
: AbstractMonitor(init_wait_val, sleep_time),
klog_pipe_(popen("dmesg -w --level=err", "r")),
error_matcher_(kError),
error_exception_(kErrorException) {}
HuddlyMonitor::~HuddlyMonitor() { pclose(klog_pipe_); }
bool HuddlyMonitor::VitalsExist() {
std::string msg = "";
bool found_error =
LookForErrorBlocking(error_matcher_, error_exception_, klog_pipe_, &msg);
if (!msg.empty()) {
LOG(ERROR) << "Failed trying to monitor camera. " << msg;
}
return !found_error;
}
bool HuddlyMonitor::InitDBus() {
if (!bus_) {
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
bus_ = new dbus::Bus(options);
}
if (!bus_->Connect()) {
LOG(ERROR) << "Faild to connect to D-Bus";
return false;
}
permission_broker_proxy_ =
bus_->GetObjectProxy(kPermissionBrokerServiceName,
dbus::ObjectPath(kPermissionBrokerServicePath));
if (!permission_broker_proxy_) {
LOG(ERROR) << "Faild to get D-Bus object proxy for permission_broker";
return false;
}
return true;
}
bool HuddlyMonitor::PowerCycleUsbPort(uint16_t vid, uint16_t pid,
base::TimeDelta delay) {
if (!permission_broker_proxy_ && !InitDBus()) {
return false;
}
dbus::MethodCall method_call(kPermissionBrokerInterface, kPowerCycleUsbPorts);
dbus::MessageWriter writer(&method_call);
writer.AppendUint16(vid);
writer.AppendUint16(pid);
writer.AppendInt64(delay.ToInternalValue());
std::unique_ptr<dbus::Response> response(
permission_broker_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
return response.get();
}
bool HuddlyMonitor::Respond() {
const base::TimeDelta kPowerCycleDelay =
base::TimeDelta::FromMilliseconds(200);
bool result;
// Guado can't power cycle USB devices trough permission_broker, it uses a
// board specific implementation instead.
std::string board = base::SysInfo::GetLsbReleaseBoard();
if (base::StartsWith(board, "guado", base::CompareCase::SENSITIVE)) {
result = HotplugDeviceGuado(kHuddlyVid, kHuddlyPid, klog_pipe_);
} else if (base::StartsWith(board, "fizz", base::CompareCase::SENSITIVE)) {
result = PowerCycleUsbPort(kHuddlyVid, kHuddlyPid, kPowerCycleDelay);
ConsumeAndDiscardInput(klog_pipe_);
} else {
LOG(WARNING) << "Unrecognized board type";
result = false;
}
if (result) {
// Please see b/109866345 before modyfing the below line.
LOG(WARNING) << "Detected crashed camera. Rebooted.";
const uint32_t kRebootSleepTimeSeconds = 30;
base::PlatformThread::Sleep(
base::TimeDelta::FromSeconds(kRebootSleepTimeSeconds));
}
return result;
}
} // namespace huddly_monitor