blob: 775a3ab3360c8b19d8ba5ab8470a994a44f9de3f [file] [log] [blame]
Adrian Roosc1b50322017-02-27 21:07:58 +01001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.util.wakelock;
18
19import android.content.Context;
20import android.os.PowerManager;
Lucas Dupinee4c9b72019-02-18 17:04:58 -080021import android.util.Log;
Gus Prevasab336792018-11-14 13:52:20 -050022
Aurimas Liutikasfd52c142018-04-17 09:50:46 -070023import androidx.annotation.VisibleForTesting;
Adrian Roosc1b50322017-02-27 21:07:58 +010024
Lucas Dupinee4c9b72019-02-18 17:04:58 -080025import java.util.HashMap;
26
Adrian Roosc1b50322017-02-27 21:07:58 +010027/** WakeLock wrapper for testability */
Adrian Roos664c9d72017-04-28 15:52:24 -070028public interface WakeLock {
29
Lucas Dupinee4c9b72019-02-18 17:04:58 -080030 static final String TAG = "WakeLock";
31 static final String REASON_WRAP = "wrap";
Adrian Roos664c9d72017-04-28 15:52:24 -070032
Lucas Dupinee4c9b72019-02-18 17:04:58 -080033 /**
Lucas Dupin924010d2019-06-26 13:23:22 -070034 * Default wake-lock timeout, to avoid battery regressions.
35 */
36 long DEFAULT_MAX_TIMEOUT = 20000;
37
38 /**
Lucas Dupinee4c9b72019-02-18 17:04:58 -080039 * @param why A tag that will be saved for sysui dumps.
40 * @see android.os.PowerManager.WakeLock#acquire()
41 **/
42 void acquire(String why);
43
44 /**
45 * @param why Same tag used in {@link #acquire(String)}
46 * @see android.os.PowerManager.WakeLock#release()
47 **/
48 void release(String why);
Adrian Roos664c9d72017-04-28 15:52:24 -070049
50 /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
51 Runnable wrap(Runnable r);
Adrian Roosc1b50322017-02-27 21:07:58 +010052
53 static WakeLock createPartial(Context context, String tag) {
Lucas Dupin924010d2019-06-26 13:23:22 -070054 return createPartial(context, tag, DEFAULT_MAX_TIMEOUT);
55 }
56
57 /**
58 * Creates a {@link WakeLock} that has a default release timeout.
59 * @see android.os.PowerManager.WakeLock#acquire(long) */
60 static WakeLock createPartial(Context context, String tag, long maxTimeout) {
61 return wrap(createPartialInner(context, tag), maxTimeout);
Adrian Roosc1b50322017-02-27 21:07:58 +010062 }
63
64 @VisibleForTesting
65 static PowerManager.WakeLock createPartialInner(Context context, String tag) {
66 return context.getSystemService(PowerManager.class)
67 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, tag);
68 }
69
Adrian Roos0fb55ae2017-04-14 14:49:11 -070070 static Runnable wrapImpl(WakeLock w, Runnable r) {
Lucas Dupinee4c9b72019-02-18 17:04:58 -080071 w.acquire(REASON_WRAP);
Adrian Roos0fb55ae2017-04-14 14:49:11 -070072 return () -> {
73 try {
74 r.run();
75 } finally {
Lucas Dupinee4c9b72019-02-18 17:04:58 -080076 w.release(REASON_WRAP);
Adrian Roos0fb55ae2017-04-14 14:49:11 -070077 }
78 };
79 }
80
Lucas Dupin924010d2019-06-26 13:23:22 -070081 /**
82 * Create a {@link WakeLock} containing a {@link PowerManager.WakeLock}.
83 * @param inner To be wrapped.
84 * @param maxTimeout When to expire.
85 * @return The new wake lock.
86 */
87 @VisibleForTesting
88 static WakeLock wrap(final PowerManager.WakeLock inner, long maxTimeout) {
Adrian Roosc1b50322017-02-27 21:07:58 +010089 return new WakeLock() {
Lucas Dupinee4c9b72019-02-18 17:04:58 -080090 private final HashMap<String, Integer> mActiveClients = new HashMap<>();
91
Adrian Roosc1b50322017-02-27 21:07:58 +010092 /** @see PowerManager.WakeLock#acquire() */
Lucas Dupinee4c9b72019-02-18 17:04:58 -080093 public void acquire(String why) {
94 mActiveClients.putIfAbsent(why, 0);
95 mActiveClients.put(why, mActiveClients.get(why) + 1);
Lucas Dupin924010d2019-06-26 13:23:22 -070096 inner.acquire(maxTimeout);
Adrian Roosc1b50322017-02-27 21:07:58 +010097 }
98
99 /** @see PowerManager.WakeLock#release() */
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800100 public void release(String why) {
101 Integer count = mActiveClients.get(why);
102 if (count == null) {
103 Log.wtf(TAG, "Releasing WakeLock with invalid reason: " + why,
104 new Throwable());
105 } else if (count == 1) {
106 mActiveClients.remove(why);
107 } else {
108 mActiveClients.put(why, count - 1);
109 }
Adrian Roosc1b50322017-02-27 21:07:58 +0100110 inner.release();
111 }
112
113 /** @see PowerManager.WakeLock#wrap(Runnable) */
114 public Runnable wrap(Runnable runnable) {
Adrian Roos0fb55ae2017-04-14 14:49:11 -0700115 return wrapImpl(this, runnable);
Adrian Roosc1b50322017-02-27 21:07:58 +0100116 }
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800117
118 @Override
119 public String toString() {
120 return "active clients= " + mActiveClients.toString();
121 }
Adrian Roosc1b50322017-02-27 21:07:58 +0100122 };
123 }
Gus Prevasab336792018-11-14 13:52:20 -0500124}