1 //
2 // Copyright (C) 2014 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 "update_engine/update_manager/real_shill_provider.h"
18
19 #include <string>
20
21 #include <base/logging.h>
22 #include <base/strings/stringprintf.h>
23 #include <brillo/type_name_undecorate.h>
24 #include <shill/dbus-constants.h>
25 #include <shill/dbus-proxies.h>
26
27 using chromeos_update_engine::connection_utils::ParseConnectionType;
28 using org::chromium::flimflam::ManagerProxyInterface;
29 using org::chromium::flimflam::ServiceProxyInterface;
30 using std::string;
31
32 namespace chromeos_update_manager {
33
Init()34 bool RealShillProvider::Init() {
35 ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy();
36 if (!manager_proxy)
37 return false;
38
39 // Subscribe to the manager's PropertyChanged signal.
40 manager_proxy->RegisterPropertyChangedSignalHandler(
41 base::Bind(&RealShillProvider::OnManagerPropertyChanged,
42 base::Unretained(this)),
43 base::Bind(&RealShillProvider::OnSignalConnected,
44 base::Unretained(this)));
45
46 // Attempt to read initial connection status. Even if this fails because shill
47 // is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
48 // signal as soon as it comes up, so this is not a critical step.
49 brillo::VariantDictionary properties;
50 brillo::ErrorPtr error;
51 if (!manager_proxy->GetProperties(&properties, &error))
52 return true;
53
54 const auto& prop_default_service =
55 properties.find(shill::kDefaultServiceProperty);
56 if (prop_default_service != properties.end()) {
57 OnManagerPropertyChanged(prop_default_service->first,
58 prop_default_service->second);
59 }
60
61 return true;
62 }
63
OnManagerPropertyChanged(const string & name,const brillo::Any & value)64 void RealShillProvider::OnManagerPropertyChanged(const string& name,
65 const brillo::Any& value) {
66 if (name == shill::kDefaultServiceProperty) {
67 dbus::ObjectPath service_path = value.TryGet<dbus::ObjectPath>();
68 if (!service_path.IsValid()) {
69 LOG(WARNING) << "Got an invalid DefaultService path. The property value "
70 "contains a "
71 << value.GetUndecoratedTypeName()
72 << ", read as the object path: '" << service_path.value()
73 << "'";
74 }
75 ProcessDefaultService(service_path);
76 }
77 }
78
OnSignalConnected(const string & interface_name,const string & signal_name,bool successful)79 void RealShillProvider::OnSignalConnected(const string& interface_name,
80 const string& signal_name,
81 bool successful) {
82 if (!successful) {
83 LOG(ERROR) << "Couldn't connect to the signal " << interface_name << "."
84 << signal_name;
85 }
86 }
87
ProcessDefaultService(const dbus::ObjectPath & default_service_path)88 bool RealShillProvider::ProcessDefaultService(
89 const dbus::ObjectPath& default_service_path) {
90 // We assume that if the service path didn't change, then the connection
91 // type and the tethering status of it also didn't change.
92 if (default_service_path_ == default_service_path)
93 return true;
94
95 // Update the connection status.
96 default_service_path_ = default_service_path;
97 bool is_connected = (default_service_path_.IsValid() &&
98 default_service_path_.value() != "/");
99 var_is_connected_.SetValue(is_connected);
100 var_conn_last_changed_.SetValue(clock_->GetWallclockTime());
101
102 if (!is_connected) {
103 var_conn_type_.UnsetValue();
104 var_conn_tethering_.UnsetValue();
105 return true;
106 }
107
108 // We create and dispose the ServiceProxyInterface on every request.
109 std::unique_ptr<ServiceProxyInterface> service =
110 shill_proxy_->GetServiceForPath(default_service_path_);
111
112 // Get the connection properties synchronously.
113 brillo::VariantDictionary properties;
114 brillo::ErrorPtr error;
115 if (!service->GetProperties(&properties, &error)) {
116 var_conn_type_.UnsetValue();
117 var_conn_tethering_.UnsetValue();
118 return false;
119 }
120
121 // Get the connection tethering mode.
122 const auto& prop_tethering = properties.find(shill::kTetheringProperty);
123 if (prop_tethering == properties.end()) {
124 // Remove the value if not present on the service. This most likely means an
125 // error in shill and the policy will handle it, but we will print a log
126 // message as well for accessing an unused variable.
127 var_conn_tethering_.UnsetValue();
128 LOG(ERROR) << "Could not find connection type (service: "
129 << default_service_path_.value() << ")";
130 } else {
131 // If the property doesn't contain a string value, the empty string will
132 // become kUnknown.
133 var_conn_tethering_.SetValue(
134 chromeos_update_engine::connection_utils::ParseConnectionTethering(
135 prop_tethering->second.TryGet<string>()));
136 }
137
138 // Get the connection type.
139 const auto& prop_type = properties.find(shill::kTypeProperty);
140 if (prop_type == properties.end()) {
141 var_conn_type_.UnsetValue();
142 LOG(ERROR) << "Could not find connection tethering mode (service: "
143 << default_service_path_.value() << ")";
144 } else {
145 string type_str = prop_type->second.TryGet<string>();
146 if (type_str == shill::kTypeVPN) {
147 const auto& prop_physical =
148 properties.find(shill::kPhysicalTechnologyProperty);
149 if (prop_physical == properties.end()) {
150 LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
151 << " connection (service: " << default_service_path_.value()
152 << "). Using default kUnknown value.";
153 var_conn_type_.SetValue(
154 chromeos_update_engine::ConnectionType::kUnknown);
155 } else {
156 var_conn_type_.SetValue(
157 ParseConnectionType(prop_physical->second.TryGet<string>()));
158 }
159 } else {
160 var_conn_type_.SetValue(ParseConnectionType(type_str));
161 }
162 }
163
164 return true;
165 }
166
167 } // namespace chromeos_update_manager
168