1 // Copyright 2017 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.
4 
5 #include "services/device/wake_lock/wake_lock_provider.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "mojo/public/cpp/bindings/remote_set.h"
12 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
13 #include "services/device/wake_lock/wake_lock.h"
14 
15 namespace device {
16 
17 // Holds the state associated with wake locks of a single type across the
18 // system i.e. if 3 |kAppSuspension| wake locks are currently held the |count|
19 // would be 3.
20 struct WakeLockProvider::WakeLockDataPerType {
21   WakeLockDataPerType() = default;
22   ~WakeLockDataPerType() = default;
23 
24   // Currently activated wake locks of this wake lock type.
25   int64_t count = 0;
26 
27   // Map of all wake locks of this type created by this provider. An entry is
28   // removed from this map when an |OnConnectionError| is received.
29   std::map<WakeLock*, std::unique_ptr<WakeLock>> wake_locks;
30 
31   // Observers for this wake lock type.
32   mojo::RemoteSet<mojom::WakeLockObserver> observers;
33 
34   DISALLOW_COPY_AND_ASSIGN(WakeLockDataPerType);
35 };
36 
WakeLockProvider(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,const WakeLockContextCallback & native_view_getter)37 WakeLockProvider::WakeLockProvider(
38     scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
39     const WakeLockContextCallback& native_view_getter)
40     : file_task_runner_(std::move(file_task_runner)),
41       native_view_getter_(native_view_getter) {
42   // Populates |wake_lock_store_| with entries for all types of wake locks.
43   wake_lock_store_[mojom::WakeLockType::kPreventAppSuspension] =
44       std::make_unique<WakeLockDataPerType>();
45   wake_lock_store_[mojom::WakeLockType::kPreventDisplaySleep] =
46       std::make_unique<WakeLockDataPerType>();
47   wake_lock_store_[mojom::WakeLockType::kPreventDisplaySleepAllowDimming] =
48       std::make_unique<WakeLockDataPerType>();
49 }
50 
51 WakeLockProvider::~WakeLockProvider() = default;
52 
AddBinding(mojo::PendingReceiver<mojom::WakeLockProvider> receiver)53 void WakeLockProvider::AddBinding(
54     mojo::PendingReceiver<mojom::WakeLockProvider> receiver) {
55   receivers_.Add(this, std::move(receiver));
56 }
57 
GetWakeLockContextForID(int context_id,mojo::PendingReceiver<mojom::WakeLockContext> receiver)58 void WakeLockProvider::GetWakeLockContextForID(
59     int context_id,
60     mojo::PendingReceiver<mojom::WakeLockContext> receiver) {
61   DCHECK_GE(context_id, 0);
62   mojo::MakeSelfOwnedReceiver(
63       std::make_unique<WakeLockContext>(context_id, file_task_runner_,
64                                         native_view_getter_),
65       std::move(receiver));
66 }
67 
GetWakeLockWithoutContext(mojom::WakeLockType type,mojom::WakeLockReason reason,const std::string & description,mojo::PendingReceiver<mojom::WakeLock> receiver)68 void WakeLockProvider::GetWakeLockWithoutContext(
69     mojom::WakeLockType type,
70     mojom::WakeLockReason reason,
71     const std::string& description,
72     mojo::PendingReceiver<mojom::WakeLock> receiver) {
73   std::unique_ptr<WakeLock> wake_lock =
74       std::make_unique<WakeLock>(std::move(receiver), type, reason, description,
75                                  WakeLockContext::WakeLockInvalidContextId,
76                                  native_view_getter_, file_task_runner_, this);
77   GetWakeLockDataPerType(type).wake_locks[wake_lock.get()] =
78       std::move(wake_lock);
79 }
80 
NotifyOnWakeLockDeactivation(mojom::WakeLockType type,mojo::PendingRemote<mojom::WakeLockObserver> pending_observer)81 void WakeLockProvider::NotifyOnWakeLockDeactivation(
82     mojom::WakeLockType type,
83     mojo::PendingRemote<mojom::WakeLockObserver> pending_observer) {
84   mojo::Remote<mojom::WakeLockObserver> observer(std::move(pending_observer));
85   // If |type| is not held then notify the observer immediately. Add it to the
86   // observer list for future deactivation notifications.
87   if (GetWakeLockDataPerType(type).count == 0) {
88     observer->OnWakeLockDeactivated(type);
89   }
90   GetWakeLockDataPerType(type).observers.Add(std::move(observer));
91 }
92 
GetActiveWakeLocksForTests(mojom::WakeLockType type,GetActiveWakeLocksForTestsCallback callback)93 void WakeLockProvider::GetActiveWakeLocksForTests(
94     mojom::WakeLockType type,
95     GetActiveWakeLocksForTestsCallback callback) {
96   std::move(callback).Run(GetWakeLockDataPerType(type).count);
97 }
98 
OnWakeLockActivated(mojom::WakeLockType type)99 void WakeLockProvider::OnWakeLockActivated(mojom::WakeLockType type) {
100   DVLOG(1) << __func__;
101   const int64_t old_count = GetWakeLockDataPerType(type).count;
102   DCHECK_GE(old_count, 0);
103 
104   GetWakeLockDataPerType(type).count = old_count + 1;
105 }
106 
OnWakeLockDeactivated(mojom::WakeLockType type)107 void WakeLockProvider::OnWakeLockDeactivated(mojom::WakeLockType type) {
108   DVLOG(1) << __func__;
109   const int64_t old_count = GetWakeLockDataPerType(type).count;
110   DCHECK_GT(old_count, 0);
111 
112   const int64_t new_count = old_count - 1;
113   GetWakeLockDataPerType(type).count = new_count;
114   // Notify observers of the last cancelation i.e. deactivation of wake lock
115   // type |type|.
116   if (new_count == 0) {
117     for (auto& observer : GetWakeLockDataPerType(type).observers)
118       observer->OnWakeLockDeactivated(type);
119   }
120 }
121 
OnWakeLockChanged(mojom::WakeLockType old_type,mojom::WakeLockType new_type)122 void WakeLockProvider::OnWakeLockChanged(mojom::WakeLockType old_type,
123                                          mojom::WakeLockType new_type) {
124   // This event is only received iff |old_type| had just one client. A change
125   // event means there is one less wake lock of |old_type| i.e. the same path
126   // as the deactivation event needs to be triggered.
127   OnWakeLockDeactivated(old_type);
128   OnWakeLockActivated(new_type);
129 }
130 
OnConnectionError(mojom::WakeLockType type,WakeLock * wake_lock)131 void WakeLockProvider::OnConnectionError(mojom::WakeLockType type,
132                                          WakeLock* wake_lock) {
133   size_t result = GetWakeLockDataPerType(type).wake_locks.erase(wake_lock);
134   DCHECK_GT(result, 0UL);
135 }
136 
GetWakeLockDataPerType(mojom::WakeLockType type)137 WakeLockProvider::WakeLockDataPerType& WakeLockProvider::GetWakeLockDataPerType(
138     mojom::WakeLockType type) {
139   auto it = wake_lock_store_.find(type);
140   // An entry for |type| should always be created in the constructor.
141   DCHECK(it != wake_lock_store_.end());
142   return *(it->second);
143 }
144 
145 }  // namespace device
146