• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 
17 package com.android.car.systeminterface;
18 
19 import static com.android.car.internal.util.VersionUtils.isPlatformVersionAtLeastU;
20 
21 import android.car.builtin.power.PowerManagerHelper;
22 import android.car.builtin.util.Slogf;
23 import android.content.Context;
24 import android.hardware.display.DisplayManager;
25 import android.os.PowerManager;
26 import android.os.PowerManager.WakeLock;
27 import android.util.Pair;
28 import android.util.SparseArray;
29 import android.view.Display;
30 
31 import com.android.car.CarLog;
32 import com.android.internal.annotations.GuardedBy;
33 
34 /**
35  * Interface that abstracts wake lock operations
36  */
37 public interface WakeLockInterface {
38 
39     /**
40      * Releases all wakelocks.
41      *
42      * @param displayId Target display
43      */
releaseAllWakeLocks(int displayId)44     void releaseAllWakeLocks(int displayId);
45 
46     /**
47      * Acquires partial wakelock.
48      *
49      * @param displayId Target display
50      * @see android.os.PowerManager#PARTIAL_WAKE_LOCK
51      */
switchToPartialWakeLock(int displayId)52     void switchToPartialWakeLock(int displayId);
53 
54     /**
55      * Acquires full wakelock. This can wake up the display if display is asleep.
56      *
57      * @param displayId Target display
58      */
switchToFullWakeLock(int displayId)59     void switchToFullWakeLock(int displayId);
60 
61     class DefaultImpl implements WakeLockInterface {
62         private static final String TAG = WakeLockInterface.class.getSimpleName();
63 
64         private final Context mContext;
65         private final Object mLock = new Object();
66         @GuardedBy("mLock")
67         private final SparseArray<Pair</* Full */WakeLock, /* Partial */WakeLock>>
68                 mPerDisplayWakeLocks = new SparseArray<>();
69 
DefaultImpl(Context context)70         DefaultImpl(Context context) {
71             mContext = context;
72             DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
73             displayManager.registerDisplayListener(mDisplayListener, /* handler= */ null);
74 
75 
76             if (isPlatformVersionAtLeastU()) {
77                 for (Display display : displayManager.getDisplays()) {
78                     int displayId = display.getDisplayId();
79                     Pair<WakeLock, WakeLock> wakeLockPair = createWakeLockPair(displayId);
80                     synchronized (mLock) {
81                         mPerDisplayWakeLocks.put(displayId, wakeLockPair);
82                     }
83                 }
84             } else {
85                 Pair<WakeLock, WakeLock> wakeLockPair = createWakeLockPair(Display.DEFAULT_DISPLAY);
86                 synchronized (mLock) {
87                     mPerDisplayWakeLocks.put(Display.DEFAULT_DISPLAY, wakeLockPair);
88                 }
89             }
90         }
91 
92         @Override
switchToPartialWakeLock(int displayId)93         public void switchToPartialWakeLock(int displayId) {
94             Pair<WakeLock, WakeLock> wakeLockPair;
95             synchronized (mLock) {
96                 wakeLockPair = mPerDisplayWakeLocks.get(displayId);
97             }
98             if (wakeLockPair == null) {
99                 Slogf.w(TAG, "WakeLocks for display %d is null", displayId);
100                 return;
101             }
102             WakeLock partialWakeLock = wakeLockPair.second;
103             WakeLock fullWakeLock = wakeLockPair.first;
104             if (!partialWakeLock.isHeld()) {
105                 // CPMS controls the wake lock duration, so we don't use timeout when calling
106                 // acquire().
107                 partialWakeLock.acquire();
108             }
109             if (fullWakeLock.isHeld()) {
110                 fullWakeLock.release();
111             }
112         }
113 
114         @Override
switchToFullWakeLock(int displayId)115         public void switchToFullWakeLock(int displayId) {
116             Pair<WakeLock, WakeLock> wakeLockPair;
117             synchronized (mLock) {
118                 wakeLockPair = mPerDisplayWakeLocks.get(displayId);
119             }
120             if (wakeLockPair == null) {
121                 Slogf.w(TAG, "WakeLocks for display %d is null", displayId);
122                 return;
123             }
124             WakeLock fullWakeLock = wakeLockPair.first;
125             WakeLock partialWakeLock = wakeLockPair.second;
126             if (!fullWakeLock.isHeld()) {
127                 // CPMS controls the wake lock duration, so we don't use timeout when calling
128                 // acquire().
129                 fullWakeLock.acquire();
130             }
131             if (partialWakeLock.isHeld()) {
132                 partialWakeLock.release();
133             }
134         }
135 
136         @Override
releaseAllWakeLocks(int displayId)137         public void releaseAllWakeLocks(int displayId) {
138             Pair<WakeLock, WakeLock> wakeLockPair;
139             synchronized (mLock) {
140                 wakeLockPair = mPerDisplayWakeLocks.get(displayId);
141             }
142             if (wakeLockPair == null) {
143                 Slogf.w(TAG, "WakeLocks for display %d is null", displayId);
144                 return;
145             }
146             WakeLock fullWakeLock = wakeLockPair.first;
147             WakeLock partialWakeLock = wakeLockPair.second;
148             if (fullWakeLock.isHeld()) {
149                 fullWakeLock.release();
150             }
151             if (partialWakeLock.isHeld()) {
152                 partialWakeLock.release();
153             }
154         }
155 
createWakeLockPair(int displayId)156         private Pair<WakeLock, WakeLock> createWakeLockPair(int displayId) {
157             if (isPlatformVersionAtLeastU()) {
158                 StringBuilder tag = new StringBuilder(CarLog.TAG_POWER).append(":")
159                         .append(displayId);
160                 WakeLock fullWakeLock = PowerManagerHelper.newWakeLock(mContext,
161                         PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
162                         tag.toString(), displayId);
163                 WakeLock partialWakeLock = PowerManagerHelper.newWakeLock(mContext,
164                         PowerManager.PARTIAL_WAKE_LOCK, tag.toString(), displayId);
165                 Slogf.d(TAG, "createWakeLockPair displayId=%d", displayId);
166                 return Pair.create(fullWakeLock, partialWakeLock);
167             }
168 
169             PowerManager powerManager = mContext.getSystemService(PowerManager.class);
170             WakeLock fullWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
171                     CarLog.TAG_POWER);
172             WakeLock partialWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
173                     CarLog.TAG_POWER);
174             Slogf.d(TAG, "createWakeLockPair for main display");
175             return Pair.create(fullWakeLock, partialWakeLock);
176         }
177 
178         DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
179             @Override
180             public void onDisplayAdded(int displayId) {
181                 Slogf.d(TAG, "onDisplayAdded displayId=%d", displayId);
182                 Pair<WakeLock, WakeLock> wakeLockPair = createWakeLockPair(displayId);
183 
184                 synchronized (mLock) {
185                     mPerDisplayWakeLocks.put(displayId, wakeLockPair);
186                 }
187             }
188 
189             @Override
190             public void onDisplayRemoved(int displayId) {
191                 Slogf.d(TAG, "onDisplayRemoved displayId=%d", displayId);
192                 Pair<WakeLock, WakeLock> wakeLockPair;
193                 synchronized (mLock) {
194                     wakeLockPair = mPerDisplayWakeLocks.get(displayId);
195                     if (wakeLockPair == null) {
196                         Slogf.w(TAG, "WakeLocks for display %d is null", displayId);
197                         return;
198                     }
199                     mPerDisplayWakeLocks.remove(displayId);
200                 }
201                 WakeLock fullWakeLock = wakeLockPair.first;
202                 WakeLock partialWakeLock = wakeLockPair.second;
203                 if (fullWakeLock.isHeld()) {
204                     fullWakeLock.release();
205                 }
206                 if (partialWakeLock.isHeld()) {
207                     partialWakeLock.release();
208                 }
209             }
210 
211             @Override
212             public void onDisplayChanged(int displayId) {
213                 // ignore
214             }
215         };
216     }
217 }
218