OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/net/wake_on_wifi_manager.h" | 5 #include "chrome/browser/chromeos/net/wake_on_wifi_manager.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/containers/scoped_ptr_hash_map.h" | 10 #include "base/containers/scoped_ptr_hash_map.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/macros.h" | 12 #include "base/macros.h" |
13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
| 14 #include "base/message_loop/message_loop_proxy.h" |
14 #include "base/sys_info.h" | 15 #include "base/sys_info.h" |
15 #include "base/values.h" | 16 #include "base/values.h" |
16 #include "chrome/browser/chrome_notification_types.h" | 17 #include "chrome/browser/chrome_notification_types.h" |
17 #include "chrome/browser/profiles/profile.h" | 18 #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.h" |
19 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" | 20 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" |
| 21 #include "chrome/common/extensions/api/gcm.h" |
20 #include "chromeos/chromeos_switches.h" | 22 #include "chromeos/chromeos_switches.h" |
| 23 #include "chromeos/dbus/dbus_thread_manager.h" |
21 #include "chromeos/login/login_state.h" | 24 #include "chromeos/login/login_state.h" |
22 #include "chromeos/network/device_state.h" | 25 #include "chromeos/network/device_state.h" |
23 #include "chromeos/network/network_device_handler.h" | 26 #include "chromeos/network/network_device_handler.h" |
24 #include "chromeos/network/network_handler.h" | 27 #include "chromeos/network/network_handler.h" |
25 #include "chromeos/network/network_state_handler.h" | 28 #include "chromeos/network/network_state_handler.h" |
26 #include "chromeos/network/network_type_pattern.h" | 29 #include "chromeos/network/network_type_pattern.h" |
27 #include "components/gcm_driver/gcm_connection_observer.h" | 30 #include "components/gcm_driver/gcm_connection_observer.h" |
28 #include "components/gcm_driver/gcm_driver.h" | 31 #include "components/gcm_driver/gcm_driver.h" |
| 32 #include "content/public/browser/browser_context.h" |
29 #include "content/public/browser/browser_thread.h" | 33 #include "content/public/browser/browser_thread.h" |
30 #include "content/public/browser/notification_service.h" | 34 #include "content/public/browser/notification_service.h" |
31 #include "content/public/browser/notification_source.h" | 35 #include "content/public/browser/notification_source.h" |
| 36 #include "extensions/browser/extension_registry.h" |
| 37 #include "extensions/browser/extension_system.h" |
| 38 #include "extensions/common/extension.h" |
| 39 #include "extensions/common/extension_set.h" |
| 40 #include "extensions/common/one_shot_event.h" |
| 41 #include "extensions/common/permissions/api_permission.h" |
| 42 #include "extensions/common/permissions/permissions_data.h" |
32 #include "net/base/ip_endpoint.h" | 43 #include "net/base/ip_endpoint.h" |
33 #include "third_party/cros_system_api/dbus/service_constants.h" | 44 #include "third_party/cros_system_api/dbus/service_constants.h" |
34 | 45 |
35 namespace chromeos { | 46 namespace chromeos { |
36 | 47 |
37 namespace { | 48 namespace { |
38 | 49 |
39 const char kWakeOnNone[] = "none"; | 50 const char kWakeOnNone[] = "none"; |
40 const char kWakeOnPacket[] = "packet"; | 51 const char kWakeOnPacket[] = "packet"; |
41 const char kWakeOnSsid[] = "ssid"; | 52 const char kWakeOnSsid[] = "ssid"; |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 | 145 |
135 // static | 146 // static |
136 WakeOnWifiManager* WakeOnWifiManager::Get() { | 147 WakeOnWifiManager* WakeOnWifiManager::Get() { |
137 DCHECK(g_wake_on_wifi_manager); | 148 DCHECK(g_wake_on_wifi_manager); |
138 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 149 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
139 return g_wake_on_wifi_manager; | 150 return g_wake_on_wifi_manager; |
140 } | 151 } |
141 | 152 |
142 WakeOnWifiManager::WakeOnWifiManager() | 153 WakeOnWifiManager::WakeOnWifiManager() |
143 : current_feature_(WakeOnWifiManager::INVALID), | 154 : current_feature_(WakeOnWifiManager::INVALID), |
| 155 suspend_is_pending_(false), |
144 weak_ptr_factory_(this) { | 156 weak_ptr_factory_(this) { |
| 157 LOG(WARNING) << "CONSTRUCTOR"; |
145 // This class must be constructed before any users are logged in, i.e., before | 158 // This class must be constructed before any users are logged in, i.e., before |
146 // any profiles are created or added to the ProfileManager. Additionally, | 159 // any profiles are created or added to the ProfileManager. Additionally, |
147 // IsUserLoggedIn always returns true when we are not running on a Chrome OS | 160 // IsUserLoggedIn always returns true when we are not running on a Chrome OS |
148 // device so this check should only run on real devices. | 161 // device so this check should only run on real devices. |
149 CHECK(!base::SysInfo::IsRunningOnChromeOS() || | 162 CHECK(!base::SysInfo::IsRunningOnChromeOS() || |
150 !LoginState::Get()->IsUserLoggedIn()); | 163 !LoginState::Get()->IsUserLoggedIn()); |
151 DCHECK(!g_wake_on_wifi_manager); | 164 DCHECK(!g_wake_on_wifi_manager); |
152 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 165 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
153 | 166 |
154 g_wake_on_wifi_manager = this; | 167 g_wake_on_wifi_manager = this; |
155 | 168 |
156 registrar_.Add(this, | 169 registrar_.Add(this, |
157 chrome::NOTIFICATION_PROFILE_ADDED, | 170 chrome::NOTIFICATION_PROFILE_ADDED, |
158 content::NotificationService::AllBrowserContextsAndSources()); | 171 content::NotificationService::AllBrowserContextsAndSources()); |
159 registrar_.Add(this, | 172 registrar_.Add(this, |
160 chrome::NOTIFICATION_PROFILE_DESTROYED, | 173 chrome::NOTIFICATION_PROFILE_DESTROYED, |
161 content::NotificationService::AllBrowserContextsAndSources()); | 174 content::NotificationService::AllBrowserContextsAndSources()); |
162 | 175 |
163 NetworkHandler::Get() | 176 NetworkHandler::Get() |
164 ->network_device_handler() | 177 ->network_device_handler() |
165 ->RemoveAllWifiWakeOnPacketConnections( | 178 ->RemoveAllWifiWakeOnPacketConnections( |
166 base::Bind(&base::DoNothing), | 179 base::Bind(&base::DoNothing), |
167 network_handler::ErrorCallback()); | 180 network_handler::ErrorCallback()); |
168 | 181 |
169 if (!switches::WakeOnWifiEnabled()) | 182 if (!switches::WakeOnWifiEnabled()) |
170 return; | 183 return; |
| 184 LOG(WARNING) << "Adding WakeOnWifiManager as PowerManagerClient::Observer."; |
| 185 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); |
171 | 186 |
172 const DeviceState* device = | 187 const DeviceState* device = |
173 NetworkHandler::Get()->network_state_handler()->GetDeviceStateByType( | 188 NetworkHandler::Get()->network_state_handler()->GetDeviceStateByType( |
174 NetworkTypePattern::WiFi()); | 189 NetworkTypePattern::WiFi()); |
175 if (!device) | 190 if (!device) |
176 return; | 191 return; |
177 // Get device properties to check whether wake-on-wifi is supported. | 192 // Get device properties to check whether wake-on-wifi is supported. |
178 NetworkHandler::Get()->network_device_handler()->GetDeviceProperties( | 193 NetworkHandler::Get()->network_device_handler()->GetDeviceProperties( |
179 device->path(), | 194 device->path(), |
180 base::Bind(&WakeOnWifiManager::GetDevicePropertiesCallback, | 195 base::Bind(&WakeOnWifiManager::GetDevicePropertiesCallback, |
181 weak_ptr_factory_.GetWeakPtr()), | 196 weak_ptr_factory_.GetWeakPtr()), |
182 network_handler::ErrorCallback()); | 197 network_handler::ErrorCallback()); |
183 } | 198 } |
184 | 199 |
185 WakeOnWifiManager::~WakeOnWifiManager() { | 200 WakeOnWifiManager::~WakeOnWifiManager() { |
186 DCHECK(g_wake_on_wifi_manager); | 201 DCHECK(g_wake_on_wifi_manager); |
187 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 202 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
188 g_wake_on_wifi_manager = NULL; | 203 g_wake_on_wifi_manager = NULL; |
| 204 |
| 205 for (const auto& kv_pair : connection_observers_) { |
| 206 Profile* profile = kv_pair.first; |
| 207 extensions::ExtensionRegistry::Get(profile)->RemoveObserver(this); |
| 208 } |
| 209 |
| 210 if (switches::WakeOnWifiEnabled()) |
| 211 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); |
189 } | 212 } |
190 | 213 |
191 void WakeOnWifiManager::OnPreferenceChanged( | 214 void WakeOnWifiManager::OnPreferenceChanged( |
192 WakeOnWifiManager::WakeOnWifiFeature feature) { | 215 WakeOnWifiManager::WakeOnWifiFeature feature) { |
193 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 216 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
194 if (current_feature_ == NOT_SUPPORTED) | 217 if (current_feature_ == NOT_SUPPORTED) |
195 return; | 218 return; |
196 if (!switches::WakeOnWifiEnabled()) | 219 if (!switches::WakeOnWifiEnabled()) |
197 feature = WAKE_ON_NONE; | 220 feature = WAKE_ON_NONE; |
198 if (feature == current_feature_) | 221 if (feature == current_feature_) |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 if (properties.GetString(shill::kWakeOnWiFiFeaturesEnabledProperty, | 261 if (properties.GetString(shill::kWakeOnWiFiFeaturesEnabledProperty, |
239 &enabled) && | 262 &enabled) && |
240 enabled == shill::kWakeOnWiFiFeaturesEnabledNotSupported) { | 263 enabled == shill::kWakeOnWiFiFeaturesEnabledNotSupported) { |
241 current_feature_ = NOT_SUPPORTED; | 264 current_feature_ = NOT_SUPPORTED; |
242 } | 265 } |
243 } | 266 } |
244 | 267 |
245 void WakeOnWifiManager::Observe(int type, | 268 void WakeOnWifiManager::Observe(int type, |
246 const content::NotificationSource& source, | 269 const content::NotificationSource& source, |
247 const content::NotificationDetails& details) { | 270 const content::NotificationDetails& details) { |
| 271 using DispatchDetails = extensions::EventRouter::DispatchDetails; |
248 switch (type) { | 272 switch (type) { |
249 case chrome::NOTIFICATION_PROFILE_ADDED: { | 273 case chrome::NOTIFICATION_PROFILE_ADDED: { |
250 OnProfileAdded(content::Source<Profile>(source).ptr()); | 274 OnProfileAdded(content::Source<Profile>(source).ptr()); |
251 break; | 275 break; |
252 } | 276 } |
253 case chrome::NOTIFICATION_PROFILE_DESTROYED: { | 277 case chrome::NOTIFICATION_PROFILE_DESTROYED: { |
254 OnProfileDestroyed(content::Source<Profile>(source).ptr()); | 278 OnProfileDestroyed(content::Source<Profile>(source).ptr()); |
255 break; | 279 break; |
256 } | 280 } |
| 281 case extensions::NOTIFICATION_EXTENSION_MESSAGE_DISPATCHED: { |
| 282 OnExtensionMessageDispatched( |
| 283 content::Details<DispatchDetails>(details).ptr()); |
| 284 break; |
| 285 } |
| 286 case extensions::NOTIFICATION_EXTENSION_MESSAGE_ACKED: { |
| 287 OnExtensionMessageAcked(*(content::Details<int>(details).ptr())); |
| 288 break; |
| 289 } |
257 default: | 290 default: |
258 NOTREACHED(); | 291 NOTREACHED(); |
259 } | 292 } |
260 } | 293 } |
261 | 294 |
| 295 void WakeOnWifiManager::OnExtensionLoaded( |
| 296 content::BrowserContext* context, const extensions::Extension* extension) { |
| 297 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 298 if (!extension->permissions_data()->HasAPIPermission( |
| 299 extensions::APIPermission::kGcm)) |
| 300 return; |
| 301 |
| 302 gcm_extensions_.insert(extension->id()); |
| 303 } |
| 304 |
| 305 void WakeOnWifiManager::SuspendImminent() { |
| 306 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 307 OnSuspendImminent(false); |
| 308 } |
| 309 |
| 310 void WakeOnWifiManager::SuspendDone(const base::TimeDelta& duration) { |
| 311 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 312 suspend_is_pending_ = false; |
| 313 power_manager_callback_.Reset(); |
| 314 suspend_readiness_callback_.Cancel(); |
| 315 } |
| 316 |
| 317 void WakeOnWifiManager::DarkSuspendImminent() { |
| 318 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 319 OnSuspendImminent(true); |
| 320 } |
| 321 |
262 void WakeOnWifiManager::OnProfileAdded(Profile* profile) { | 322 void WakeOnWifiManager::OnProfileAdded(Profile* profile) { |
263 // add will do nothing if |profile| already exists in |connection_observers_|. | 323 // add will do nothing if |profile| already exists in |connection_observers_|. |
264 auto result = connection_observers_.add( | 324 auto result = connection_observers_.add( |
265 profile, | 325 profile, |
266 make_scoped_ptr( | 326 make_scoped_ptr( |
267 new WakeOnWifiManager::WakeOnPacketConnectionObserver(profile))); | 327 new WakeOnWifiManager::WakeOnPacketConnectionObserver(profile))); |
268 | 328 |
269 if (result.second) { | 329 if (result.second) { |
270 // This is a profile we haven't seen before. | 330 // This is a profile we haven't seen before. |
271 gcm::GCMProfileServiceFactory::GetForProfile(profile) | 331 gcm::GCMProfileServiceFactory::GetForProfile(profile) |
272 ->driver() | 332 ->driver() |
273 ->WakeFromSuspendForHeartbeat( | 333 ->WakeFromSuspendForHeartbeat( |
274 IsWakeOnPacketEnabled(current_feature_)); | 334 IsWakeOnPacketEnabled(current_feature_)); |
| 335 |
| 336 // The ExtensionRegistry will call OnExtensionLoaded whenever the user |
| 337 // installs and enables a new extension. |
| 338 extensions::ExtensionRegistry::Get(profile)->AddObserver(this); |
| 339 |
| 340 // OnExtensionLoaded is not called for extensions that the user had already |
| 341 // installed and enabled. So we wait until the ExtensionSystem for the |
| 342 // profile is ready and then iterate through the installed extensions, |
| 343 // manually calling OnExtensionLoaded for each of them. |
| 344 extensions::ExtensionSystem::Get(profile)->ready().Post( |
| 345 FROM_HERE, |
| 346 base::Bind(&WakeOnWifiManager::OnExtensionSystemReady, |
| 347 weak_ptr_factory_.GetWeakPtr(), profile)); |
| 348 |
| 349 registrar_.Add(this, |
| 350 extensions::NOTIFICATION_EXTENSION_MESSAGE_DISPATCHED, |
| 351 content::Source<content::BrowserContext>(profile)); |
| 352 registrar_.Add(this, |
| 353 extensions::NOTIFICATION_EXTENSION_MESSAGE_ACKED, |
| 354 content::Source<content::BrowserContext>(profile)); |
275 } | 355 } |
276 } | 356 } |
277 | 357 |
278 void WakeOnWifiManager::OnProfileDestroyed(Profile* profile) { | 358 void WakeOnWifiManager::OnProfileDestroyed(Profile* profile) { |
279 connection_observers_.erase(profile); | 359 connection_observers_.erase(profile); |
| 360 |
| 361 extensions::ExtensionRegistry::Get(profile)->RemoveObserver(this); |
| 362 registrar_.Remove(this, |
| 363 extensions::NOTIFICATION_EXTENSION_MESSAGE_DISPATCHED, |
| 364 content::Source<content::BrowserContext>(profile)); |
| 365 registrar_.Remove(this, |
| 366 extensions::NOTIFICATION_EXTENSION_MESSAGE_ACKED, |
| 367 content::Source<content::BrowserContext>(profile)); |
| 368 } |
| 369 |
| 370 void WakeOnWifiManager::OnSuspendImminent(bool dark_suspend) { |
| 371 if (suspend_is_pending_) { |
| 372 LOG(WARNING) << "OnSuspendImminent called while previous suspend attempt " |
| 373 << "is still pending."; |
| 374 } |
| 375 |
| 376 suspend_is_pending_ = true; |
| 377 power_manager_callback_ = |
| 378 DBusThreadManager::Get() |
| 379 ->GetPowerManagerClient() |
| 380 ->GetSuspendReadinessCallback(); |
| 381 |
| 382 suspend_readiness_callback_.Reset( |
| 383 base::Bind(&WakeOnWifiManager::MaybeReportSuspendReadiness, |
| 384 weak_ptr_factory_.GetWeakPtr())); |
| 385 |
| 386 base::MessageLoopProxy::current()->PostDelayedTask( |
| 387 FROM_HERE, |
| 388 suspend_readiness_callback_.callback(), |
| 389 dark_suspend ? base::TimeDelta::FromSeconds(1) : base::TimeDelta()); |
| 390 } |
| 391 |
| 392 void WakeOnWifiManager::MaybeReportSuspendReadiness() { |
| 393 LOG(WARNING) << "MaybeReportSuspendReadiness. keepalive count = " |
| 394 << unacked_extension_messages_.size(); |
| 395 if (!suspend_is_pending_ || unacked_extension_messages_.size() > 0 || |
| 396 power_manager_callback_.is_null()) |
| 397 return; |
| 398 |
| 399 suspend_is_pending_ = false; |
| 400 power_manager_callback_.Run(); |
| 401 power_manager_callback_.Reset(); |
| 402 } |
| 403 |
| 404 void WakeOnWifiManager::OnExtensionMessageDispatched( |
| 405 extensions::EventRouter::DispatchDetails* details) { |
| 406 if (details->event_name_ != extensions::api::gcm::OnMessage::kEventName) |
| 407 return; |
| 408 |
| 409 if (gcm_extensions_.find(details->extension_id_) == gcm_extensions_.end()) |
| 410 return; |
| 411 |
| 412 unacked_extension_messages_.insert(details->message_id_); |
| 413 } |
| 414 |
| 415 void WakeOnWifiManager::OnExtensionMessageAcked(int message_id) { |
| 416 if (unacked_extension_messages_.erase(message_id) > 0) |
| 417 MaybeReportSuspendReadiness(); |
| 418 } |
| 419 |
| 420 void WakeOnWifiManager::OnExtensionSystemReady(Profile* profile) { |
| 421 scoped_ptr<extensions::ExtensionSet> installed_set = |
| 422 extensions::ExtensionRegistry::Get(profile) |
| 423 ->GenerateInstalledExtensionsSet(); |
| 424 |
| 425 for (const auto& extension_refptr : *installed_set) { |
| 426 OnExtensionLoaded(profile, extension_refptr.get()); |
| 427 } |
280 } | 428 } |
281 | 429 |
282 } // namespace chromeos | 430 } // namespace chromeos |
OLD | NEW |