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 47 using base::Bind; 48 using base::Unretained; 49 using std::string; 50 51 namespace shill { 52 53 namespace Logging { 54 static auto kModuleLogScope = ScopeLogger::kDaemon; 55 static string ObjectID(DaemonTask* d) { return "(chromeos_daemon)"; } 56 } 57 58 DaemonTask::DaemonTask(const Settings& settings, Config* config) 59 : settings_(settings), config_(config) {} 60 61 DaemonTask::~DaemonTask() {} 62 63 void 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 84 bool 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 98 void 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 126 void 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 155 void DaemonTask::StopAndReturnToMain() { 156 Stop(); 157 if (!termination_completed_callback_.is_null()) { 158 termination_completed_callback_.Run(); 159 } 160 } 161 162 void 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 196 void 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 210 void 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