• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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