1 /*
2  * Copyright (C) 2023 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.display.feature;
18 
19 import android.os.Build;
20 import android.os.SystemProperties;
21 import android.text.TextUtils;
22 import android.util.Slog;
23 
24 import com.android.server.display.feature.flags.Flags;
25 import com.android.server.display.utils.DebugUtils;
26 
27 import java.io.PrintWriter;
28 import java.util.function.Supplier;
29 
30 /**
31  * Utility class to read the flags used in the display manager server.
32  */
33 public class DisplayManagerFlags {
34     private static final String TAG = "DisplayManagerFlags";
35 
36     // To enable these logs, run:
37     // 'adb shell setprop persist.log.tag.DisplayManagerFlags DEBUG && adb reboot'
38     private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
39 
40     private final FlagState mPortInDisplayLayoutFlagState = new FlagState(
41             Flags.FLAG_ENABLE_PORT_IN_DISPLAY_LAYOUT,
42             Flags::enablePortInDisplayLayout);
43 
44     private final FlagState mConnectedDisplayManagementFlagState = new FlagState(
45             Flags.FLAG_ENABLE_CONNECTED_DISPLAY_MANAGEMENT,
46             Flags::enableConnectedDisplayManagement);
47 
48     private final FlagState mNbmControllerFlagState = new FlagState(
49             Flags.FLAG_ENABLE_NBM_CONTROLLER,
50             Flags::enableNbmController);
51 
52     private final FlagState mHdrClamperFlagState = new FlagState(
53             Flags.FLAG_ENABLE_HDR_CLAMPER,
54             Flags::enableHdrClamper);
55 
56     private final FlagState mAdaptiveToneImprovements1 = new FlagState(
57             Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1,
58             Flags::enableAdaptiveToneImprovements1);
59 
60     private final FlagState mAdaptiveToneImprovements2 = new FlagState(
61             Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_2,
62             Flags::enableAdaptiveToneImprovements2);
63 
64     private final FlagState mDisplayOffloadFlagState = new FlagState(
65             Flags.FLAG_ENABLE_DISPLAY_OFFLOAD,
66             Flags::enableDisplayOffload);
67 
68     private final FlagState mExternalDisplayLimitModeState = new FlagState(
69             Flags.FLAG_ENABLE_MODE_LIMIT_FOR_EXTERNAL_DISPLAY,
70             Flags::enableModeLimitForExternalDisplay);
71 
72     private final FlagState mConnectedDisplayErrorHandlingFlagState = new FlagState(
73             Flags.FLAG_ENABLE_CONNECTED_DISPLAY_ERROR_HANDLING,
74             Flags::enableConnectedDisplayErrorHandling);
75 
76     private final FlagState mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState = new FlagState(
77             Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE,
78             Flags::backUpSmoothDisplayAndForcePeakRefreshRate);
79 
80     private final FlagState mPowerThrottlingClamperFlagState = new FlagState(
81             Flags.FLAG_ENABLE_POWER_THROTTLING_CLAMPER,
82             Flags::enablePowerThrottlingClamper);
83 
84     private final FlagState mEvenDimmerFlagState = new FlagState(
85             Flags.FLAG_EVEN_DIMMER,
86             Flags::evenDimmer);
87     private final FlagState mSmallAreaDetectionFlagState = new FlagState(
88             com.android.graphics.surfaceflinger.flags.Flags.FLAG_ENABLE_SMALL_AREA_DETECTION,
89             com.android.graphics.surfaceflinger.flags.Flags::enableSmallAreaDetection);
90 
91     private final FlagState mBrightnessIntRangeUserPerceptionFlagState = new FlagState(
92             Flags.FLAG_BRIGHTNESS_INT_RANGE_USER_PERCEPTION,
93             Flags::brightnessIntRangeUserPerception);
94 
95     private final FlagState mRestrictDisplayModes = new FlagState(
96             Flags.FLAG_ENABLE_RESTRICT_DISPLAY_MODES,
97             Flags::enableRestrictDisplayModes);
98 
99     private final FlagState mResolutionBackupRestore = new FlagState(
100             Flags.FLAG_RESOLUTION_BACKUP_RESTORE,
101             Flags::resolutionBackupRestore);
102 
103     private final FlagState mVsyncLowPowerVote = new FlagState(
104             Flags.FLAG_ENABLE_VSYNC_LOW_POWER_VOTE,
105             Flags::enableVsyncLowPowerVote);
106 
107     private final FlagState mVsyncLowLightVote = new FlagState(
108             Flags.FLAG_ENABLE_VSYNC_LOW_LIGHT_VOTE,
109             Flags::enableVsyncLowLightVote);
110 
111     private final FlagState mBrightnessWearBedtimeModeClamperFlagState = new FlagState(
112             Flags.FLAG_BRIGHTNESS_WEAR_BEDTIME_MODE_CLAMPER,
113             Flags::brightnessWearBedtimeModeClamper);
114 
115     private final FlagState mAutoBrightnessModesFlagState = new FlagState(
116             Flags.FLAG_AUTO_BRIGHTNESS_MODES,
117             Flags::autoBrightnessModes);
118 
119     private final FlagState mFastHdrTransitions = new FlagState(
120             Flags.FLAG_FAST_HDR_TRANSITIONS,
121             Flags::fastHdrTransitions);
122 
123     private final FlagState mAlwaysRotateDisplayDevice = new FlagState(
124             Flags.FLAG_ALWAYS_ROTATE_DISPLAY_DEVICE,
125             Flags::alwaysRotateDisplayDevice);
126 
127     private final FlagState mRefreshRateVotingTelemetry = new FlagState(
128             Flags.FLAG_REFRESH_RATE_VOTING_TELEMETRY,
129             Flags::refreshRateVotingTelemetry
130     );
131 
132     private final FlagState mPixelAnisotropyCorrectionEnabled = new FlagState(
133             Flags.FLAG_ENABLE_PIXEL_ANISOTROPY_CORRECTION,
134             Flags::enablePixelAnisotropyCorrection
135     );
136 
137     private final FlagState mSensorBasedBrightnessThrottling = new FlagState(
138             Flags.FLAG_SENSOR_BASED_BRIGHTNESS_THROTTLING,
139             Flags::sensorBasedBrightnessThrottling
140     );
141 
142     private final FlagState mIdleScreenRefreshRateTimeout = new FlagState(
143             Flags.FLAG_IDLE_SCREEN_REFRESH_RATE_TIMEOUT,
144             Flags::idleScreenRefreshRateTimeout
145     );
146 
147     private final FlagState mRefactorDisplayPowerController = new FlagState(
148             Flags.FLAG_REFACTOR_DISPLAY_POWER_CONTROLLER,
149             Flags::refactorDisplayPowerController
150     );
151 
152     private final FlagState mUseFusionProxSensor = new FlagState(
153             Flags.FLAG_USE_FUSION_PROX_SENSOR,
154             Flags::useFusionProxSensor
155     );
156 
157     private final FlagState mOffloadControlsDozeAutoBrightness = new FlagState(
158             Flags.FLAG_OFFLOAD_CONTROLS_DOZE_AUTO_BRIGHTNESS,
159             Flags::offloadControlsDozeAutoBrightness
160     );
161 
162     private final FlagState mPeakRefreshRatePhysicalLimit = new FlagState(
163             Flags.FLAG_ENABLE_PEAK_REFRESH_RATE_PHYSICAL_LIMIT,
164             Flags::enablePeakRefreshRatePhysicalLimit
165     );
166 
167     private final FlagState mIgnoreAppPreferredRefreshRate = new FlagState(
168             Flags.FLAG_IGNORE_APP_PREFERRED_REFRESH_RATE_REQUEST,
169             Flags::ignoreAppPreferredRefreshRateRequest
170     );
171 
172     private final FlagState mSynthetic60hzModes = new FlagState(
173             Flags.FLAG_ENABLE_SYNTHETIC_60HZ_MODES,
174             Flags::enableSynthetic60hzModes
175     );
176 
177     private final FlagState mOffloadDozeOverrideHoldsWakelock = new FlagState(
178             Flags.FLAG_OFFLOAD_DOZE_OVERRIDE_HOLDS_WAKELOCK,
179             Flags::offloadDozeOverrideHoldsWakelock
180     );
181 
182     /**
183      * @return {@code true} if 'port' is allowed in display layout configuration file.
184      */
isPortInDisplayLayoutEnabled()185     public boolean isPortInDisplayLayoutEnabled() {
186         return mPortInDisplayLayoutFlagState.isEnabled();
187     }
188 
189     /** Returns whether connected display management is enabled or not. */
isConnectedDisplayManagementEnabled()190     public boolean isConnectedDisplayManagementEnabled() {
191         return mConnectedDisplayManagementFlagState.isEnabled();
192     }
193 
194     /** Returns whether NBM Controller is enabled or not. */
isNbmControllerEnabled()195     public boolean isNbmControllerEnabled() {
196         return mNbmControllerFlagState.isEnabled();
197     }
198 
199     /** Returns whether hdr clamper is enabled on not. */
isHdrClamperEnabled()200     public boolean isHdrClamperEnabled() {
201         return mHdrClamperFlagState.isEnabled();
202     }
203 
204     /** Returns whether power throttling clamper is enabled on not. */
isPowerThrottlingClamperEnabled()205     public boolean isPowerThrottlingClamperEnabled() {
206         return mPowerThrottlingClamperFlagState.isEnabled();
207     }
208 
209     /**
210      * Returns whether adaptive tone improvements are enabled
211      */
isAdaptiveTone1Enabled()212     public boolean isAdaptiveTone1Enabled() {
213         return mAdaptiveToneImprovements1.isEnabled();
214     }
215 
216     /**
217      * Returns whether adaptive tone improvements are enabled
218      */
isAdaptiveTone2Enabled()219     public boolean isAdaptiveTone2Enabled() {
220         return mAdaptiveToneImprovements2.isEnabled();
221     }
222 
223     /** Returns whether resolution range voting feature is enabled or not. */
isDisplayResolutionRangeVotingEnabled()224     public boolean isDisplayResolutionRangeVotingEnabled() {
225         return isExternalDisplayLimitModeEnabled();
226     }
227 
228     /**
229      * @return Whether user preferred mode is added as a vote in
230      *      {@link com.android.server.display.mode.DisplayModeDirector}
231      */
isUserPreferredModeVoteEnabled()232     public boolean isUserPreferredModeVoteEnabled() {
233         return isExternalDisplayLimitModeEnabled();
234     }
235 
236     /**
237      * @return Whether external display mode limitation is enabled.
238      */
isExternalDisplayLimitModeEnabled()239     public boolean isExternalDisplayLimitModeEnabled() {
240         return mExternalDisplayLimitModeState.isEnabled();
241     }
242 
243     /**
244      * @return Whether displays refresh rate synchronization is enabled.
245      */
isDisplaysRefreshRatesSynchronizationEnabled()246     public boolean isDisplaysRefreshRatesSynchronizationEnabled() {
247         return isExternalDisplayLimitModeEnabled();
248     }
249 
250     /** Returns whether displayoffload is enabled on not */
isDisplayOffloadEnabled()251     public boolean isDisplayOffloadEnabled() {
252         return mDisplayOffloadFlagState.isEnabled();
253     }
254 
255     /** Returns whether error notifications for connected displays are enabled on not */
isConnectedDisplayErrorHandlingEnabled()256     public boolean isConnectedDisplayErrorHandlingEnabled() {
257         return mConnectedDisplayErrorHandlingFlagState.isEnabled();
258     }
259 
isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()260     public boolean isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled() {
261         return mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState.isEnabled();
262     }
263 
264     /** Returns whether brightness range is allowed to extend below traditional range. */
isEvenDimmerEnabled()265     public boolean isEvenDimmerEnabled() {
266         return mEvenDimmerFlagState.isEnabled();
267     }
268 
isSmallAreaDetectionEnabled()269     public boolean isSmallAreaDetectionEnabled() {
270         return mSmallAreaDetectionFlagState.isEnabled();
271     }
272 
isBrightnessIntRangeUserPerceptionEnabled()273     public boolean isBrightnessIntRangeUserPerceptionEnabled() {
274         return mBrightnessIntRangeUserPerceptionFlagState.isEnabled();
275     }
276 
isRestrictDisplayModesEnabled()277     public boolean isRestrictDisplayModesEnabled() {
278         return mRestrictDisplayModes.isEnabled();
279     }
280 
isResolutionBackupRestoreEnabled()281     public boolean isResolutionBackupRestoreEnabled() {
282         return mResolutionBackupRestore.isEnabled();
283     }
284 
isVsyncLowPowerVoteEnabled()285     public boolean isVsyncLowPowerVoteEnabled() {
286         return mVsyncLowPowerVote.isEnabled();
287     }
288 
isVsyncLowLightVoteEnabled()289     public boolean isVsyncLowLightVoteEnabled() {
290         return mVsyncLowLightVote.isEnabled();
291     }
292 
isBrightnessWearBedtimeModeClamperEnabled()293     public boolean isBrightnessWearBedtimeModeClamperEnabled() {
294         return mBrightnessWearBedtimeModeClamperFlagState.isEnabled();
295     }
296 
297     /**
298      * @return Whether generic auto-brightness modes are enabled
299      */
areAutoBrightnessModesEnabled()300     public boolean areAutoBrightnessModesEnabled() {
301         return mAutoBrightnessModesFlagState.isEnabled();
302     }
303 
isFastHdrTransitionsEnabled()304     public boolean isFastHdrTransitionsEnabled() {
305         return mFastHdrTransitions.isEnabled();
306     }
307 
isAlwaysRotateDisplayDeviceEnabled()308     public boolean isAlwaysRotateDisplayDeviceEnabled() {
309         return mAlwaysRotateDisplayDevice.isEnabled();
310     }
311 
isRefreshRateVotingTelemetryEnabled()312     public boolean isRefreshRateVotingTelemetryEnabled() {
313         return mRefreshRateVotingTelemetry.isEnabled();
314     }
315 
isPixelAnisotropyCorrectionInLogicalDisplayEnabled()316     public boolean isPixelAnisotropyCorrectionInLogicalDisplayEnabled() {
317         return mPixelAnisotropyCorrectionEnabled.isEnabled();
318     }
319 
isSensorBasedBrightnessThrottlingEnabled()320     public boolean isSensorBasedBrightnessThrottlingEnabled() {
321         return mSensorBasedBrightnessThrottling.isEnabled();
322     }
323 
isIdleScreenRefreshRateTimeoutEnabled()324     public boolean isIdleScreenRefreshRateTimeoutEnabled() {
325         return mIdleScreenRefreshRateTimeout.isEnabled();
326     }
327 
isRefactorDisplayPowerControllerEnabled()328     public boolean isRefactorDisplayPowerControllerEnabled() {
329         return mRefactorDisplayPowerController.isEnabled();
330     }
331 
isUseFusionProxSensorEnabled()332     public boolean isUseFusionProxSensorEnabled() {
333         return mUseFusionProxSensor.isEnabled();
334     }
335 
getUseFusionProxSensorFlagName()336     public String getUseFusionProxSensorFlagName() {
337         return mUseFusionProxSensor.getName();
338     }
339 
340     /**
341      * @return Whether DisplayOffload should control auto-brightness in doze
342      */
offloadControlsDozeAutoBrightness()343     public boolean offloadControlsDozeAutoBrightness() {
344         return mOffloadControlsDozeAutoBrightness.isEnabled();
345     }
346 
isPeakRefreshRatePhysicalLimitEnabled()347     public boolean isPeakRefreshRatePhysicalLimitEnabled() {
348         return mPeakRefreshRatePhysicalLimit.isEnabled();
349     }
350 
isOffloadDozeOverrideHoldsWakelockEnabled()351     public boolean isOffloadDozeOverrideHoldsWakelockEnabled() {
352         return mOffloadDozeOverrideHoldsWakelock.isEnabled();
353     }
354 
355     /**
356      * @return Whether to ignore preferredRefreshRate app request conversion to display mode or not
357      */
ignoreAppPreferredRefreshRateRequest()358     public boolean ignoreAppPreferredRefreshRateRequest() {
359         return mIgnoreAppPreferredRefreshRate.isEnabled();
360     }
361 
isSynthetic60HzModesEnabled()362     public boolean isSynthetic60HzModesEnabled() {
363         return mSynthetic60hzModes.isEnabled();
364     }
365 
366     /**
367      * dumps all flagstates
368      * @param pw printWriter
369      */
dump(PrintWriter pw)370     public void dump(PrintWriter pw) {
371         pw.println("DisplayManagerFlags:");
372         pw.println(" " + mAdaptiveToneImprovements1);
373         pw.println(" " + mAdaptiveToneImprovements2);
374         pw.println(" " + mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState);
375         pw.println(" " + mConnectedDisplayErrorHandlingFlagState);
376         pw.println(" " + mConnectedDisplayManagementFlagState);
377         pw.println(" " + mDisplayOffloadFlagState);
378         pw.println(" " + mExternalDisplayLimitModeState);
379         pw.println(" " + mHdrClamperFlagState);
380         pw.println(" " + mNbmControllerFlagState);
381         pw.println(" " + mPowerThrottlingClamperFlagState);
382         pw.println(" " + mEvenDimmerFlagState);
383         pw.println(" " + mSmallAreaDetectionFlagState);
384         pw.println(" " + mBrightnessIntRangeUserPerceptionFlagState);
385         pw.println(" " + mRestrictDisplayModes);
386         pw.println(" " + mBrightnessWearBedtimeModeClamperFlagState);
387         pw.println(" " + mAutoBrightnessModesFlagState);
388         pw.println(" " + mFastHdrTransitions);
389         pw.println(" " + mAlwaysRotateDisplayDevice);
390         pw.println(" " + mRefreshRateVotingTelemetry);
391         pw.println(" " + mPixelAnisotropyCorrectionEnabled);
392         pw.println(" " + mSensorBasedBrightnessThrottling);
393         pw.println(" " + mIdleScreenRefreshRateTimeout);
394         pw.println(" " + mRefactorDisplayPowerController);
395         pw.println(" " + mResolutionBackupRestore);
396         pw.println(" " + mUseFusionProxSensor);
397         pw.println(" " + mOffloadControlsDozeAutoBrightness);
398         pw.println(" " + mPeakRefreshRatePhysicalLimit);
399         pw.println(" " + mIgnoreAppPreferredRefreshRate);
400         pw.println(" " + mSynthetic60hzModes);
401         pw.println(" " + mOffloadDozeOverrideHoldsWakelock);
402     }
403 
404     private static class FlagState {
405 
406         private final String mName;
407 
408         private final Supplier<Boolean> mFlagFunction;
409         private boolean mEnabledSet;
410         private boolean mEnabled;
411 
FlagState(String name, Supplier<Boolean> flagFunction)412         private FlagState(String name, Supplier<Boolean> flagFunction) {
413             mName = name;
414             mFlagFunction = flagFunction;
415         }
416 
getName()417         private String getName() {
418             return mName;
419         }
420 
isEnabled()421         private boolean isEnabled() {
422             if (mEnabledSet) {
423                 if (DEBUG) {
424                     Slog.d(TAG, mName + ": mEnabled. Recall = " + mEnabled);
425                 }
426                 return mEnabled;
427             }
428             mEnabled = flagOrSystemProperty(mFlagFunction, mName);
429             if (DEBUG) {
430                 Slog.d(TAG, mName + ": mEnabled. Flag value = " + mEnabled);
431             }
432             mEnabledSet = true;
433             return mEnabled;
434         }
435 
flagOrSystemProperty(Supplier<Boolean> flagFunction, String flagName)436         private boolean flagOrSystemProperty(Supplier<Boolean> flagFunction, String flagName) {
437             boolean flagValue = flagFunction.get();
438             // TODO(b/299462337) Remove when the infrastructure is ready.
439             if (Build.IS_ENG || Build.IS_USERDEBUG) {
440                 return SystemProperties.getBoolean("persist.sys." + flagName + "-override",
441                         flagValue);
442             }
443             return flagValue;
444         }
445 
446         @Override
toString()447         public String toString() {
448             // remove com.android.server.display.feature.flags. from the beginning of the name.
449             // align all isEnabled() values.
450             // Adjust lengths if we end up with longer names
451             final int nameLength = mName.length();
452             return TextUtils.substring(mName,  41, nameLength) + ": "
453                     + TextUtils.formatSimple("%" + (93 - nameLength) + "s%s", " " , isEnabled())
454                     + " (def:" + mFlagFunction.get() + ")";
455         }
456     }
457 }
458