1// 2// Copyright (C) 2015 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "shill/daemon_task.h" 18 19#include <base/bind.h> 20 21#if !defined(ENABLE_JSON_STORE) 22#include <glib-object.h> 23#include <glib.h> 24#endif // ENABLE_JSON_STORE 25 26#if defined(ENABLE_BINDER) 27#include "shill/binder/binder_control.h" 28#elif defined(ENABLE_CHROMEOS_DBUS) 29#include "shill/dbus/chromeos_dbus_control.h" 30#endif // ENABLE_BINDER, ENABLE_CHROMEOS_DBUS 31#include "shill/control_interface.h" 32#include "shill/dhcp/dhcp_provider.h" 33#include "shill/error.h" 34#include "shill/logging.h" 35#include "shill/manager.h" 36#include "shill/net/ndisc.h" 37#include "shill/net/rtnl_handler.h" 38#include "shill/process_manager.h" 39#include "shill/routing_table.h" 40#include "shill/shill_config.h" 41 42#if !defined(DISABLE_WIFI) 43#include "shill/net/netlink_manager.h" 44#include "shill/net/nl80211_message.h" 45#endif // DISABLE_WIFI 46 47using base::Bind; 48using base::Unretained; 49using std::string; 50 51namespace shill { 52 53namespace Logging { 54static auto kModuleLogScope = ScopeLogger::kDaemon; 55static string ObjectID(DaemonTask* d) { return "(chromeos_daemon)"; } 56} 57 58DaemonTask::DaemonTask(const Settings& settings, Config* config) 59 : settings_(settings), config_(config) {} 60 61DaemonTask::~DaemonTask() {} 62 63void DaemonTask::ApplySettings() { 64 manager_->SetBlacklistedDevices(settings_.device_blacklist); 65 manager_->SetWhitelistedDevices(settings_.device_whitelist); 66 Error error; 67 manager_->SetTechnologyOrder(settings_.default_technology_order, &error); 68 CHECK(error.IsSuccess()); // Command line should have been validated. 69 manager_->SetIgnoreUnknownEthernet(settings_.ignore_unknown_ethernet); 70 if (settings_.use_portal_list) { 71 manager_->SetStartupPortalList(settings_.portal_list); 72 } 73 if (settings_.passive_mode) { 74 manager_->SetPassiveMode(); 75 } 76 manager_->SetPrependDNSServers(settings_.prepend_dns_servers); 77 if (settings_.minimum_mtu) { 78 manager_->SetMinimumMTU(settings_.minimum_mtu); 79 } 80 manager_->SetAcceptHostnameFrom(settings_.accept_hostname_from); 81 manager_->SetDHCPv6EnabledDevices(settings_.dhcpv6_enabled_devices); 82} 83 84bool DaemonTask::Quit(const base::Closure& completion_callback) { 85 SLOG(this, 1) << "Starting termination actions."; 86 if (manager_->RunTerminationActionsAndNotifyMetrics( 87 Bind(&DaemonTask::TerminationActionsCompleted, Unretained(this)))) { 88 SLOG(this, 1) << "Will wait for termination actions to complete"; 89 termination_completed_callback_ = completion_callback; 90 return false; // Note to caller: don't exit yet! 91 } else { 92 SLOG(this, 1) << "No termination actions were run"; 93 StopAndReturnToMain(); 94 return true; // All done, ready to exit. 95 } 96} 97 98void DaemonTask::Init() { 99 dispatcher_.reset(new EventDispatcher()); 100#if defined(ENABLE_BINDER) 101 control_.reset(new BinderControl(dispatcher_.get())); 102#elif defined(ENABLE_CHROMEOS_DBUS) 103 control_.reset(new ChromeosDBusControl(dispatcher_.get())); 104#else 105// TODO(zqiu): use default stub control interface. 106#error Control interface type not specified. 107#endif // ENABLE_BINDER, ENABLE_CHROMEOS_DBUS 108 metrics_.reset(new Metrics(dispatcher_.get())); 109 rtnl_handler_ = RTNLHandler::GetInstance(); 110 routing_table_ = RoutingTable::GetInstance(); 111 dhcp_provider_ = DHCPProvider::GetInstance(); 112 process_manager_ = ProcessManager::GetInstance(); 113#if !defined(DISABLE_WIFI) 114 netlink_manager_ = NetlinkManager::GetInstance(); 115 callback80211_metrics_.reset(new Callback80211Metrics(metrics_.get())); 116#endif // DISABLE_WIFI 117 manager_.reset(new Manager(control_.get(), dispatcher_.get(), metrics_.get(), 118 config_->GetRunDirectory(), 119 config_->GetStorageDirectory(), 120 config_->GetUserStorageDirectory())); 121 control_->RegisterManagerObject( 122 manager_.get(), base::Bind(&DaemonTask::Start, base::Unretained(this))); 123 ApplySettings(); 124} 125 126void DaemonTask::TerminationActionsCompleted(const Error& error) { 127 SLOG(this, 1) << "Finished termination actions. Result: " << error; 128 metrics_->NotifyTerminationActionsCompleted(error.IsSuccess()); 129 130 // Daemon::TerminationActionsCompleted() should not directly call 131 // Daemon::Stop(). Otherwise, it could lead to the call sequence below. That 132 // is not safe as the HookTable's start callback only holds a weak pointer to 133 // the Cellular object, which is destroyed in midst of the 134 // Cellular::OnTerminationCompleted() call. We schedule the 135 // Daemon::StopAndReturnToMain() call through the message loop instead. 136 // 137 // Daemon::Quit 138 // -> Manager::RunTerminationActionsAndNotifyMetrics 139 // -> Manager::RunTerminationActions 140 // -> HookTable::Run 141 // ... 142 // -> Cellular::OnTerminationCompleted 143 // -> Manager::TerminationActionComplete 144 // -> HookTable::ActionComplete 145 // -> Daemon::TerminationActionsCompleted 146 // -> Daemon::Stop 147 // -> Manager::Stop 148 // -> DeviceInfo::Stop 149 // -> Cellular::~Cellular 150 // -> Manager::RemoveTerminationAction 151 dispatcher_->PostTask( 152 Bind(&DaemonTask::StopAndReturnToMain, Unretained(this))); 153} 154 155void DaemonTask::StopAndReturnToMain() { 156 Stop(); 157 if (!termination_completed_callback_.is_null()) { 158 termination_completed_callback_.Run(); 159 } 160} 161 162void DaemonTask::Start() { 163#if !defined(ENABLE_JSON_STORE) 164 g_type_init(); 165#endif 166 metrics_->Start(); 167 rtnl_handler_->Start(RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | 168 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE | 169 RTMGRP_ND_USEROPT); 170 routing_table_->Start(); 171 dhcp_provider_->Init(control_.get(), dispatcher_.get(), metrics_.get()); 172 process_manager_->Init(dispatcher_.get()); 173#if !defined(DISABLE_WIFI) 174 if (netlink_manager_) { 175 netlink_manager_->Init(); 176 uint16_t nl80211_family_id = 177 netlink_manager_->GetFamily(Nl80211Message::kMessageTypeString, 178 Bind(&Nl80211Message::CreateMessage)); 179 if (nl80211_family_id == NetlinkMessage::kIllegalMessageType) { 180 LOG(FATAL) << "Didn't get a legal message type for 'nl80211' messages."; 181 } 182 Nl80211Message::SetMessageType(nl80211_family_id); 183 netlink_manager_->Start(); 184 185 // Install handlers for NetlinkMessages that don't have specific handlers 186 // (which are registered by message sequence number). 187 netlink_manager_->AddBroadcastHandler( 188 Bind(&Callback80211Metrics::CollectDisconnectStatistics, 189 callback80211_metrics_->AsWeakPtr())); 190 } 191#endif // DISABLE_WIFI 192 193 manager_->Start(); 194} 195 196void DaemonTask::Stop() { 197 manager_->Stop(); 198 manager_ = nullptr; // Release manager resources, including DBus adaptor. 199#if !defined(DISABLE_WIFI) 200 callback80211_metrics_ = nullptr; 201#endif // DISABLE_WIFI 202 metrics_->Stop(); 203 process_manager_->Stop(); 204 dhcp_provider_->Stop(); 205 metrics_ = nullptr; 206 // Must retain |control_|, as the D-Bus library may 207 // have some work left to do. See crbug.com/537771. 208} 209 210void DaemonTask::BreakTerminationLoop() { 211 // Break out of the termination loop, to continue on with other shutdown 212 // tasks. 213 brillo::MessageLoop::current()->BreakLoop(); 214} 215 216} // namespace shill 217