blob: 76f22180dd0619711289108a0c195bdb6cc83688 [file] [log] [blame]
// Copyright (c) 2012 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 "wimax_manager/manager.h"
#include <fcntl.h>
#include <base/file_util.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
#include <base/stl_util.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include "wimax_manager/dbus_service_dbus_proxy.h"
#include "wimax_manager/device.h"
#include "wimax_manager/device_dbus_adaptor.h"
#include "wimax_manager/event_dispatcher.h"
#include "wimax_manager/gdm_driver.h"
#include "wimax_manager/manager_dbus_adaptor.h"
#include "wimax_manager/proto_bindings/config.pb.h"
#include "wimax_manager/proto_bindings/network_operator.pb.h"
namespace wimax_manager {
namespace {
const int kMaxNumberOfDeviceScans = 15;
const int kDefaultDeviceScanIntervalInSeconds = 1;
const int kDeviceScanDelayAfterResumeInSeconds = 3;
const char kDefaultConfigFile[] = "/usr/share/wimax-manager/default.conf";
} // namespace
Manager::Manager(EventDispatcher *dispatcher)
: dispatcher_(dispatcher),
num_device_scans_(0),
dbus_service_(this) {
}
Manager::~Manager() {
Finalize();
}
bool Manager::Initialize() {
if (driver_.get())
return true;
if (!LoadConfig(base::FilePath(kDefaultConfigFile))) {
LOG(ERROR) << "Failed to load config";
return false;
}
dbus_service_.CreateDBusProxy();
dbus_service_.Initialize();
driver_.reset(new(std::nothrow) GdmDriver(this));
if (!driver_.get()) {
LOG(ERROR) << "Failed to create driver";
return false;
}
if (!driver_->Initialize()) {
LOG(ERROR) << "Failed to initialize driver";
return false;
}
if (!ScanDevices())
return false;
return true;
}
bool Manager::Finalize() {
CancelDeviceScan();
devices_.clear();
if (dbus_adaptor())
dbus_adaptor()->UpdateDevices();
if (!driver_.get())
return true;
if (!driver_->Finalize()) {
LOG(ERROR) << "Failed to de-initialize driver";
return false;
}
driver_.reset();
dbus_service_.Finalize();
return true;
}
bool Manager::ScanDevices() {
device_scan_timer_.Stop();
if (!devices_.empty())
return true;
if (!driver_->GetDevices(&devices_.get())) {
LOG(ERROR) << "Failed to get list of devices";
return false;
}
if (!devices_.empty()) {
for (size_t i = 0; i < devices_.size(); ++i)
devices_[i]->CreateDBusAdaptor();
dbus_adaptor()->UpdateDevices();
return true;
}
// Some platforms may not have any WiMAX device, so instead of scanning
// indefinitely, stop the device scan after a number of attempts.
if (++num_device_scans_ < kMaxNumberOfDeviceScans) {
VLOG(1) << "No WiMAX devices detected. Rescan later.";
device_scan_timer_.Start(
FROM_HERE,
base::TimeDelta::FromSeconds(kDefaultDeviceScanIntervalInSeconds),
this,
&Manager::OnDeviceScan);
}
return true;
}
void Manager::OnDeviceScan() {
ScanDevices();
}
void Manager::CancelDeviceScan() {
// Cancel any pending device scan.
device_scan_timer_.Stop();
num_device_scans_ = 0;
}
void Manager::Suspend() {
CancelDeviceScan();
devices_.clear();
dbus_adaptor()->UpdateDevices();
}
void Manager::Resume() {
// After resuming from suspend, the old device may not have been cleaned up.
// Delay the device scan to avoid getting the old device.
device_scan_timer_.Start(
FROM_HERE,
base::TimeDelta::FromSeconds(kDeviceScanDelayAfterResumeInSeconds),
this,
&Manager::OnDeviceScan);
}
bool Manager::LoadConfig(const base::FilePath &file_path) {
int fd = HANDLE_EINTR(open(file_path.MaybeAsASCII().c_str(), O_RDONLY));
if (fd == -1) {
PLOG(ERROR) << "Failed to read config file '"
<< file_path.MaybeAsASCII() << "'";
return false;
}
file_util::ScopedFD scoped_fd(&fd);
google::protobuf::io::FileInputStream file_stream(fd);
scoped_ptr<Config> config(new(std::nothrow) Config());
if (!google::protobuf::TextFormat::Parse(&file_stream, config.get()))
return false;
config_ = config.Pass();
return true;
}
const NetworkOperator *Manager::GetNetworkOperator(
Network::Identifier network_id) const {
if (!config_.get())
return NULL;
for (int i = 0; i < config_->network_operator_size(); ++i) {
const NetworkOperator &network_operator = config_->network_operator(i);
if (network_operator.identifier() == network_id)
return &network_operator;
}
return NULL;
}
} // namespace wimax_manager