• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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