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; 25 import android.content.ContentResolver; 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; 31 import android.database.ContentObserver; 32 import android.net.Uri; 33 import android.os.Build; 34 import android.os.Handler; 35 import android.os.SystemProperties; 36 import android.os.UserHandle; 37 import android.provider.DeviceConfig; 38 import android.provider.DeviceConfig.Properties; 39 import android.provider.Settings; 40 import android.text.TextUtils; 41 import android.updatabledriver.UpdatableDriverProto.Denylist; 42 import android.updatabledriver.UpdatableDriverProto.Denylists; 43 import android.util.Base64; 44 import android.util.Slog; 45 46 import com.android.framework.protobuf.InvalidProtocolBufferException; 47 import com.android.internal.annotations.GuardedBy; 48 import com.android.server.SystemService; 49 50 import java.io.BufferedReader; 51 import java.io.IOException; 52 import java.io.InputStreamReader; 53 import java.util.ArrayList; 54 import java.util.List; 55 56 /** 57 * Service to manage GPU related features. 58 * 59 * <p>GPU service is a core service that monitors, coordinates all GPU related features, 60 * as well as collect metrics about the GPU and GPU driver.</p> 61 */ 62 public class GpuService extends SystemService { 63 public static final String TAG = "GpuService"; 64 public static final boolean DEBUG = false; 65 66 private static final String PROD_DRIVER_PROPERTY = "ro.gfx.driver.0"; 67 private static final String DEV_DRIVER_PROPERTY = "ro.gfx.driver.1"; 68 private static final String UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST_FILENAME = "allowlist.txt"; 69 private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP; 70 71 private final Context mContext; 72 private final String mProdDriverPackageName; 73 private final String mDevDriverPackageName; 74 private final PackageManager mPackageManager; 75 private final Object mLock = new Object(); 76 private final Object mDeviceConfigLock = new Object(); 77 private final boolean mHasProdDriver; 78 private final boolean mHasDevDriver; 79 private ContentResolver mContentResolver; 80 private long mProdDriverVersionCode; 81 private SettingsObserver mSettingsObserver; 82 private DeviceConfigListener mDeviceConfigListener; 83 @GuardedBy("mLock") 84 private Denylists mDenylists; 85 GpuService(Context context)86 public GpuService(Context context) { 87 super(context); 88 89 mContext = context; 90 mProdDriverPackageName = SystemProperties.get(PROD_DRIVER_PROPERTY); 91 mProdDriverVersionCode = -1; 92 mDevDriverPackageName = SystemProperties.get(DEV_DRIVER_PROPERTY); 93 mPackageManager = context.getPackageManager(); 94 mHasProdDriver = !TextUtils.isEmpty(mProdDriverPackageName); 95 mHasDevDriver = !TextUtils.isEmpty(mDevDriverPackageName); 96 if (mHasDevDriver || mHasProdDriver) { 97 final IntentFilter packageFilter = new IntentFilter(); 98 packageFilter.addAction(ACTION_PACKAGE_ADDED); 99 packageFilter.addAction(ACTION_PACKAGE_CHANGED); 100 packageFilter.addAction(ACTION_PACKAGE_REMOVED); 101 packageFilter.addDataScheme("package"); 102 getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, 103 packageFilter, null, null); 104 } 105 } 106 107 @Override onStart()108 public void onStart() { 109 } 110 111 @Override onBootPhase(int phase)112 public void onBootPhase(int phase) { 113 if (phase == PHASE_BOOT_COMPLETED) { 114 mContentResolver = mContext.getContentResolver(); 115 if (!mHasProdDriver && !mHasDevDriver) { 116 return; 117 } 118 mSettingsObserver = new SettingsObserver(); 119 mDeviceConfigListener = new DeviceConfigListener(); 120 fetchProductionDriverPackageProperties(); 121 processDenylists(); 122 setDenylist(); 123 fetchPrereleaseDriverPackageProperties(); 124 } 125 } 126 127 private final class SettingsObserver extends ContentObserver { 128 private final Uri mProdDriverDenylistsUri = 129 Settings.Global.getUriFor(Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLISTS); 130 SettingsObserver()131 SettingsObserver() { 132 super(new Handler()); 133 mContentResolver.registerContentObserver(mProdDriverDenylistsUri, false, this, 134 UserHandle.USER_ALL); 135 } 136 137 @Override onChange(boolean selfChange, Uri uri)138 public void onChange(boolean selfChange, Uri uri) { 139 if (uri == null) { 140 return; 141 } 142 143 if (mProdDriverDenylistsUri.equals(uri)) { 144 processDenylists(); 145 setDenylist(); 146 } 147 } 148 } 149 150 private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener { 151 DeviceConfigListener()152 DeviceConfigListener() { 153 super(); 154 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER, 155 mContext.getMainExecutor(), this); 156 } 157 @Override onPropertiesChanged(Properties properties)158 public void onPropertiesChanged(Properties properties) { 159 synchronized (mDeviceConfigLock) { 160 if (properties.getKeyset().contains( 161 Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLISTS)) { 162 parseDenylists( 163 properties.getString( 164 Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLISTS, "")); 165 setDenylist(); 166 } 167 } 168 } 169 } 170 171 private final class PackageReceiver extends BroadcastReceiver { 172 @Override onReceive(@onNull final Context context, @NonNull final Intent intent)173 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { 174 final Uri data = intent.getData(); 175 if (data == null && DEBUG) { 176 Slog.e(TAG, "Cannot handle package broadcast with null data"); 177 return; 178 } 179 final String packageName = data.getSchemeSpecificPart(); 180 final boolean isProdDriver = packageName.equals(mProdDriverPackageName); 181 final boolean isDevDriver = packageName.equals(mDevDriverPackageName); 182 if (!isProdDriver && !isDevDriver) { 183 return; 184 } 185 186 switch (intent.getAction()) { 187 case ACTION_PACKAGE_ADDED: 188 case ACTION_PACKAGE_CHANGED: 189 case ACTION_PACKAGE_REMOVED: 190 if (isProdDriver) { 191 fetchProductionDriverPackageProperties(); 192 setDenylist(); 193 } else if (isDevDriver) { 194 fetchPrereleaseDriverPackageProperties(); 195 } 196 break; 197 default: 198 // do nothing 199 break; 200 } 201 } 202 } 203 assetToSettingsGlobal(Context context, Context driverContext, String fileName, String settingsGlobal, CharSequence delimiter)204 private static void assetToSettingsGlobal(Context context, Context driverContext, 205 String fileName, String settingsGlobal, CharSequence delimiter) { 206 try { 207 final BufferedReader reader = new BufferedReader( 208 new InputStreamReader(driverContext.getAssets().open(fileName))); 209 final ArrayList<String> assetStrings = new ArrayList<>(); 210 for (String assetString; (assetString = reader.readLine()) != null; ) { 211 assetStrings.add(assetString); 212 } 213 Settings.Global.putString(context.getContentResolver(), 214 settingsGlobal, 215 String.join(delimiter, assetStrings)); 216 } catch (IOException e) { 217 if (DEBUG) { 218 Slog.w(TAG, "Failed to load " + fileName + ", abort."); 219 } 220 } 221 } 222 fetchProductionDriverPackageProperties()223 private void fetchProductionDriverPackageProperties() { 224 final ApplicationInfo driverInfo; 225 try { 226 driverInfo = mPackageManager.getApplicationInfo(mProdDriverPackageName, 227 PackageManager.MATCH_SYSTEM_ONLY); 228 } catch (PackageManager.NameNotFoundException e) { 229 if (DEBUG) { 230 Slog.e(TAG, "driver package '" + mProdDriverPackageName + "' not installed"); 231 } 232 return; 233 } 234 235 // O drivers are restricted to the sphal linker namespace, so don't try to use 236 // packages unless they declare they're compatible with that restriction. 237 if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) { 238 if (DEBUG) { 239 Slog.w(TAG, "Driver package is not known to be compatible with O"); 240 } 241 return; 242 } 243 244 // Reset the allowlist. 245 Settings.Global.putString(mContentResolver, 246 Settings.Global.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST, ""); 247 mProdDriverVersionCode = driverInfo.longVersionCode; 248 249 try { 250 final Context driverContext = mContext.createPackageContext(mProdDriverPackageName, 251 Context.CONTEXT_RESTRICTED); 252 253 assetToSettingsGlobal(mContext, driverContext, 254 UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST_FILENAME, 255 Settings.Global.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST, ","); 256 } catch (PackageManager.NameNotFoundException e) { 257 if (DEBUG) { 258 Slog.w(TAG, "driver package '" + mProdDriverPackageName + "' not installed"); 259 } 260 } 261 } 262 processDenylists()263 private void processDenylists() { 264 String base64String = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_GAME_DRIVER, 265 Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLISTS); 266 if (base64String == null) { 267 base64String = 268 Settings.Global.getString(mContentResolver, 269 Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLISTS); 270 } 271 parseDenylists(base64String != null ? base64String : ""); 272 } 273 parseDenylists(String base64String)274 private void parseDenylists(String base64String) { 275 synchronized (mLock) { 276 // Reset all denylists 277 mDenylists = null; 278 try { 279 mDenylists = Denylists.parseFrom(Base64.decode(base64String, BASE64_FLAGS)); 280 } catch (IllegalArgumentException e) { 281 if (DEBUG) { 282 Slog.w(TAG, "Can't parse denylist, skip and continue..."); 283 } 284 } catch (InvalidProtocolBufferException e) { 285 if (DEBUG) { 286 Slog.w(TAG, "Can't parse denylist, skip and continue..."); 287 } 288 } 289 } 290 } 291 setDenylist()292 private void setDenylist() { 293 Settings.Global.putString(mContentResolver, 294 Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLIST, ""); 295 synchronized (mLock) { 296 if (mDenylists == null) { 297 return; 298 } 299 List<Denylist> denylists = mDenylists.getDenylistsList(); 300 for (Denylist denylist : denylists) { 301 if (denylist.getVersionCode() == mProdDriverVersionCode) { 302 Settings.Global.putString(mContentResolver, 303 Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLIST, 304 String.join(",", denylist.getPackageNamesList())); 305 return; 306 } 307 } 308 } 309 } 310 fetchPrereleaseDriverPackageProperties()311 private void fetchPrereleaseDriverPackageProperties() { 312 final ApplicationInfo driverInfo; 313 try { 314 driverInfo = mPackageManager.getApplicationInfo(mDevDriverPackageName, 315 PackageManager.MATCH_SYSTEM_ONLY); 316 } catch (PackageManager.NameNotFoundException e) { 317 if (DEBUG) { 318 Slog.e(TAG, "driver package '" + mDevDriverPackageName + "' not installed"); 319 } 320 return; 321 } 322 323 // O drivers are restricted to the sphal linker namespace, so don't try to use 324 // packages unless they declare they're compatible with that restriction. 325 if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) { 326 if (DEBUG) { 327 Slog.w(TAG, "Driver package is not known to be compatible with O"); 328 } 329 return; 330 } 331 332 setUpdatableDriverPath(driverInfo); 333 } 334 setUpdatableDriverPath(ApplicationInfo ai)335 private void setUpdatableDriverPath(ApplicationInfo ai) { 336 if (ai.primaryCpuAbi == null) { 337 nSetUpdatableDriverPath(""); 338 return; 339 } 340 final StringBuilder sb = new StringBuilder(); 341 sb.append(ai.sourceDir).append("!/lib/"); 342 nSetUpdatableDriverPath(sb.toString()); 343 } 344 nSetUpdatableDriverPath(String driverPath)345 private static native void nSetUpdatableDriverPath(String driverPath); 346 } 347