Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / chromeos / power / extension_event_observer.cc
blobf5e3960608957b3de7df27b9936b37b0d7f2aa48
1 // Copyright 2015 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/power/extension_event_observer.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/common/extensions/api/gcm.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "content/public/browser/notification_service.h"
15 #include "extensions/browser/extension_host.h"
16 #include "extensions/browser/process_manager.h"
17 #include "extensions/common/extension.h"
18 #include "extensions/common/manifest_handlers/background_info.h"
19 #include "extensions/common/permissions/api_permission.h"
20 #include "extensions/common/permissions/permissions_data.h"
22 namespace chromeos {
24 namespace {
25 // The number of milliseconds that we should wait after receiving a
26 // DarkSuspendImminent signal before attempting to report readiness to suspend.
27 const int kDarkSuspendDelayMs = 1000;
30 ExtensionEventObserver::TestApi::TestApi(
31 base::WeakPtr<ExtensionEventObserver> parent)
32 : parent_(parent) {
35 ExtensionEventObserver::TestApi::~TestApi() {
38 bool ExtensionEventObserver::TestApi::MaybeRunSuspendReadinessCallback() {
39 if (!parent_ || parent_->suspend_readiness_callback_.callback().is_null())
40 return false;
42 parent_->suspend_readiness_callback_.callback().Run();
43 parent_->suspend_readiness_callback_.Cancel();
44 return true;
47 bool ExtensionEventObserver::TestApi::WillDelaySuspendForExtensionHost(
48 extensions::ExtensionHost* host) {
49 if (!parent_)
50 return false;
52 return parent_->keepalive_sources_.contains(host);
55 struct ExtensionEventObserver::KeepaliveSources {
56 std::set<int> unacked_push_messages;
57 std::set<uint64> pending_network_requests;
60 ExtensionEventObserver::ExtensionEventObserver()
61 : should_delay_suspend_(true),
62 suspend_is_pending_(false),
63 suspend_keepalive_count_(0),
64 weak_factory_(this) {
65 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED,
66 content::NotificationService::AllBrowserContextsAndSources());
67 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
68 content::NotificationService::AllBrowserContextsAndSources());
70 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
73 ExtensionEventObserver::~ExtensionEventObserver() {
74 for (Profile* profile : active_profiles_)
75 extensions::ProcessManager::Get(profile)->RemoveObserver(this);
77 for (const auto& pair : keepalive_sources_) {
78 extensions::ExtensionHost* host =
79 const_cast<extensions::ExtensionHost*>(pair.first);
80 host->RemoveObserver(this);
83 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
86 scoped_ptr<ExtensionEventObserver::TestApi>
87 ExtensionEventObserver::CreateTestApi() {
88 return make_scoped_ptr(
89 new ExtensionEventObserver::TestApi(weak_factory_.GetWeakPtr()));
92 void ExtensionEventObserver::SetShouldDelaySuspend(bool should_delay) {
93 should_delay_suspend_ = should_delay;
94 if (!should_delay_suspend_ && suspend_is_pending_) {
95 // There is a suspend attempt pending but this class should no longer be
96 // delaying it. Immediately report readiness.
97 suspend_is_pending_ = false;
98 power_manager_callback_.Run();
99 power_manager_callback_.Reset();
100 suspend_readiness_callback_.Cancel();
104 void ExtensionEventObserver::Observe(
105 int type,
106 const content::NotificationSource& source,
107 const content::NotificationDetails& details) {
108 switch (type) {
109 case chrome::NOTIFICATION_PROFILE_ADDED: {
110 OnProfileAdded(content::Source<Profile>(source).ptr());
111 break;
113 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
114 OnProfileDestroyed(content::Source<Profile>(source).ptr());
115 break;
117 default:
118 NOTREACHED();
122 void ExtensionEventObserver::OnBackgroundHostCreated(
123 extensions::ExtensionHost* host) {
124 // We only care about ExtensionHosts for extensions that use GCM and have a
125 // lazy background page.
126 if (!host->extension()->permissions_data()->HasAPIPermission(
127 extensions::APIPermission::kGcm) ||
128 !extensions::BackgroundInfo::HasLazyBackgroundPage(host->extension()))
129 return;
131 auto result =
132 keepalive_sources_.add(host, make_scoped_ptr(new KeepaliveSources()));
134 if (result.second)
135 host->AddObserver(this);
138 void ExtensionEventObserver::OnExtensionHostDestroyed(
139 const extensions::ExtensionHost* host) {
140 DCHECK(keepalive_sources_.contains(host));
142 scoped_ptr<KeepaliveSources> sources =
143 keepalive_sources_.take_and_erase(host);
145 suspend_keepalive_count_ -= sources->unacked_push_messages.size();
146 suspend_keepalive_count_ -= sources->pending_network_requests.size();
147 MaybeReportSuspendReadiness();
150 void ExtensionEventObserver::OnBackgroundEventDispatched(
151 const extensions::ExtensionHost* host,
152 const std::string& event_name,
153 int event_id) {
154 DCHECK(keepalive_sources_.contains(host));
156 if (event_name != extensions::api::gcm::OnMessage::kEventName)
157 return;
159 keepalive_sources_.get(host)->unacked_push_messages.insert(event_id);
160 ++suspend_keepalive_count_;
163 void ExtensionEventObserver::OnBackgroundEventAcked(
164 const extensions::ExtensionHost* host,
165 int event_id) {
166 DCHECK(keepalive_sources_.contains(host));
168 if (keepalive_sources_.get(host)->unacked_push_messages.erase(event_id) > 0) {
169 --suspend_keepalive_count_;
170 MaybeReportSuspendReadiness();
174 void ExtensionEventObserver::OnNetworkRequestStarted(
175 const extensions::ExtensionHost* host,
176 uint64 request_id) {
177 DCHECK(keepalive_sources_.contains(host));
179 KeepaliveSources* sources = keepalive_sources_.get(host);
181 // We only care about network requests that were started while a push message
182 // is pending. This is an indication that the network request is related to
183 // the push message.
184 if (sources->unacked_push_messages.empty())
185 return;
187 sources->pending_network_requests.insert(request_id);
188 ++suspend_keepalive_count_;
191 void ExtensionEventObserver::OnNetworkRequestDone(
192 const extensions::ExtensionHost* host,
193 uint64 request_id) {
194 DCHECK(keepalive_sources_.contains(host));
196 if (keepalive_sources_.get(host)->pending_network_requests.erase(request_id) >
197 0) {
198 --suspend_keepalive_count_;
199 MaybeReportSuspendReadiness();
203 void ExtensionEventObserver::SuspendImminent() {
204 if (should_delay_suspend_)
205 OnSuspendImminent(false);
208 void ExtensionEventObserver::DarkSuspendImminent() {
209 if (should_delay_suspend_)
210 OnSuspendImminent(true);
213 void ExtensionEventObserver::SuspendDone(const base::TimeDelta& duration) {
214 suspend_is_pending_ = false;
215 power_manager_callback_.Reset();
216 suspend_readiness_callback_.Cancel();
219 void ExtensionEventObserver::OnProfileAdded(Profile* profile) {
220 auto result = active_profiles_.insert(profile);
222 if (result.second)
223 extensions::ProcessManager::Get(profile)->AddObserver(this);
226 void ExtensionEventObserver::OnProfileDestroyed(Profile* profile) {
227 if (active_profiles_.erase(profile) == 0)
228 return;
230 extensions::ProcessManager::Get(profile)->RemoveObserver(this);
233 void ExtensionEventObserver::OnSuspendImminent(bool dark_suspend) {
234 if (suspend_is_pending_) {
235 LOG(WARNING) << "OnSuspendImminent called while previous suspend attempt "
236 << "is still pending.";
239 suspend_is_pending_ = true;
240 power_manager_callback_ = DBusThreadManager::Get()
241 ->GetPowerManagerClient()
242 ->GetSuspendReadinessCallback();
244 suspend_readiness_callback_.Reset(
245 base::Bind(&ExtensionEventObserver::MaybeReportSuspendReadiness,
246 weak_factory_.GetWeakPtr()));
248 // Unfortunately, there is a race between the arrival of the
249 // DarkSuspendImminent signal and OnBackgroundEventDispatched. As a result,
250 // there is no way to tell from within this method if a push message is about
251 // to arrive. To try and deal with this, we wait one second before attempting
252 // to report suspend readiness. If there is a push message pending, we should
253 // receive it within that time and increment |suspend_keepalive_count_| to
254 // prevent this callback from reporting ready.
255 base::MessageLoopProxy::current()->PostDelayedTask(
256 FROM_HERE, suspend_readiness_callback_.callback(),
257 dark_suspend ? base::TimeDelta::FromMilliseconds(kDarkSuspendDelayMs)
258 : base::TimeDelta());
261 void ExtensionEventObserver::MaybeReportSuspendReadiness() {
262 if (!suspend_is_pending_ || suspend_keepalive_count_ > 0 ||
263 power_manager_callback_.is_null())
264 return;
266 suspend_is_pending_ = false;
267 power_manager_callback_.Run();
268 power_manager_callback_.Reset();
271 } // namespace chromeos