1 /* 2 * Copyright (C) 2021 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.server.power; 18 19 import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP; 20 import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE; 21 import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING; 22 import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING; 23 24 import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_ADDED; 25 import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_CHANGED; 26 import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED; 27 28 import android.hardware.display.DisplayManagerInternal; 29 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; 30 import android.os.PowerManagerInternal; 31 import android.util.Slog; 32 import android.util.SparseArray; 33 import android.view.Display; 34 35 import com.android.internal.annotations.GuardedBy; 36 import com.android.internal.util.ArrayUtils; 37 import com.android.server.display.DisplayGroup; 38 39 /** 40 * Responsible for creating {@link DisplayPowerRequest}s and associating them with 41 * {@link com.android.server.display.DisplayGroup}s. 42 * 43 * Each {@link com.android.server.display.DisplayGroup} has a single {@link DisplayPowerRequest} 44 * which is used to request power state changes to every display in the group. 45 */ 46 public class DisplayGroupPowerStateMapper { 47 48 private static final String TAG = "DisplayPowerRequestMapper"; 49 50 /** Lock obtained from {@link PowerManagerService}. */ 51 private final Object mLock; 52 53 /** Listener to inform of changes to display groups. */ 54 private final DisplayGroupPowerChangeListener mListener; 55 56 /** A mapping from DisplayGroup Id to DisplayGroup information. */ 57 @GuardedBy("mLock") 58 private final SparseArray<DisplayGroupInfo> mDisplayGroupInfos = new SparseArray<>(); 59 60 /** A cached array of DisplayGroup Ids. */ 61 @GuardedBy("mLock") 62 private int[] mDisplayGroupIds; 63 64 private final DisplayManagerInternal.DisplayGroupListener mDisplayGroupListener = 65 new DisplayManagerInternal.DisplayGroupListener() { 66 @Override 67 public void onDisplayGroupAdded(int groupId) { 68 synchronized (mLock) { 69 if (mDisplayGroupInfos.contains(groupId)) { 70 Slog.e(TAG, "Tried to add already existing group:" + groupId); 71 return; 72 } 73 // For now, only the default group supports sandman (dream/AOD). 74 final boolean supportsSandman = groupId == Display.DEFAULT_DISPLAY_GROUP; 75 final DisplayGroupInfo displayGroupInfo = new DisplayGroupInfo( 76 new DisplayPowerRequest(), 77 getGlobalWakefulnessLocked(), 78 /* ready= */ false, 79 supportsSandman); 80 mDisplayGroupInfos.append(groupId, displayGroupInfo); 81 mDisplayGroupIds = ArrayUtils.appendInt(mDisplayGroupIds, groupId); 82 mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_ADDED, groupId); 83 } 84 } 85 86 @Override 87 public void onDisplayGroupRemoved(int groupId) { 88 synchronized (mLock) { 89 if (!mDisplayGroupInfos.contains(groupId)) { 90 Slog.e(TAG, "Tried to remove non-existent group:" + groupId); 91 return; 92 } 93 mDisplayGroupInfos.delete(groupId); 94 mDisplayGroupIds = ArrayUtils.removeInt(mDisplayGroupIds, groupId); 95 mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_REMOVED, groupId); 96 } 97 } 98 99 @Override 100 public void onDisplayGroupChanged(int groupId) { 101 synchronized (mLock) { 102 mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_CHANGED, groupId); 103 } 104 } 105 }; 106 DisplayGroupPowerStateMapper(Object lock, DisplayManagerInternal displayManagerInternal, DisplayGroupPowerChangeListener listener)107 DisplayGroupPowerStateMapper(Object lock, DisplayManagerInternal displayManagerInternal, 108 DisplayGroupPowerChangeListener listener) { 109 mLock = lock; 110 mListener = listener; 111 displayManagerInternal.registerDisplayGroupListener(mDisplayGroupListener); 112 113 final DisplayGroupInfo displayGroupInfo = new DisplayGroupInfo( 114 new DisplayPowerRequest(), WAKEFULNESS_AWAKE, /* ready= */ 115 false, /* supportsSandman= */ true); 116 mDisplayGroupInfos.append(Display.DEFAULT_DISPLAY_GROUP, displayGroupInfo); 117 mDisplayGroupIds = new int[]{Display.DEFAULT_DISPLAY_GROUP}; 118 } 119 getPowerRequestLocked(int groupId)120 DisplayPowerRequest getPowerRequestLocked(int groupId) { 121 return mDisplayGroupInfos.get(groupId).displayPowerRequest; 122 } 123 getDisplayGroupIdsLocked()124 int[] getDisplayGroupIdsLocked() { 125 return mDisplayGroupIds; 126 } 127 getDisplayGroupCountLocked()128 int getDisplayGroupCountLocked() { 129 return mDisplayGroupIds.length; 130 } 131 getWakefulnessLocked(int groupId)132 int getWakefulnessLocked(int groupId) { 133 return mDisplayGroupInfos.get(groupId).wakefulness; 134 } 135 setLastPowerOnTimeLocked(int groupId, long eventTime)136 void setLastPowerOnTimeLocked(int groupId, long eventTime) { 137 mDisplayGroupInfos.get(groupId).lastPowerOnTime = eventTime; 138 } 139 getLastPowerOnTimeLocked(int groupId)140 long getLastPowerOnTimeLocked(int groupId) { 141 return mDisplayGroupInfos.get(groupId).lastPowerOnTime; 142 } 143 setPoweringOnLocked(int groupId, boolean poweringOn)144 void setPoweringOnLocked(int groupId, boolean poweringOn) { 145 mDisplayGroupInfos.get(groupId).poweringOn = poweringOn; 146 } 147 isPoweringOnLocked(int groupId)148 boolean isPoweringOnLocked(int groupId) { 149 return mDisplayGroupInfos.get(groupId).poweringOn; 150 } 151 152 /** 153 * Returns the amalgamated wakefulness of all {@link DisplayGroup DisplayGroups}. 154 * 155 * <p>This will be the highest wakeful state of all {@link DisplayGroup DisplayGroups}; ordered 156 * from highest to lowest: 157 * <ol> 158 * <li>{@link PowerManagerInternal#WAKEFULNESS_AWAKE} 159 * <li>{@link PowerManagerInternal#WAKEFULNESS_DREAMING} 160 * <li>{@link PowerManagerInternal#WAKEFULNESS_DOZING} 161 * <li>{@link PowerManagerInternal#WAKEFULNESS_ASLEEP} 162 * </ol> 163 */ getGlobalWakefulnessLocked()164 int getGlobalWakefulnessLocked() { 165 final int size = mDisplayGroupInfos.size(); 166 int deviceWakefulness = WAKEFULNESS_ASLEEP; 167 for (int i = 0; i < size; i++) { 168 final int wakefulness = mDisplayGroupInfos.valueAt(i).wakefulness; 169 if (wakefulness == WAKEFULNESS_AWAKE) { 170 return WAKEFULNESS_AWAKE; 171 } else if (wakefulness == WAKEFULNESS_DREAMING 172 && (deviceWakefulness == WAKEFULNESS_ASLEEP 173 || deviceWakefulness == WAKEFULNESS_DOZING)) { 174 deviceWakefulness = WAKEFULNESS_DREAMING; 175 } else if (wakefulness == WAKEFULNESS_DOZING 176 && deviceWakefulness == WAKEFULNESS_ASLEEP) { 177 deviceWakefulness = WAKEFULNESS_DOZING; 178 } 179 } 180 181 return deviceWakefulness; 182 } 183 184 /** 185 * Sets the {@code wakefulness} value for the {@link DisplayGroup} specified by the provided 186 * {@code groupId}. 187 * 188 * @return {@code true} if the wakefulness value was changed; {@code false} otherwise. 189 */ setWakefulnessLocked(int groupId, int wakefulness)190 boolean setWakefulnessLocked(int groupId, int wakefulness) { 191 final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId); 192 if (displayGroupInfo.wakefulness != wakefulness) { 193 displayGroupInfo.wakefulness = wakefulness; 194 return true; 195 } 196 197 return false; 198 } 199 isSandmanSummoned(int groupId)200 boolean isSandmanSummoned(int groupId) { 201 return mDisplayGroupInfos.get(groupId).sandmanSummoned; 202 } 203 isSandmanSupported(int groupId)204 boolean isSandmanSupported(int groupId) { 205 return mDisplayGroupInfos.get(groupId).supportsSandman; 206 } 207 208 /** 209 * Sets whether or not the sandman is summoned for the given {@code groupId}. 210 * 211 * @param groupId Signifies the DisplayGroup for which to summon or unsummon the 212 * sandman. 213 * @param sandmanSummoned {@code true} to summon the sandman; {@code false} to unsummon. 214 */ setSandmanSummoned(int groupId, boolean sandmanSummoned)215 void setSandmanSummoned(int groupId, boolean sandmanSummoned) { 216 final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId); 217 displayGroupInfo.sandmanSummoned = displayGroupInfo.supportsSandman && sandmanSummoned; 218 } 219 220 /** 221 * Returns {@code true} if every display in the specified group has its requested state matching 222 * its actual state. 223 * 224 * @param groupId The identifier for the display group to check for readiness. 225 */ isReady(int groupId)226 boolean isReady(int groupId) { 227 return mDisplayGroupInfos.get(groupId).ready; 228 } 229 230 /** Returns {@code true} if every display has its requested state matching its actual state. */ areAllDisplaysReadyLocked()231 boolean areAllDisplaysReadyLocked() { 232 final int size = mDisplayGroupInfos.size(); 233 for (int i = 0; i < size; i++) { 234 if (!mDisplayGroupInfos.valueAt(i).ready) { 235 return false; 236 } 237 } 238 239 return true; 240 } 241 242 /** 243 * Sets whether the displays specified by the provided {@code groupId} are all ready. 244 * 245 * <p>A display is ready if its reported 246 * {@link DisplayManagerInternal.DisplayPowerCallbacks#onStateChanged() actual state} matches 247 * its {@link DisplayManagerInternal#requestPowerState requested state}. 248 * 249 * @param groupId The identifier for the display group. 250 * @param ready {@code true} if every display in the group is ready; otherwise {@code false}. 251 * @return {@code true} if the ready state changed; otherwise {@code false}. 252 */ setDisplayGroupReadyLocked(int groupId, boolean ready)253 boolean setDisplayGroupReadyLocked(int groupId, boolean ready) { 254 final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId); 255 if (displayGroupInfo.ready != ready) { 256 displayGroupInfo.ready = ready; 257 return true; 258 } 259 260 return false; 261 } 262 getLastUserActivityTimeLocked(int groupId)263 long getLastUserActivityTimeLocked(int groupId) { 264 return mDisplayGroupInfos.get(groupId).lastUserActivityTime; 265 } 266 getLastUserActivityTimeNoChangeLightsLocked(int groupId)267 long getLastUserActivityTimeNoChangeLightsLocked(int groupId) { 268 return mDisplayGroupInfos.get(groupId).lastUserActivityTimeNoChangeLights; 269 } 270 getUserActivitySummaryLocked(int groupId)271 int getUserActivitySummaryLocked(int groupId) { 272 return mDisplayGroupInfos.get(groupId).userActivitySummary; 273 } 274 setLastUserActivityTimeLocked(int groupId, long time)275 void setLastUserActivityTimeLocked(int groupId, long time) { 276 mDisplayGroupInfos.get(groupId).lastUserActivityTime = time; 277 } 278 setLastUserActivityTimeNoChangeLightsLocked(int groupId, long time)279 void setLastUserActivityTimeNoChangeLightsLocked(int groupId, long time) { 280 mDisplayGroupInfos.get(groupId).lastUserActivityTimeNoChangeLights = time; 281 } 282 setUserActivitySummaryLocked(int groupId, int summary)283 void setUserActivitySummaryLocked(int groupId, int summary) { 284 mDisplayGroupInfos.get(groupId).userActivitySummary = summary; 285 } 286 getWakeLockSummaryLocked(int groupId)287 int getWakeLockSummaryLocked(int groupId) { 288 return mDisplayGroupInfos.get(groupId).wakeLockSummary; 289 } 290 setWakeLockSummaryLocked(int groupId, int summary)291 void setWakeLockSummaryLocked(int groupId, int summary) { 292 mDisplayGroupInfos.get(groupId).wakeLockSummary = summary; 293 } 294 295 /** 296 * Interface through which an interested party may be informed of {@link DisplayGroup} events. 297 */ 298 interface DisplayGroupPowerChangeListener { 299 int DISPLAY_GROUP_ADDED = 0; 300 int DISPLAY_GROUP_REMOVED = 1; 301 int DISPLAY_GROUP_CHANGED = 2; 302 onDisplayGroupEventLocked(int event, int groupId)303 void onDisplayGroupEventLocked(int event, int groupId); 304 } 305 306 private static final class DisplayGroupInfo { 307 public final DisplayPowerRequest displayPowerRequest; 308 public int wakefulness; 309 public boolean ready; 310 public long lastPowerOnTime; 311 boolean poweringOn; 312 public boolean sandmanSummoned; 313 public long lastUserActivityTime; 314 public long lastUserActivityTimeNoChangeLights; 315 public int userActivitySummary; 316 public int wakeLockSummary; 317 318 /** {@code true} if this DisplayGroup supports dreaming; otherwise {@code false}. */ 319 public boolean supportsSandman; 320 DisplayGroupInfo(DisplayPowerRequest displayPowerRequest, int wakefulness, boolean ready, boolean supportsSandman)321 DisplayGroupInfo(DisplayPowerRequest displayPowerRequest, int wakefulness, boolean ready, 322 boolean supportsSandman) { 323 this.displayPowerRequest = displayPowerRequest; 324 this.wakefulness = wakefulness; 325 this.ready = ready; 326 this.supportsSandman = supportsSandman; 327 } 328 } 329 } 330