Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / chromeos / net / wake_on_wifi_manager.cc
blob842acc54862ee2d0486a36efdf2381ff4cbed43c
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/net/wake_on_wifi_manager.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/containers/scoped_ptr_hash_map.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/sys_info.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/services/gcm/gcm_profile_service.h"
19 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
20 #include "chromeos/chromeos_switches.h"
21 #include "chromeos/login/login_state.h"
22 #include "chromeos/network/device_state.h"
23 #include "chromeos/network/network_device_handler.h"
24 #include "chromeos/network/network_handler.h"
25 #include "chromeos/network/network_state_handler.h"
26 #include "chromeos/network/network_type_pattern.h"
27 #include "components/gcm_driver/gcm_connection_observer.h"
28 #include "components/gcm_driver/gcm_driver.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/notification_service.h"
31 #include "content/public/browser/notification_source.h"
32 #include "net/base/ip_endpoint.h"
33 #include "third_party/cros_system_api/dbus/service_constants.h"
35 namespace chromeos {
37 namespace {
39 const char kWakeOnNone[] = "none";
40 const char kWakeOnPacket[] = "packet";
41 const char kWakeOnSsid[] = "ssid";
42 const char kWakeOnPacketAndSsid[] = "packet_and_ssid";
44 std::string WakeOnWifiFeatureToString(
45 WakeOnWifiManager::WakeOnWifiFeature feature) {
46 switch (feature) {
47 case WakeOnWifiManager::WAKE_ON_NONE:
48 return kWakeOnNone;
49 case WakeOnWifiManager::WAKE_ON_PACKET:
50 return kWakeOnPacket;
51 case WakeOnWifiManager::WAKE_ON_SSID:
52 return kWakeOnSsid;
53 case WakeOnWifiManager::WAKE_ON_PACKET_AND_SSID:
54 return kWakeOnPacketAndSsid;
55 case WakeOnWifiManager::INVALID:
56 return std::string();
57 case WakeOnWifiManager::NOT_SUPPORTED:
58 NOTREACHED();
59 return std::string();
62 NOTREACHED() << "Unknown wake on wifi feature: " << feature;
63 return std::string();
66 bool IsWakeOnPacketEnabled(WakeOnWifiManager::WakeOnWifiFeature feature) {
67 return feature & WakeOnWifiManager::WAKE_ON_PACKET;
70 // Weak pointer. This class is owned by ChromeBrowserMainPartsChromeos.
71 WakeOnWifiManager* g_wake_on_wifi_manager = NULL;
73 } // namespace
75 // Simple class that listens for a connection to the GCM server and passes the
76 // connection information down to shill. Each profile gets its own instance of
77 // this class.
78 class WakeOnWifiManager::WakeOnPacketConnectionObserver
79 : public gcm::GCMConnectionObserver {
80 public:
81 WakeOnPacketConnectionObserver(Profile* profile,
82 bool wifi_properties_received)
83 : profile_(profile),
84 ip_endpoint_(net::IPEndPoint()),
85 wifi_properties_received_(wifi_properties_received) {
86 gcm::GCMProfileServiceFactory::GetForProfile(profile_)
87 ->driver()
88 ->AddConnectionObserver(this);
91 ~WakeOnPacketConnectionObserver() override {
92 if (!(ip_endpoint_ == net::IPEndPoint()))
93 OnDisconnected();
95 gcm::GCMProfileServiceFactory::GetForProfile(profile_)
96 ->driver()
97 ->RemoveConnectionObserver(this);
100 void HandleWifiDevicePropertiesReady() {
101 wifi_properties_received_ = true;
103 // IPEndPoint doesn't implement operator!=
104 if (ip_endpoint_ == net::IPEndPoint())
105 return;
107 AddWakeOnPacketConnection();
110 // gcm::GCMConnectionObserver overrides.
112 void OnConnected(const net::IPEndPoint& ip_endpoint) override {
113 ip_endpoint_ = ip_endpoint;
115 if (wifi_properties_received_)
116 AddWakeOnPacketConnection();
119 void OnDisconnected() override {
120 if (ip_endpoint_ == net::IPEndPoint()) {
121 VLOG(1) << "Received GCMConnectionObserver::OnDisconnected without a "
122 << "valid IPEndPoint.";
123 return;
126 if (wifi_properties_received_)
127 RemoveWakeOnPacketConnection();
129 ip_endpoint_ = net::IPEndPoint();
132 private:
133 void AddWakeOnPacketConnection() {
134 NetworkHandler::Get()
135 ->network_device_handler()
136 ->AddWifiWakeOnPacketConnection(ip_endpoint_,
137 base::Bind(&base::DoNothing),
138 network_handler::ErrorCallback());
141 void RemoveWakeOnPacketConnection() {
142 NetworkHandler::Get()
143 ->network_device_handler()
144 ->RemoveWifiWakeOnPacketConnection(ip_endpoint_,
145 base::Bind(&base::DoNothing),
146 network_handler::ErrorCallback());
149 Profile* profile_;
150 net::IPEndPoint ip_endpoint_;
151 bool wifi_properties_received_;
153 DISALLOW_COPY_AND_ASSIGN(WakeOnPacketConnectionObserver);
156 // static
157 WakeOnWifiManager* WakeOnWifiManager::Get() {
158 DCHECK(g_wake_on_wifi_manager);
159 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
160 return g_wake_on_wifi_manager;
163 WakeOnWifiManager::WakeOnWifiManager()
164 : current_feature_(WakeOnWifiManager::INVALID),
165 wifi_properties_received_(false),
166 extension_event_observer_(new ExtensionEventObserver()),
167 weak_ptr_factory_(this) {
168 // This class must be constructed before any users are logged in, i.e., before
169 // any profiles are created or added to the ProfileManager. Additionally,
170 // IsUserLoggedIn always returns true when we are not running on a Chrome OS
171 // device so this check should only run on real devices.
172 CHECK(!base::SysInfo::IsRunningOnChromeOS() ||
173 !LoginState::Get()->IsUserLoggedIn());
174 DCHECK(!g_wake_on_wifi_manager);
175 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
177 g_wake_on_wifi_manager = this;
179 registrar_.Add(this,
180 chrome::NOTIFICATION_PROFILE_ADDED,
181 content::NotificationService::AllBrowserContextsAndSources());
182 registrar_.Add(this,
183 chrome::NOTIFICATION_PROFILE_DESTROYED,
184 content::NotificationService::AllBrowserContextsAndSources());
186 NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
188 GetWifiDeviceProperties();
191 WakeOnWifiManager::~WakeOnWifiManager() {
192 DCHECK(g_wake_on_wifi_manager);
193 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
194 if (current_feature_ != NOT_SUPPORTED) {
195 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
196 FROM_HERE);
198 g_wake_on_wifi_manager = NULL;
201 void WakeOnWifiManager::OnPreferenceChanged(
202 WakeOnWifiManager::WakeOnWifiFeature feature) {
203 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
204 if (current_feature_ == NOT_SUPPORTED)
205 return;
206 if (!switches::WakeOnWifiEnabled())
207 feature = WAKE_ON_NONE;
208 if (feature == current_feature_)
209 return;
211 current_feature_ = feature;
213 if (wifi_properties_received_)
214 HandleWakeOnWifiFeatureUpdated();
217 bool WakeOnWifiManager::WakeOnWifiSupported() {
218 return current_feature_ != NOT_SUPPORTED && current_feature_ != INVALID;
221 void WakeOnWifiManager::Observe(int type,
222 const content::NotificationSource& source,
223 const content::NotificationDetails& details) {
224 switch (type) {
225 case chrome::NOTIFICATION_PROFILE_ADDED: {
226 OnProfileAdded(content::Source<Profile>(source).ptr());
227 break;
229 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
230 OnProfileDestroyed(content::Source<Profile>(source).ptr());
231 break;
233 default:
234 NOTREACHED();
238 void WakeOnWifiManager::DeviceListChanged() {
239 if (current_feature_ != NOT_SUPPORTED)
240 GetWifiDeviceProperties();
243 void WakeOnWifiManager::DevicePropertiesUpdated(const DeviceState* device) {
244 if (device->Matches(NetworkTypePattern::WiFi()) &&
245 current_feature_ != NOT_SUPPORTED) {
246 GetWifiDeviceProperties();
250 void WakeOnWifiManager::HandleWakeOnWifiFeatureUpdated() {
251 const DeviceState* device =
252 NetworkHandler::Get()->network_state_handler()->GetDeviceStateByType(
253 NetworkTypePattern::WiFi());
254 if (!device)
255 return;
257 std::string feature_string(WakeOnWifiFeatureToString(current_feature_));
258 DCHECK(!feature_string.empty());
260 NetworkHandler::Get()->network_device_handler()->SetDeviceProperty(
261 device->path(),
262 shill::kWakeOnWiFiFeaturesEnabledProperty,
263 base::StringValue(feature_string),
264 base::Bind(&base::DoNothing),
265 network_handler::ErrorCallback());
267 bool wake_on_packet_enabled = IsWakeOnPacketEnabled(current_feature_);
268 for (const auto& kv_pair : connection_observers_) {
269 Profile* profile = kv_pair.first;
270 gcm::GCMProfileServiceFactory::GetForProfile(profile)
271 ->driver()
272 ->WakeFromSuspendForHeartbeat(wake_on_packet_enabled);
275 extension_event_observer_->SetShouldDelaySuspend(wake_on_packet_enabled);
278 void WakeOnWifiManager::GetWifiDeviceProperties() {
279 const DeviceState* device =
280 NetworkHandler::Get()->network_state_handler()->GetDeviceStateByType(
281 NetworkTypePattern::WiFi());
282 if (!device)
283 return;
285 NetworkHandler::Get()->network_device_handler()->GetDeviceProperties(
286 device->path(),
287 base::Bind(&WakeOnWifiManager::GetDevicePropertiesCallback,
288 weak_ptr_factory_.GetWeakPtr()),
289 network_handler::ErrorCallback());
292 void WakeOnWifiManager::GetDevicePropertiesCallback(
293 const std::string& device_path,
294 const base::DictionaryValue& properties) {
295 std::string enabled;
296 if (!properties.HasKey(shill::kWakeOnWiFiFeaturesEnabledProperty) ||
297 !properties.GetString(shill::kWakeOnWiFiFeaturesEnabledProperty,
298 &enabled) ||
299 enabled == shill::kWakeOnWiFiFeaturesEnabledNotSupported) {
300 current_feature_ = NOT_SUPPORTED;
301 connection_observers_.clear();
302 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
303 FROM_HERE);
304 registrar_.RemoveAll();
305 extension_event_observer_.reset();
307 return;
310 if (wifi_properties_received_)
311 return;
313 wifi_properties_received_ = true;
315 if (current_feature_ != INVALID)
316 HandleWakeOnWifiFeatureUpdated();
318 NetworkHandler::Get()
319 ->network_device_handler()
320 ->RemoveAllWifiWakeOnPacketConnections(base::Bind(&base::DoNothing),
321 network_handler::ErrorCallback());
323 for (const auto& kv_pair : connection_observers_) {
324 WakeOnPacketConnectionObserver* observer = kv_pair.second;
325 observer->HandleWifiDevicePropertiesReady();
329 void WakeOnWifiManager::OnProfileAdded(Profile* profile) {
330 // add will do nothing if |profile| already exists in |connection_observers_|.
331 auto result = connection_observers_.add(
332 profile,
333 make_scoped_ptr(new WakeOnWifiManager::WakeOnPacketConnectionObserver(
334 profile, wifi_properties_received_)));
336 if (result.second) {
337 // This is a profile we haven't seen before.
338 gcm::GCMProfileServiceFactory::GetForProfile(profile)
339 ->driver()
340 ->WakeFromSuspendForHeartbeat(
341 IsWakeOnPacketEnabled(current_feature_));
345 void WakeOnWifiManager::OnProfileDestroyed(Profile* profile) {
346 connection_observers_.erase(profile);
349 } // namespace chromeos