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