Index: device/wake_lock/wake_lock_service_impl.cc |
diff --git a/device/wake_lock/wake_lock_service_impl.cc b/device/wake_lock/wake_lock_service_impl.cc |
index ae998aa62f4e27a29e65b60d5c0d3b5eb1c6c026..3b8a1a8515e2058e283b77cd3c4be92c1d1f72ce 100644 |
--- a/device/wake_lock/wake_lock_service_impl.cc |
+++ b/device/wake_lock/wake_lock_service_impl.cc |
@@ -6,31 +6,156 @@ |
#include <utility> |
+#include "base/atomic_sequence_num.h" |
+#include "base/memory/ptr_util.h" |
+#include "device/power_save_blocker/power_save_blocker.h" |
#include "device/wake_lock/wake_lock_service_context.h" |
namespace device { |
-WakeLockServiceImpl::WakeLockServiceImpl(WakeLockServiceContext* context) |
- : context_(context), wake_lock_request_outstanding_(false) {} |
+namespace { |
+ |
+base::StaticAtomicSequenceNumber g_unique_client_id; |
+ |
+} // namespace |
+ |
+WakeLockServiceImpl::WakeLockServiceImpl( |
+ WakeLockServiceContext* context, |
+ device::PowerSaveBlocker::PowerSaveBlockerType type, |
+ device::PowerSaveBlocker::Reason reason, |
+ const std::string& description, |
+ int context_id, |
+ WakeLockContextCallback native_view_getter, |
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner) |
+ : context_(context), |
+ type_(type), |
+ reason_(reason), |
+ description_(base::MakeUnique<std::string>(description)), |
+ num_lock_requests_(0), |
+#if defined(OS_ANDROID) |
+ context_id_(context_id), |
+ native_view_getter_(native_view_getter), |
+#endif |
+ main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
+ file_task_runner_(std::move(file_task_runner)), |
+ outstanding_(false) { |
+ frames_binding_set_.set_connection_error_handler(base::Bind( |
+ &WakeLockServiceImpl::OnConnectionError, base::Unretained(this))); |
+} |
WakeLockServiceImpl::~WakeLockServiceImpl() { |
- CancelWakeLock(); |
+ if (wake_lock_) { |
+ wake_lock_.reset(); |
+ DCHECK(context_); |
+ context_->DecreaseWakeLockCount(); |
+ } |
+} |
+ |
+void WakeLockServiceImpl::AddClient(mojom::WakeLockServiceRequest request) { |
+ // Multiple frames that associate to the same WebContents share the same one |
+ // WakeLockServiceImpl instance. Two consecutive |RequestWakeLock| requests |
+ // from the same frame should be coalesced as one request. Everytime a new |
+ // client is being added into the bindingSet, we create an unique client_id |
+ // as its context, this context is used as the key of the map |outstandings_| |
+ // which records the clients' last requested status. |
+ int client_id = g_unique_client_id.GetNext(); |
+ frames_binding_set_.AddBinding(this, std::move(request), client_id); |
+ outstandings_[client_id] = false; |
} |
void WakeLockServiceImpl::RequestWakeLock() { |
- if (wake_lock_request_outstanding_) |
- return; |
+ DCHECK(main_task_runner_->RunsTasksOnCurrentThread()); |
+ |
+ // |frames_binding_set_| empty means the requests are not from frames. |
+ if (frames_binding_set_.empty()) { |
+ if (outstanding_) { |
+ return; |
+ } |
+ outstanding_ = true; |
+ } else { |
+ // If the requests are from frames, we need the Context of bindingSet to |
+ // differenciate which binding is from which frame. |
+ int client_id = frames_binding_set_.dispatch_context(); |
+ if (outstandings_[client_id]) { |
+ return; |
+ } |
+ outstandings_[client_id] = true; |
+ } |
- wake_lock_request_outstanding_ = true; |
- context_->RequestWakeLock(); |
+ num_lock_requests_++; |
+ UpdateWakeLock(); |
} |
void WakeLockServiceImpl::CancelWakeLock() { |
- if (!wake_lock_request_outstanding_) |
- return; |
+ DCHECK(main_task_runner_->RunsTasksOnCurrentThread()); |
+ |
+ if (frames_binding_set_.empty()) { |
+ if (!outstanding_) { |
+ return; |
+ } |
+ outstanding_ = false; |
+ } else { |
+ int client_id = frames_binding_set_.dispatch_context(); |
+ if (!outstandings_[client_id]) { |
+ return; |
+ } |
+ outstandings_[client_id] = false; |
+ if (num_lock_requests_ == 0) { |
+ return; |
+ } |
+ } |
+ |
+ num_lock_requests_--; |
+ UpdateWakeLock(); |
+} |
+ |
+void WakeLockServiceImpl::UpdateWakeLock() { |
+ DCHECK(num_lock_requests_ >= 0); |
+ if (num_lock_requests_) { |
+ if (!wake_lock_) |
+ CreateWakeLock(); |
+ } else { |
+ if (wake_lock_) |
+ RemoveWakeLock(); |
+ } |
+} |
+ |
+void WakeLockServiceImpl::CreateWakeLock() { |
+ DCHECK(!wake_lock_); |
+ wake_lock_ = base::MakeUnique<device::PowerSaveBlocker>( |
+ type_, reason_, *description_, main_task_runner_, file_task_runner_); |
+ DCHECK(context_); |
+ context_->IncreaseWakeLockCount(); |
+ |
+#if defined(OS_ANDROID) |
+ gfx::NativeView native_view = native_view_getter_.Run(context_id_); |
+ if (native_view) { |
+ wake_lock_.get()->InitDisplaySleepBlocker(native_view); |
+ } |
+#endif |
+} |
+ |
+void WakeLockServiceImpl::RemoveWakeLock() { |
+ DCHECK(wake_lock_); |
+ wake_lock_.reset(); |
+ DCHECK(context_); |
+ context_->DecreaseWakeLockCount(); |
+} |
+ |
+void WakeLockServiceImpl::OnConnectionError() { |
+ int client_id = frames_binding_set_.dispatch_context(); |
+ // If the client's wakelock outstanding status is True before it crashes, we |
+ // should decrease the num_lock_requests and call UpdateWakeLock(). |
+ if (outstandings_[client_id]) { |
+ if (num_lock_requests_ == 0) { |
+ return; |
+ } |
+ num_lock_requests_--; |
+ UpdateWakeLock(); |
+ } |
- wake_lock_request_outstanding_ = false; |
- context_->CancelWakeLock(); |
+ // Remove the entry of client_id from map. |
+ outstandings_.erase(client_id); |
} |
} // namespace device |