blob: d4396534d06726c694de3accebca7a9b75b4b440 [file] [log] [blame]
Peiyong Linfd71c202019-01-23 15:29:59 -08001/*
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
17package com.android.server.gpu;
18
19import static android.content.Intent.ACTION_PACKAGE_ADDED;
20import static android.content.Intent.ACTION_PACKAGE_CHANGED;
21import static android.content.Intent.ACTION_PACKAGE_REMOVED;
22
23import android.annotation.NonNull;
24import android.content.BroadcastReceiver;
Peiyong Lin24854202019-02-13 20:02:33 +000025import android.content.ContentResolver;
Peiyong Linfd71c202019-01-23 15:29:59 -080026import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.pm.ApplicationInfo;
30import android.content.pm.PackageManager;
Peiyong Lin24854202019-02-13 20:02:33 +000031import android.database.ContentObserver;
32import android.gamedriver.GameDriverProto.Blacklist;
33import android.gamedriver.GameDriverProto.Blacklists;
Peiyong Linfd71c202019-01-23 15:29:59 -080034import android.net.Uri;
35import android.os.Build;
Peiyong Lin24854202019-02-13 20:02:33 +000036import android.os.Handler;
Peiyong Linfd71c202019-01-23 15:29:59 -080037import android.os.SystemProperties;
38import android.os.UserHandle;
Peiyong Lin4e410292019-04-08 16:12:12 -070039import android.provider.DeviceConfig;
Matt Pape15769e22019-04-19 12:31:24 -070040import android.provider.DeviceConfig.Properties;
Peiyong Linfd71c202019-01-23 15:29:59 -080041import android.provider.Settings;
Peiyong Lin24854202019-02-13 20:02:33 +000042import android.util.Base64;
Peiyong Linfd71c202019-01-23 15:29:59 -080043import android.util.Slog;
44
Peiyong Lin24854202019-02-13 20:02:33 +000045import com.android.framework.protobuf.InvalidProtocolBufferException;
46import com.android.internal.annotations.GuardedBy;
Peiyong Linfd71c202019-01-23 15:29:59 -080047import com.android.server.SystemService;
48
49import java.io.BufferedReader;
50import java.io.IOException;
51import java.io.InputStreamReader;
52import java.util.ArrayList;
Peiyong Lin24854202019-02-13 20:02:33 +000053import java.util.List;
Peiyong Linfd71c202019-01-23 15:29:59 -080054
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 */
61public 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 Lin24854202019-02-13 20:02:33 +000066 private static final String GAME_DRIVER_WHITELIST_FILENAME = "whitelist.txt";
Yiwei Zhang1c51f052019-02-14 12:05:47 -080067 private static final String GAME_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
Peiyong Lin24854202019-02-13 20:02:33 +000068 private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
Peiyong Linfd71c202019-01-23 15:29:59 -080069
70 private final Context mContext;
71 private final String mDriverPackageName;
72 private final PackageManager mPackageManager;
Peiyong Lin24854202019-02-13 20:02:33 +000073 private final Object mLock = new Object();
Peiyong Lin4e410292019-04-08 16:12:12 -070074 private final Object mDeviceConfigLock = new Object();
Peiyong Lin24854202019-02-13 20:02:33 +000075 private ContentResolver mContentResolver;
76 private long mGameDriverVersionCode;
77 private SettingsObserver mSettingsObserver;
Peiyong Lin4e410292019-04-08 16:12:12 -070078 private DeviceConfigListener mDeviceConfigListener;
Peiyong Lin24854202019-02-13 20:02:33 +000079 @GuardedBy("mLock")
80 private Blacklists mBlacklists;
Peiyong Linfd71c202019-01-23 15:29:59 -080081
82 public GpuService(Context context) {
83 super(context);
84
85 mContext = context;
86 mDriverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
Peiyong Lin24854202019-02-13 20:02:33 +000087 mGameDriverVersionCode = -1;
Peiyong Linfd71c202019-01-23 15:29:59 -080088 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 Lin24854202019-02-13 20:02:33 +0000107 mContentResolver = mContext.getContentResolver();
Peiyong Linfd71c202019-01-23 15:29:59 -0800108 if (mDriverPackageName == null || mDriverPackageName.isEmpty()) {
109 return;
110 }
Peiyong Lin4e410292019-04-08 16:12:12 -0700111 mSettingsObserver = new SettingsObserver();
112 mDeviceConfigListener = new DeviceConfigListener();
Peiyong Linfd71c202019-01-23 15:29:59 -0800113 fetchGameDriverPackageProperties();
Peiyong Lin24854202019-02-13 20:02:33 +0000114 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 Linfd71c202019-01-23 15:29:59 -0800139 }
140 }
141
Matt Pape15769e22019-04-19 12:31:24 -0700142 private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
Peiyong Lin4e410292019-04-08 16:12:12 -0700143
144 DeviceConfigListener() {
145 super();
Matt Pape15769e22019-04-19 12:31:24 -0700146 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER,
Peiyong Lin4e410292019-04-08 16:12:12 -0700147 mContext.getMainExecutor(), this);
148 }
149 @Override
Matt Pape15769e22019-04-19 12:31:24 -0700150 public void onPropertiesChanged(Properties properties) {
Peiyong Lin4e410292019-04-08 16:12:12 -0700151 synchronized (mDeviceConfigLock) {
Matt Pape15769e22019-04-19 12:31:24 -0700152 if (properties.getKeyset().contains(Settings.Global.GAME_DRIVER_BLACKLISTS)) {
153 parseBlacklists(
154 properties.getString(Settings.Global.GAME_DRIVER_BLACKLISTS, ""));
Peiyong Lin4e410292019-04-08 16:12:12 -0700155 setBlacklist();
156 }
157 }
158 }
159 }
160
Peiyong Linfd71c202019-01-23 15:29:59 -0800161 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 Lin24854202019-02-13 20:02:33 +0000181 setBlacklist();
Peiyong Linfd71c202019-01-23 15:29:59 -0800182 break;
183 default:
184 // do nothing
185 break;
186 }
187 }
188 }
189
Yiwei Zhang1c51f052019-02-14 12:05:47 -0800190 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 Linfd71c202019-01-23 15:29:59 -0800209 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 Lin24854202019-02-13 20:02:33 +0000230 // Reset the whitelist.
231 Settings.Global.putString(mContentResolver,
232 Settings.Global.GAME_DRIVER_WHITELIST, "");
Yiwei Zhang1c51f052019-02-14 12:05:47 -0800233 // Reset the sphal libraries
234 Settings.Global.putString(mContentResolver,
235 Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, "");
Peiyong Lin24854202019-02-13 20:02:33 +0000236 mGameDriverVersionCode = driverInfo.longVersionCode;
237
Peiyong Linfd71c202019-01-23 15:29:59 -0800238 try {
239 final Context driverContext = mContext.createPackageContext(mDriverPackageName,
240 Context.CONTEXT_RESTRICTED);
Yiwei Zhang1c51f052019-02-14 12:05:47 -0800241
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 Linfd71c202019-01-23 15:29:59 -0800248 } catch (PackageManager.NameNotFoundException e) {
249 if (DEBUG) {
250 Slog.w(TAG, "driver package '" + mDriverPackageName + "' not installed");
251 }
Peiyong Linfd71c202019-01-23 15:29:59 -0800252 }
253 }
Peiyong Lin24854202019-02-13 20:02:33 +0000254
255 private void processBlacklists() {
Peiyong Lin4e410292019-04-08 16:12:12 -0700256 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 Lin24854202019-02-13 20:02:33 +0000262 }
Peiyong Lin4e410292019-04-08 16:12:12 -0700263 parseBlacklists(base64String != null ? base64String : "");
264 }
Peiyong Lin24854202019-02-13 20:02:33 +0000265
Peiyong Lin4e410292019-04-08 16:12:12 -0700266 private void parseBlacklists(String base64String) {
Peiyong Lin24854202019-02-13 20:02:33 +0000267 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 Linfd71c202019-01-23 15:29:59 -0800302}