Home | History | Annotate | Download | only in shill
      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