1 /*
2  * Copyright (C) 2019 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.wm;
18 
19 import static android.hardware.display.DisplayManager.DeviceConfig.KEY_HIGH_REFRESH_RATE_BLACKLIST;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.content.res.Resources;
24 import android.provider.DeviceConfig;
25 import android.util.ArraySet;
26 
27 import com.android.internal.R;
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.internal.os.BackgroundThread;
30 import com.android.server.wm.utils.DeviceConfigInterface;
31 
32 import java.io.PrintWriter;
33 
34 /**
35  * A Blacklist for packages that should force the display out of high refresh rate.
36  */
37 class HighRefreshRateBlacklist {
38 
39     private final ArraySet<String> mBlacklistedPackages = new ArraySet<>();
40     @NonNull
41     private final String[] mDefaultBlacklist;
42     private final Object mLock = new Object();
43 
44     private DeviceConfigInterface mDeviceConfig;
45     private OnPropertiesChangedListener mListener = new OnPropertiesChangedListener();
46 
create(@onNull Resources r)47     static HighRefreshRateBlacklist create(@NonNull Resources r) {
48         return new HighRefreshRateBlacklist(r, DeviceConfigInterface.REAL);
49     }
50 
51     @VisibleForTesting
HighRefreshRateBlacklist(Resources r, DeviceConfigInterface deviceConfig)52     HighRefreshRateBlacklist(Resources r, DeviceConfigInterface deviceConfig) {
53         mDefaultBlacklist = r.getStringArray(R.array.config_highRefreshRateBlacklist);
54         mDeviceConfig = deviceConfig;
55         mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
56                 BackgroundThread.getExecutor(), mListener);
57         final String property = mDeviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
58                 KEY_HIGH_REFRESH_RATE_BLACKLIST);
59         updateBlacklist(property);
60     }
61 
updateBlacklist(@ullable String property)62     private void updateBlacklist(@Nullable String property) {
63         synchronized (mLock) {
64             mBlacklistedPackages.clear();
65             if (property != null) {
66                 String[] packages = property.split(",");
67                 for (String pkg : packages) {
68                     String pkgName = pkg.trim();
69                     if (!pkgName.isEmpty()) {
70                         mBlacklistedPackages.add(pkgName);
71                     }
72                 }
73             } else {
74                 // If there's no config, or the config has been deleted, fallback to the device's
75                 // default blacklist
76                 for (String pkg : mDefaultBlacklist) {
77                     mBlacklistedPackages.add(pkg);
78                 }
79             }
80         }
81     }
82 
isBlacklisted(String packageName)83     boolean isBlacklisted(String packageName) {
84         synchronized (mLock) {
85             return mBlacklistedPackages.contains(packageName);
86         }
87     }
dump(PrintWriter pw)88     void dump(PrintWriter pw) {
89         pw.println("High Refresh Rate Blacklist");
90         pw.println("  Packages:");
91         synchronized (mLock) {
92             for (String pkg : mBlacklistedPackages) {
93                 pw.println("    " + pkg);
94             }
95         }
96     }
97 
98     /** Used to prevent WmTests leaking issues. */
99     @VisibleForTesting
dispose()100     void dispose() {
101         mDeviceConfig.removeOnPropertiesChangedListener(mListener);
102         mDeviceConfig = null;
103         mBlacklistedPackages.clear();
104     }
105 
106     private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener {
onPropertiesChanged(@onNull DeviceConfig.Properties properties)107         public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
108             if (properties.getKeyset().contains(KEY_HIGH_REFRESH_RATE_BLACKLIST)) {
109                 updateBlacklist(
110                         properties.getString(KEY_HIGH_REFRESH_RATE_BLACKLIST, null /*default*/));
111             }
112         }
113     }
114 }
115 
116