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