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;
ObjectID(DaemonTask * d)55 static string ObjectID(DaemonTask* d) { return "(chromeos_daemon)"; }
56 }
57
DaemonTask(const Settings & settings,Config * config)58 DaemonTask::DaemonTask(const Settings& settings, Config* config)
59 : settings_(settings), config_(config) {}
60
~DaemonTask()61 DaemonTask::~DaemonTask() {}
62
ApplySettings()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
Quit(const base::Closure & completion_callback)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
Init()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
TerminationActionsCompleted(const Error & error)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
StopAndReturnToMain()155 void DaemonTask::StopAndReturnToMain() {
156 Stop();
157 if (!termination_completed_callback_.is_null()) {
158 termination_completed_callback_.Run();
159 }
160 }
161
Start()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
Stop()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
BreakTerminationLoop()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