Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 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.gpu; |
| 18 | |
| 19 | import static android.content.Intent.ACTION_PACKAGE_ADDED; |
| 20 | import static android.content.Intent.ACTION_PACKAGE_CHANGED; |
| 21 | import static android.content.Intent.ACTION_PACKAGE_REMOVED; |
| 22 | |
| 23 | import android.annotation.NonNull; |
| 24 | import android.content.BroadcastReceiver; |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 25 | import android.content.ContentResolver; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 26 | import android.content.Context; |
| 27 | import android.content.Intent; |
| 28 | import android.content.IntentFilter; |
| 29 | import android.content.pm.ApplicationInfo; |
| 30 | import android.content.pm.PackageManager; |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 31 | import android.database.ContentObserver; |
| 32 | import android.gamedriver.GameDriverProto.Blacklist; |
| 33 | import android.gamedriver.GameDriverProto.Blacklists; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 34 | import android.net.Uri; |
| 35 | import android.os.Build; |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 36 | import android.os.Handler; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 37 | import android.os.SystemProperties; |
| 38 | import android.os.UserHandle; |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 39 | import android.provider.DeviceConfig; |
Matt Pape | 15769e2 | 2019-04-19 12:31:24 -0700 | [diff] [blame] | 40 | import android.provider.DeviceConfig.Properties; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 41 | import android.provider.Settings; |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 42 | import android.util.Base64; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 43 | import android.util.Slog; |
| 44 | |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 45 | import com.android.framework.protobuf.InvalidProtocolBufferException; |
| 46 | import com.android.internal.annotations.GuardedBy; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 47 | import com.android.server.SystemService; |
| 48 | |
| 49 | import java.io.BufferedReader; |
| 50 | import java.io.IOException; |
| 51 | import java.io.InputStreamReader; |
| 52 | import java.util.ArrayList; |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 53 | import java.util.List; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 54 | |
| 55 | /** |
| 56 | * Service to manage GPU related features. |
| 57 | * |
| 58 | * <p>GPU service is a core service that monitors, coordinates all GPU related features, |
| 59 | * as well as collect metrics about the GPU and GPU driver.</p> |
| 60 | */ |
| 61 | public class GpuService extends SystemService { |
| 62 | public static final String TAG = "GpuService"; |
| 63 | public static final boolean DEBUG = false; |
| 64 | |
| 65 | private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0"; |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 66 | private static final String GAME_DRIVER_WHITELIST_FILENAME = "whitelist.txt"; |
Yiwei Zhang | 1c51f05 | 2019-02-14 12:05:47 -0800 | [diff] [blame] | 67 | private static final String GAME_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt"; |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 68 | private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 69 | |
| 70 | private final Context mContext; |
| 71 | private final String mDriverPackageName; |
| 72 | private final PackageManager mPackageManager; |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 73 | private final Object mLock = new Object(); |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 74 | private final Object mDeviceConfigLock = new Object(); |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 75 | private ContentResolver mContentResolver; |
| 76 | private long mGameDriverVersionCode; |
| 77 | private SettingsObserver mSettingsObserver; |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 78 | private DeviceConfigListener mDeviceConfigListener; |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 79 | @GuardedBy("mLock") |
| 80 | private Blacklists mBlacklists; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 81 | |
| 82 | public GpuService(Context context) { |
| 83 | super(context); |
| 84 | |
| 85 | mContext = context; |
| 86 | mDriverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER); |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 87 | mGameDriverVersionCode = -1; |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 88 | mPackageManager = context.getPackageManager(); |
| 89 | if (mDriverPackageName != null && !mDriverPackageName.isEmpty()) { |
| 90 | final IntentFilter packageFilter = new IntentFilter(); |
| 91 | packageFilter.addAction(ACTION_PACKAGE_ADDED); |
| 92 | packageFilter.addAction(ACTION_PACKAGE_CHANGED); |
| 93 | packageFilter.addAction(ACTION_PACKAGE_REMOVED); |
| 94 | packageFilter.addDataScheme("package"); |
| 95 | getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, |
| 96 | packageFilter, null, null); |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | @Override |
| 101 | public void onStart() { |
| 102 | } |
| 103 | |
| 104 | @Override |
| 105 | public void onBootPhase(int phase) { |
| 106 | if (phase == PHASE_BOOT_COMPLETED) { |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 107 | mContentResolver = mContext.getContentResolver(); |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 108 | if (mDriverPackageName == null || mDriverPackageName.isEmpty()) { |
| 109 | return; |
| 110 | } |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 111 | mSettingsObserver = new SettingsObserver(); |
| 112 | mDeviceConfigListener = new DeviceConfigListener(); |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 113 | fetchGameDriverPackageProperties(); |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 114 | processBlacklists(); |
| 115 | setBlacklist(); |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | private final class SettingsObserver extends ContentObserver { |
| 120 | private final Uri mGameDriverBlackUri = |
| 121 | Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_BLACKLISTS); |
| 122 | |
| 123 | SettingsObserver() { |
| 124 | super(new Handler()); |
| 125 | mContentResolver.registerContentObserver(mGameDriverBlackUri, false, this, |
| 126 | UserHandle.USER_ALL); |
| 127 | } |
| 128 | |
| 129 | @Override |
| 130 | public void onChange(boolean selfChange, Uri uri) { |
| 131 | if (uri == null) { |
| 132 | return; |
| 133 | } |
| 134 | |
| 135 | if (mGameDriverBlackUri.equals(uri)) { |
| 136 | processBlacklists(); |
| 137 | setBlacklist(); |
| 138 | } |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 139 | } |
| 140 | } |
| 141 | |
Matt Pape | 15769e2 | 2019-04-19 12:31:24 -0700 | [diff] [blame] | 142 | private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener { |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 143 | |
| 144 | DeviceConfigListener() { |
| 145 | super(); |
Matt Pape | 15769e2 | 2019-04-19 12:31:24 -0700 | [diff] [blame] | 146 | DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER, |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 147 | mContext.getMainExecutor(), this); |
| 148 | } |
| 149 | @Override |
Matt Pape | 15769e2 | 2019-04-19 12:31:24 -0700 | [diff] [blame] | 150 | public void onPropertiesChanged(Properties properties) { |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 151 | synchronized (mDeviceConfigLock) { |
Matt Pape | 15769e2 | 2019-04-19 12:31:24 -0700 | [diff] [blame] | 152 | if (properties.getKeyset().contains(Settings.Global.GAME_DRIVER_BLACKLISTS)) { |
| 153 | parseBlacklists( |
| 154 | properties.getString(Settings.Global.GAME_DRIVER_BLACKLISTS, "")); |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 155 | setBlacklist(); |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 161 | private final class PackageReceiver extends BroadcastReceiver { |
| 162 | @Override |
| 163 | public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { |
| 164 | final Uri data = intent.getData(); |
| 165 | if (data == null && DEBUG) { |
| 166 | Slog.e(TAG, "Cannot handle package broadcast with null data"); |
| 167 | return; |
| 168 | } |
| 169 | final String packageName = data.getSchemeSpecificPart(); |
| 170 | if (!packageName.equals(mDriverPackageName)) { |
| 171 | return; |
| 172 | } |
| 173 | |
| 174 | final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); |
| 175 | |
| 176 | switch (intent.getAction()) { |
| 177 | case ACTION_PACKAGE_ADDED: |
| 178 | case ACTION_PACKAGE_CHANGED: |
| 179 | case ACTION_PACKAGE_REMOVED: |
| 180 | fetchGameDriverPackageProperties(); |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 181 | setBlacklist(); |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 182 | break; |
| 183 | default: |
| 184 | // do nothing |
| 185 | break; |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | |
Yiwei Zhang | 1c51f05 | 2019-02-14 12:05:47 -0800 | [diff] [blame] | 190 | private static void assetToSettingsGlobal(Context context, Context driverContext, |
| 191 | String fileName, String settingsGlobal, CharSequence delimiter) { |
| 192 | try { |
| 193 | final BufferedReader reader = new BufferedReader( |
| 194 | new InputStreamReader(driverContext.getAssets().open(fileName))); |
| 195 | final ArrayList<String> assetStrings = new ArrayList<>(); |
| 196 | for (String assetString; (assetString = reader.readLine()) != null; ) { |
| 197 | assetStrings.add(assetString); |
| 198 | } |
| 199 | Settings.Global.putString(context.getContentResolver(), |
| 200 | settingsGlobal, |
| 201 | String.join(delimiter, assetStrings)); |
| 202 | } catch (IOException e) { |
| 203 | if (DEBUG) { |
| 204 | Slog.w(TAG, "Failed to load " + fileName + ", abort."); |
| 205 | } |
| 206 | } |
| 207 | } |
| 208 | |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 209 | private void fetchGameDriverPackageProperties() { |
| 210 | final ApplicationInfo driverInfo; |
| 211 | try { |
| 212 | driverInfo = mPackageManager.getApplicationInfo(mDriverPackageName, |
| 213 | PackageManager.MATCH_SYSTEM_ONLY); |
| 214 | } catch (PackageManager.NameNotFoundException e) { |
| 215 | if (DEBUG) { |
| 216 | Slog.e(TAG, "driver package '" + mDriverPackageName + "' not installed"); |
| 217 | } |
| 218 | return; |
| 219 | } |
| 220 | |
| 221 | // O drivers are restricted to the sphal linker namespace, so don't try to use |
| 222 | // packages unless they declare they're compatible with that restriction. |
| 223 | if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) { |
| 224 | if (DEBUG) { |
| 225 | Slog.w(TAG, "Driver package is not known to be compatible with O"); |
| 226 | } |
| 227 | return; |
| 228 | } |
| 229 | |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 230 | // Reset the whitelist. |
| 231 | Settings.Global.putString(mContentResolver, |
| 232 | Settings.Global.GAME_DRIVER_WHITELIST, ""); |
Yiwei Zhang | 1c51f05 | 2019-02-14 12:05:47 -0800 | [diff] [blame] | 233 | // Reset the sphal libraries |
| 234 | Settings.Global.putString(mContentResolver, |
| 235 | Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, ""); |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 236 | mGameDriverVersionCode = driverInfo.longVersionCode; |
| 237 | |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 238 | try { |
| 239 | final Context driverContext = mContext.createPackageContext(mDriverPackageName, |
| 240 | Context.CONTEXT_RESTRICTED); |
Yiwei Zhang | 1c51f05 | 2019-02-14 12:05:47 -0800 | [diff] [blame] | 241 | |
| 242 | assetToSettingsGlobal(mContext, driverContext, GAME_DRIVER_WHITELIST_FILENAME, |
| 243 | Settings.Global.GAME_DRIVER_WHITELIST, ","); |
| 244 | |
| 245 | assetToSettingsGlobal(mContext, driverContext, GAME_DRIVER_SPHAL_LIBRARIES_FILENAME, |
| 246 | Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, ":"); |
| 247 | |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 248 | } catch (PackageManager.NameNotFoundException e) { |
| 249 | if (DEBUG) { |
| 250 | Slog.w(TAG, "driver package '" + mDriverPackageName + "' not installed"); |
| 251 | } |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 252 | } |
| 253 | } |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 254 | |
| 255 | private void processBlacklists() { |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 256 | String base64String = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_GAME_DRIVER, |
| 257 | Settings.Global.GAME_DRIVER_BLACKLISTS); |
| 258 | if (base64String == null) { |
| 259 | base64String = |
| 260 | Settings.Global.getString(mContentResolver, |
| 261 | Settings.Global.GAME_DRIVER_BLACKLISTS); |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 262 | } |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 263 | parseBlacklists(base64String != null ? base64String : ""); |
| 264 | } |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 265 | |
Peiyong Lin | 4e41029 | 2019-04-08 16:12:12 -0700 | [diff] [blame] | 266 | private void parseBlacklists(String base64String) { |
Peiyong Lin | 2485420 | 2019-02-13 20:02:33 +0000 | [diff] [blame] | 267 | synchronized (mLock) { |
| 268 | // Reset all blacklists |
| 269 | mBlacklists = null; |
| 270 | try { |
| 271 | mBlacklists = Blacklists.parseFrom(Base64.decode(base64String, BASE64_FLAGS)); |
| 272 | } catch (IllegalArgumentException e) { |
| 273 | if (DEBUG) { |
| 274 | Slog.w(TAG, "Can't parse blacklist, skip and continue..."); |
| 275 | } |
| 276 | } catch (InvalidProtocolBufferException e) { |
| 277 | if (DEBUG) { |
| 278 | Slog.w(TAG, "Can't parse blacklist, skip and continue..."); |
| 279 | } |
| 280 | } |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | private void setBlacklist() { |
| 285 | Settings.Global.putString(mContentResolver, |
| 286 | Settings.Global.GAME_DRIVER_BLACKLIST, ""); |
| 287 | synchronized (mLock) { |
| 288 | if (mBlacklists == null) { |
| 289 | return; |
| 290 | } |
| 291 | List<Blacklist> blacklists = mBlacklists.getBlacklistsList(); |
| 292 | for (Blacklist blacklist : blacklists) { |
| 293 | if (blacklist.getVersionCode() == mGameDriverVersionCode) { |
| 294 | Settings.Global.putString(mContentResolver, |
| 295 | Settings.Global.GAME_DRIVER_BLACKLIST, |
| 296 | String.join(",", blacklist.getPackageNamesList())); |
| 297 | return; |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | } |
Peiyong Lin | fd71c20 | 2019-01-23 15:29:59 -0800 | [diff] [blame] | 302 | } |