Index: chrome/browser/chromeos/net/wake_on_wifi_manager.cc |
diff --git a/chrome/browser/chromeos/net/wake_on_wifi_manager.cc b/chrome/browser/chromeos/net/wake_on_wifi_manager.cc |
index 5584524f1aa66098c896412cf2315d3985cabf48..b43de4434f158ded0951e03df2805d47d01217f5 100644 |
--- a/chrome/browser/chromeos/net/wake_on_wifi_manager.cc |
+++ b/chrome/browser/chromeos/net/wake_on_wifi_manager.cc |
@@ -11,13 +11,16 @@ |
#include "base/logging.h" |
#include "base/macros.h" |
#include "base/memory/scoped_ptr.h" |
+#include "base/message_loop/message_loop_proxy.h" |
#include "base/sys_info.h" |
#include "base/values.h" |
#include "chrome/browser/chrome_notification_types.h" |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/browser/services/gcm/gcm_profile_service.h" |
#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" |
+#include "chrome/common/extensions/api/gcm.h" |
#include "chromeos/chromeos_switches.h" |
+#include "chromeos/dbus/dbus_thread_manager.h" |
#include "chromeos/login/login_state.h" |
#include "chromeos/network/device_state.h" |
#include "chromeos/network/network_device_handler.h" |
@@ -26,9 +29,17 @@ |
#include "chromeos/network/network_type_pattern.h" |
#include "components/gcm_driver/gcm_connection_observer.h" |
#include "components/gcm_driver/gcm_driver.h" |
+#include "content/public/browser/browser_context.h" |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/notification_service.h" |
#include "content/public/browser/notification_source.h" |
+#include "extensions/browser/extension_registry.h" |
+#include "extensions/browser/extension_system.h" |
+#include "extensions/common/extension.h" |
+#include "extensions/common/extension_set.h" |
+#include "extensions/common/one_shot_event.h" |
+#include "extensions/common/permissions/api_permission.h" |
+#include "extensions/common/permissions/permissions_data.h" |
#include "net/base/ip_endpoint.h" |
#include "third_party/cros_system_api/dbus/service_constants.h" |
@@ -141,7 +152,9 @@ WakeOnWifiManager* WakeOnWifiManager::Get() { |
WakeOnWifiManager::WakeOnWifiManager() |
: current_feature_(WakeOnWifiManager::INVALID), |
+ suspend_is_pending_(false), |
weak_ptr_factory_(this) { |
+ LOG(WARNING) << "CONSTRUCTOR"; |
// This class must be constructed before any users are logged in, i.e., before |
// any profiles are created or added to the ProfileManager. Additionally, |
// IsUserLoggedIn always returns true when we are not running on a Chrome OS |
@@ -168,6 +181,8 @@ WakeOnWifiManager::WakeOnWifiManager() |
if (!switches::WakeOnWifiEnabled()) |
return; |
+ LOG(WARNING) << "Adding WakeOnWifiManager as PowerManagerClient::Observer."; |
+ DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); |
const DeviceState* device = |
NetworkHandler::Get()->network_state_handler()->GetDeviceStateByType( |
@@ -186,6 +201,14 @@ WakeOnWifiManager::~WakeOnWifiManager() { |
DCHECK(g_wake_on_wifi_manager); |
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
g_wake_on_wifi_manager = NULL; |
+ |
+ for (const auto& kv_pair : connection_observers_) { |
+ Profile* profile = kv_pair.first; |
+ extensions::ExtensionRegistry::Get(profile)->RemoveObserver(this); |
+ } |
+ |
+ if (switches::WakeOnWifiEnabled()) |
+ DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); |
} |
void WakeOnWifiManager::OnPreferenceChanged( |
@@ -245,6 +268,7 @@ void WakeOnWifiManager::GetDevicePropertiesCallback( |
void WakeOnWifiManager::Observe(int type, |
const content::NotificationSource& source, |
const content::NotificationDetails& details) { |
+ using DispatchDetails = extensions::EventRouter::DispatchDetails; |
switch (type) { |
case chrome::NOTIFICATION_PROFILE_ADDED: { |
OnProfileAdded(content::Source<Profile>(source).ptr()); |
@@ -254,11 +278,47 @@ void WakeOnWifiManager::Observe(int type, |
OnProfileDestroyed(content::Source<Profile>(source).ptr()); |
break; |
} |
+ case extensions::NOTIFICATION_EXTENSION_MESSAGE_DISPATCHED: { |
+ OnExtensionMessageDispatched( |
+ content::Details<DispatchDetails>(details).ptr()); |
+ break; |
+ } |
+ case extensions::NOTIFICATION_EXTENSION_MESSAGE_ACKED: { |
+ OnExtensionMessageAcked(*(content::Details<int>(details).ptr())); |
+ break; |
+ } |
default: |
NOTREACHED(); |
} |
} |
+void WakeOnWifiManager::OnExtensionLoaded( |
+ content::BrowserContext* context, const extensions::Extension* extension) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ if (!extension->permissions_data()->HasAPIPermission( |
+ extensions::APIPermission::kGcm)) |
+ return; |
+ |
+ gcm_extensions_.insert(extension->id()); |
+} |
+ |
+void WakeOnWifiManager::SuspendImminent() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ OnSuspendImminent(false); |
+} |
+ |
+void WakeOnWifiManager::SuspendDone(const base::TimeDelta& duration) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ suspend_is_pending_ = false; |
+ power_manager_callback_.Reset(); |
+ suspend_readiness_callback_.Cancel(); |
+} |
+ |
+void WakeOnWifiManager::DarkSuspendImminent() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ OnSuspendImminent(true); |
+} |
+ |
void WakeOnWifiManager::OnProfileAdded(Profile* profile) { |
// add will do nothing if |profile| already exists in |connection_observers_|. |
auto result = connection_observers_.add( |
@@ -272,11 +332,99 @@ void WakeOnWifiManager::OnProfileAdded(Profile* profile) { |
->driver() |
->WakeFromSuspendForHeartbeat( |
IsWakeOnPacketEnabled(current_feature_)); |
+ |
+ // The ExtensionRegistry will call OnExtensionLoaded whenever the user |
+ // installs and enables a new extension. |
+ extensions::ExtensionRegistry::Get(profile)->AddObserver(this); |
+ |
+ // OnExtensionLoaded is not called for extensions that the user had already |
+ // installed and enabled. So we wait until the ExtensionSystem for the |
+ // profile is ready and then iterate through the installed extensions, |
+ // manually calling OnExtensionLoaded for each of them. |
+ extensions::ExtensionSystem::Get(profile)->ready().Post( |
+ FROM_HERE, |
+ base::Bind(&WakeOnWifiManager::OnExtensionSystemReady, |
+ weak_ptr_factory_.GetWeakPtr(), profile)); |
+ |
+ registrar_.Add(this, |
+ extensions::NOTIFICATION_EXTENSION_MESSAGE_DISPATCHED, |
+ content::Source<content::BrowserContext>(profile)); |
+ registrar_.Add(this, |
+ extensions::NOTIFICATION_EXTENSION_MESSAGE_ACKED, |
+ content::Source<content::BrowserContext>(profile)); |
} |
} |
void WakeOnWifiManager::OnProfileDestroyed(Profile* profile) { |
connection_observers_.erase(profile); |
+ |
+ extensions::ExtensionRegistry::Get(profile)->RemoveObserver(this); |
+ registrar_.Remove(this, |
+ extensions::NOTIFICATION_EXTENSION_MESSAGE_DISPATCHED, |
+ content::Source<content::BrowserContext>(profile)); |
+ registrar_.Remove(this, |
+ extensions::NOTIFICATION_EXTENSION_MESSAGE_ACKED, |
+ content::Source<content::BrowserContext>(profile)); |
+} |
+ |
+void WakeOnWifiManager::OnSuspendImminent(bool dark_suspend) { |
+ if (suspend_is_pending_) { |
+ LOG(WARNING) << "OnSuspendImminent called while previous suspend attempt " |
+ << "is still pending."; |
+ } |
+ |
+ suspend_is_pending_ = true; |
+ power_manager_callback_ = |
+ DBusThreadManager::Get() |
+ ->GetPowerManagerClient() |
+ ->GetSuspendReadinessCallback(); |
+ |
+ suspend_readiness_callback_.Reset( |
+ base::Bind(&WakeOnWifiManager::MaybeReportSuspendReadiness, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ |
+ base::MessageLoopProxy::current()->PostDelayedTask( |
+ FROM_HERE, |
+ suspend_readiness_callback_.callback(), |
+ dark_suspend ? base::TimeDelta::FromSeconds(1) : base::TimeDelta()); |
+} |
+ |
+void WakeOnWifiManager::MaybeReportSuspendReadiness() { |
+ LOG(WARNING) << "MaybeReportSuspendReadiness. keepalive count = " |
+ << unacked_extension_messages_.size(); |
+ if (!suspend_is_pending_ || unacked_extension_messages_.size() > 0 || |
+ power_manager_callback_.is_null()) |
+ return; |
+ |
+ suspend_is_pending_ = false; |
+ power_manager_callback_.Run(); |
+ power_manager_callback_.Reset(); |
+} |
+ |
+void WakeOnWifiManager::OnExtensionMessageDispatched( |
+ extensions::EventRouter::DispatchDetails* details) { |
+ if (details->event_name_ != extensions::api::gcm::OnMessage::kEventName) |
+ return; |
+ |
+ if (gcm_extensions_.find(details->extension_id_) == gcm_extensions_.end()) |
+ return; |
+ |
+ unacked_extension_messages_.insert(details->message_id_); |
+} |
+ |
+void WakeOnWifiManager::OnExtensionMessageAcked(int message_id) { |
+ if (unacked_extension_messages_.erase(message_id) > 0) |
+ MaybeReportSuspendReadiness(); |
+} |
+ |
+void WakeOnWifiManager::OnExtensionSystemReady(Profile* profile) { |
+ scoped_ptr<extensions::ExtensionSet> installed_set = |
+ extensions::ExtensionRegistry::Get(profile) |
+ ->GenerateInstalledExtensionsSet(); |
+ |
+ for (const auto& extension_refptr : *installed_set) { |
+ OnExtensionLoaded(profile, extension_refptr.get()); |
+ } |
} |
} // namespace chromeos |