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