• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.compat;
18 
19 import static android.Manifest.permission.LOG_COMPAT_CHANGE;
20 import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
21 import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD;
22 import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
23 
24 import android.annotation.EnforcePermission;
25 import android.annotation.RequiresNoPermission;
26 import android.annotation.UserIdInt;
27 import android.app.ActivityManager;
28 import android.app.IActivityManager;
29 import android.app.compat.PackageOverride;
30 import android.content.BroadcastReceiver;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.pm.ApplicationInfo;
35 import android.content.pm.PackageManager;
36 import android.content.pm.PackageManagerInternal;
37 import android.net.Uri;
38 import android.os.Binder;
39 import android.os.Build;
40 import android.os.PermissionEnforcer;
41 import android.os.Process;
42 import android.os.RemoteException;
43 import android.os.UserHandle;
44 import android.util.Slog;
45 
46 import com.android.internal.annotations.VisibleForTesting;
47 import com.android.internal.compat.AndroidBuildClassifier;
48 import com.android.internal.compat.ChangeReporter;
49 import com.android.internal.compat.CompatibilityChangeConfig;
50 import com.android.internal.compat.CompatibilityChangeInfo;
51 import com.android.internal.compat.CompatibilityOverrideConfig;
52 import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
53 import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
54 import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
55 import com.android.internal.compat.IOverrideValidator;
56 import com.android.internal.compat.IPlatformCompat;
57 import com.android.internal.util.DumpUtils;
58 import com.android.server.LocalServices;
59 
60 import java.io.FileDescriptor;
61 import java.io.PrintWriter;
62 import java.util.Arrays;
63 import java.util.Collection;
64 import java.util.HashMap;
65 import java.util.Map;
66 
67 /**
68  * System server internal API for gating and reporting compatibility changes.
69  */
70 @android.ravenwood.annotation.RavenwoodKeepWholeClass
71 public class PlatformCompat extends IPlatformCompat.Stub {
72 
73     private static final String TAG = "Compatibility";
74 
75     private final Context mContext;
76     private final ChangeReporter mChangeReporter;
77     private final CompatConfig mCompatConfig;
78     private final AndroidBuildClassifier mBuildClassifier;
79     private Boolean mIsWear;
80 
PlatformCompat(Context context)81     public PlatformCompat(Context context) {
82         super(PermissionEnforcer.fromContext(context));
83         mContext = context;
84         mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
85         mBuildClassifier = new AndroidBuildClassifier();
86         mCompatConfig = CompatConfig.create(mBuildClassifier, mContext);
87     }
88 
89     @VisibleForTesting
PlatformCompat(Context context, CompatConfig compatConfig, AndroidBuildClassifier buildClassifier, ChangeReporter changeReporter)90     PlatformCompat(Context context, CompatConfig compatConfig,
91             AndroidBuildClassifier buildClassifier,
92             ChangeReporter changeReporter) {
93         super(PermissionEnforcer.fromContext(context));
94         mContext = context;
95         mChangeReporter = changeReporter;
96         mCompatConfig = compatConfig;
97         mBuildClassifier = buildClassifier;
98 
99         registerPackageReceiver(context);
100     }
101 
102     @Override
103     @EnforcePermission(LOG_COMPAT_CHANGE)
reportChange(long changeId, ApplicationInfo appInfo)104     public void reportChange(long changeId, ApplicationInfo appInfo) {
105         super.reportChange_enforcePermission();
106         reportChangeInternal(
107                 changeId,
108                 appInfo.uid,
109                 appInfo.isSystemApp(),
110                 ChangeReporter.STATE_LOGGED);
111     }
112 
113     @Override
114     @EnforcePermission(LOG_COMPAT_CHANGE)
reportChangeByPackageName(long changeId, String packageName, @UserIdInt int userId)115     public void reportChangeByPackageName(long changeId, String packageName,
116             @UserIdInt int userId) {
117         super.reportChangeByPackageName_enforcePermission();
118 
119         ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
120         if (appInfo != null) {
121             reportChangeInternal(
122                     changeId,
123                     appInfo.uid,
124                     appInfo.isSystemApp(),
125                     ChangeReporter.STATE_LOGGED);
126         }
127     }
128 
129     @Override
130     @EnforcePermission(LOG_COMPAT_CHANGE)
reportChangeByUid(long changeId, int uid)131     public void reportChangeByUid(long changeId, int uid) {
132         super.reportChangeByUid_enforcePermission();
133 
134         reportChangeInternal(changeId, uid, false, ChangeReporter.STATE_LOGGED);
135     }
136 
137     /**
138      * Report the change, but skip over the sdk target version check. This can be used to force the
139      * debug logs.
140      *
141      * @param changeId        of the change to report
142      * @param uid             of the user
143      * @param state           of the change - enabled/disabled/logged
144      */
reportChangeInternal(long changeId, int uid, boolean isKnownSystemApp, int state)145     private void reportChangeInternal(long changeId, int uid, boolean isKnownSystemApp, int state) {
146         mChangeReporter.reportChange(uid, changeId, state, isKnownSystemApp, true);
147     }
148 
149     @Override
150     @EnforcePermission(allOf = {LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG})
isChangeEnabled(long changeId, ApplicationInfo appInfo)151     public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
152         super.isChangeEnabled_enforcePermission();
153 
154         return isChangeEnabledInternal(changeId, appInfo);
155     }
156 
157     @Override
158     @EnforcePermission(allOf = {LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG})
isChangeEnabledByPackageName(long changeId, String packageName, @UserIdInt int userId)159     public boolean isChangeEnabledByPackageName(long changeId, String packageName,
160             @UserIdInt int userId) {
161         super.isChangeEnabledByPackageName_enforcePermission();
162 
163         ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
164         if (appInfo == null) {
165             return mCompatConfig.willChangeBeEnabled(changeId, packageName);
166         }
167         return isChangeEnabledInternal(changeId, appInfo);
168     }
169 
170     @Override
171     @EnforcePermission(allOf = {LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG})
isChangeEnabledByUid(long changeId, int uid)172     public boolean isChangeEnabledByUid(long changeId, int uid) {
173         super.isChangeEnabledByUid_enforcePermission();
174 
175         return isChangeEnabledByUidInternal(changeId, uid);
176     }
177 
178     /**
179      * Internal version of the above method, without logging.
180      *
181      * <p>Does not perform costly permission check.
182      * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property.
183      */
isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo)184     public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) {
185         return mCompatConfig.isChangeEnabled(changeId, appInfo);
186     }
187 
188     /**
189      * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}. If the provided appInfo
190      * is not null, also reports the change.
191      *
192      * @param changeId of the change to report
193      * @param appInfo  the app to check
194      *
195      * <p>Does not perform costly permission check.
196      */
isChangeEnabledInternal(long changeId, ApplicationInfo appInfo)197     public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
198         // Fetch the CompatChange. This is done here instead of in mCompatConfig to avoid multiple
199         // fetches.
200         CompatChange c = mCompatConfig.getCompatChange(changeId);
201 
202         boolean enabled = mCompatConfig.isChangeEnabled(c, appInfo);
203         int state = enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED;
204         if (appInfo != null) {
205             boolean isTargetingLatestSdk =
206                     mCompatConfig.isChangeTargetingLatestSdk(c, appInfo.targetSdkVersion);
207             mChangeReporter.reportChange(appInfo.uid,
208                     changeId,
209                     state,
210                     appInfo.isSystemApp(),
211                     isTargetingLatestSdk);
212         }
213         return enabled;
214     }
215 
216     /**
217      * Called by the package manager to check if a given change is enabled for a given package name
218      * and the target sdk version while the package is in the parsing state.
219      *
220      * <p>Does not perform costly permission check.
221      *
222      * @param changeId         the ID of the change in question
223      * @param packageName      package name to check for
224      * @param targetSdkVersion target sdk version to check for
225      * @return {@code true} if the change would be enabled for this package name.
226      */
isChangeEnabledInternal(long changeId, String packageName, int targetSdkVersion)227     public boolean isChangeEnabledInternal(long changeId, String packageName,
228             int targetSdkVersion) {
229         if (mCompatConfig.willChangeBeEnabled(changeId, packageName)) {
230             final ApplicationInfo appInfo = new ApplicationInfo();
231             appInfo.packageName = packageName;
232             appInfo.targetSdkVersion = targetSdkVersion;
233             return isChangeEnabledInternalNoLogging(changeId, appInfo);
234         }
235         return false;
236     }
237 
238     /**
239      * Internal version of {@link #isChangeEnabledByUid(long, int)}.
240      *
241      * <p>Does not perform costly permission check.
242      */
isChangeEnabledByUidInternal(long changeId, int uid)243     public boolean isChangeEnabledByUidInternal(long changeId, int uid) {
244         String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
245         if (packages == null || packages.length == 0) {
246             return mCompatConfig.defaultChangeIdValue(changeId);
247         }
248         boolean enabled = true;
249         final int userId = UserHandle.getUserId(uid);
250         for (String packageName : packages) {
251             final var appInfo =
252                 fixTargetSdk(getApplicationInfo(packageName, userId), uid);
253             enabled &= isChangeEnabledInternal(changeId, appInfo);
254         }
255         return enabled;
256     }
257 
258     /**
259      * Internal version of {@link #isChangeEnabledByUid(long, int)}.
260      *
261      * <p>Does not perform costly permission check and logging.
262      */
isChangeEnabledByUidInternalNoLogging(long changeId, int uid)263     public boolean isChangeEnabledByUidInternalNoLogging(long changeId, int uid) {
264         String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
265         if (packages == null || packages.length == 0) {
266             return mCompatConfig.defaultChangeIdValue(changeId);
267         }
268         boolean enabled = true;
269         final int userId = UserHandle.getUserId(uid);
270         for (String packageName : packages) {
271             final var appInfo =
272                 fixTargetSdk(getApplicationInfo(packageName, userId), uid);
273             enabled &= isChangeEnabledInternalNoLogging(changeId, appInfo);
274         }
275         return enabled;
276     }
277 
278     @Override
279     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
setOverrides(CompatibilityChangeConfig overrides, String packageName)280     public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
281         super.setOverrides_enforcePermission();
282 
283         Map<Long, PackageOverride> overridesMap = new HashMap<>();
284         for (long change : overrides.enabledChanges()) {
285             overridesMap.put(change, new PackageOverride.Builder().setEnabled(true).build());
286         }
287         for (long change : overrides.disabledChanges()) {
288             overridesMap.put(change, new PackageOverride.Builder().setEnabled(false)
289                     .build());
290         }
291         mCompatConfig.addPackageOverrides(new CompatibilityOverrideConfig(overridesMap),
292                 packageName, /* skipUnknownChangeIds */ false);
293         killPackage(packageName);
294     }
295 
296     @Override
297     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)298     public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
299         super.setOverridesForTest_enforcePermission();
300 
301         Map<Long, PackageOverride> overridesMap = new HashMap<>();
302         for (long change : overrides.enabledChanges()) {
303             overridesMap.put(change, new PackageOverride.Builder().setEnabled(true).build());
304         }
305         for (long change : overrides.disabledChanges()) {
306             overridesMap.put(change, new PackageOverride.Builder().setEnabled(false)
307                     .build());
308         }
309         mCompatConfig.addPackageOverrides(new CompatibilityOverrideConfig(overridesMap),
310                 packageName, /* skipUnknownChangeIds */ false);
311     }
312 
313     @Override
314     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
putAllOverridesOnReleaseBuilds( CompatibilityOverridesByPackageConfig overridesByPackage)315     public void putAllOverridesOnReleaseBuilds(
316             CompatibilityOverridesByPackageConfig overridesByPackage) {
317         super.putAllOverridesOnReleaseBuilds_enforcePermission();
318 
319         for (CompatibilityOverrideConfig overrides :
320                 overridesByPackage.packageNameToOverrides.values()) {
321             checkAllCompatOverridesAreOverridable(overrides.overrides.keySet());
322         }
323         mCompatConfig.addAllPackageOverrides(overridesByPackage, /* skipUnknownChangeIds= */ true);
324     }
325 
326     @Override
327     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
putOverridesOnReleaseBuilds(CompatibilityOverrideConfig overrides, String packageName)328     public void putOverridesOnReleaseBuilds(CompatibilityOverrideConfig overrides,
329             String packageName) {
330         super.putOverridesOnReleaseBuilds_enforcePermission();
331 
332         checkAllCompatOverridesAreOverridable(overrides.overrides.keySet());
333         mCompatConfig.addPackageOverrides(overrides, packageName, /* skipUnknownChangeIds= */ true);
334     }
335 
336     @Override
337     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
enableTargetSdkChanges(String packageName, int targetSdkVersion)338     public int enableTargetSdkChanges(String packageName, int targetSdkVersion) {
339         super.enableTargetSdkChanges_enforcePermission();
340 
341         int numChanges =
342                 mCompatConfig.enableTargetSdkChangesForPackage(packageName, targetSdkVersion);
343         killPackage(packageName);
344         return numChanges;
345     }
346 
347     @Override
348     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
disableTargetSdkChanges(String packageName, int targetSdkVersion)349     public int disableTargetSdkChanges(String packageName, int targetSdkVersion) {
350         super.disableTargetSdkChanges_enforcePermission();
351 
352         int numChanges =
353                 mCompatConfig.disableTargetSdkChangesForPackage(packageName, targetSdkVersion);
354         killPackage(packageName);
355         return numChanges;
356     }
357 
358     @Override
359     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
clearOverrides(String packageName)360     public void clearOverrides(String packageName) {
361         super.clearOverrides_enforcePermission();
362 
363         mCompatConfig.removePackageOverrides(packageName);
364         killPackage(packageName);
365     }
366 
367     @Override
368     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
clearOverridesForTest(String packageName)369     public void clearOverridesForTest(String packageName) {
370         super.clearOverridesForTest_enforcePermission();
371 
372         mCompatConfig.removePackageOverrides(packageName);
373     }
374 
375     @Override
376     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
clearOverride(long changeId, String packageName)377     public boolean clearOverride(long changeId, String packageName) {
378         super.clearOverride_enforcePermission();
379 
380         boolean existed = mCompatConfig.removeOverride(changeId, packageName);
381         killPackage(packageName);
382         return existed;
383     }
384 
385     @Override
386     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
clearOverrideForTest(long changeId, String packageName)387     public boolean clearOverrideForTest(long changeId, String packageName) {
388         super.clearOverrideForTest_enforcePermission();
389 
390         return mCompatConfig.removeOverride(changeId, packageName);
391     }
392 
393     @Override
394     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
removeAllOverridesOnReleaseBuilds( CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage)395     public void removeAllOverridesOnReleaseBuilds(
396             CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage) {
397         super.removeAllOverridesOnReleaseBuilds_enforcePermission();
398 
399         for (CompatibilityOverridesToRemoveConfig overridesToRemove :
400                 overridesToRemoveByPackage.packageNameToOverridesToRemove.values()) {
401             checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds);
402         }
403         mCompatConfig.removeAllPackageOverrides(overridesToRemoveByPackage);
404     }
405 
406     @Override
407     @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
removeOverridesOnReleaseBuilds( CompatibilityOverridesToRemoveConfig overridesToRemove, String packageName)408     public void removeOverridesOnReleaseBuilds(
409             CompatibilityOverridesToRemoveConfig overridesToRemove,
410             String packageName) {
411         super.removeOverridesOnReleaseBuilds_enforcePermission();
412 
413         checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds);
414         mCompatConfig.removePackageOverrides(overridesToRemove, packageName);
415     }
416 
417     @Override
418     @EnforcePermission(allOf = {LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG})
getAppConfig(ApplicationInfo appInfo)419     public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
420         super.getAppConfig_enforcePermission();
421 
422         return mCompatConfig.getAppConfig(appInfo);
423     }
424 
425     @Override
426     @EnforcePermission(READ_COMPAT_CHANGE_CONFIG)
listAllChanges()427     public CompatibilityChangeInfo[] listAllChanges() {
428         super.listAllChanges_enforcePermission();
429 
430         return mCompatConfig.dumpChanges();
431     }
432 
433     @Override
434     @RequiresNoPermission
listUIChanges()435     public CompatibilityChangeInfo[] listUIChanges() {
436         return Arrays.stream(listAllChanges()).filter(this::isShownInUI).toArray(
437                 CompatibilityChangeInfo[]::new);
438     }
439 
440     /** Checks whether the change is known to the compat config. */
isKnownChangeId(long changeId)441     public boolean isKnownChangeId(long changeId) {
442         return mCompatConfig.isKnownChangeId(changeId);
443     }
444 
445     /**
446      * Retrieves the set of disabled changes for a given app. Any change ID not in the returned
447      * array is by default enabled for the app.
448      *
449      * @param appInfo The app in question
450      * @return A sorted long array of change IDs. We use a primitive array to minimize memory
451      * footprint: Every app process will store this array statically so we aim to reduce
452      * overhead as much as possible.
453      */
getDisabledChanges(ApplicationInfo appInfo)454     public long[] getDisabledChanges(ApplicationInfo appInfo) {
455         return mCompatConfig.getDisabledChanges(appInfo);
456     }
457 
458     /**
459      * Retrieves the set of changes that should be logged for a given app. Any change ID not in the
460      * returned array is ignored for logging purposes.
461      *
462      * @param appInfo The app in question
463      * @return A sorted long array of change IDs. We use a primitive array to minimize memory
464      * footprint: Every app process will store this array statically so we aim to reduce
465      * overhead as much as possible.
466      */
getLoggableChanges(ApplicationInfo appInfo)467     public long[] getLoggableChanges(ApplicationInfo appInfo) {
468         return mCompatConfig.getLoggableChanges(appInfo);
469     }
470 
471     /**
472      * Look up a change ID by name.
473      *
474      * @param name Name of the change to look up
475      * @return The change ID, or {@code -1} if no change with that name exists.
476      */
lookupChangeId(String name)477     public long lookupChangeId(String name) {
478         return mCompatConfig.lookupChangeId(name);
479     }
480 
481     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)482     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
483         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) {
484             return;
485         }
486         mContext.enforceCallingOrSelfPermission(
487                 READ_COMPAT_CHANGE_CONFIG, "Cannot read compat change");
488         mContext.enforceCallingOrSelfPermission(
489                 LOG_COMPAT_CHANGE, "Cannot read log compat change usage");
490         mCompatConfig.dumpConfig(pw);
491     }
492 
493     @Override
494     @RequiresNoPermission
getOverrideValidator()495     public IOverrideValidator getOverrideValidator() {
496         return mCompatConfig.getOverrideValidator();
497     }
498 
499     /**
500      * Clears information stored about events reported on behalf of an app.
501      *
502      * <p>To be called once upon app start or end. A second call would be a no-op.
503      *
504      * @param appInfo the app to reset
505      */
resetReporting(ApplicationInfo appInfo)506     public void resetReporting(ApplicationInfo appInfo) {
507         mChangeReporter.resetReportedChanges(appInfo.uid);
508     }
509 
getApplicationInfo(String packageName, int userId)510     private ApplicationInfo getApplicationInfo(String packageName, int userId) {
511         return LocalServices.getService(PackageManagerInternal.class).getApplicationInfo(
512                 packageName, 0, Process.myUid(), userId);
513     }
514 
fixTargetSdk(ApplicationInfo appInfo, int uid)515     private ApplicationInfo fixTargetSdk(ApplicationInfo appInfo, int uid) {
516 
517         // mIsWear doesn't need to be locked, ok if executes twice
518         if (mIsWear == null) {
519             mIsWear = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
520         }
521 
522         // b/282922910 - we don't want apps sharing system uid and targeting
523         // older target sdk to impact all system uid apps
524         if (Flags.systemUidTargetSystemSdk() && !mIsWear &&
525                 uid == Process.SYSTEM_UID && appInfo != null) {
526             appInfo.targetSdkVersion = mBuildClassifier.platformTargetSdk();
527         }
528         return appInfo;
529     }
530 
531     @android.ravenwood.annotation.RavenwoodReplace
killPackage(String packageName)532     private void killPackage(String packageName) {
533         int uid = LocalServices.getService(PackageManagerInternal.class).getPackageUid(packageName,
534                 0, UserHandle.myUserId());
535 
536         if (uid < 0) {
537             Slog.w(TAG, "Didn't find package " + packageName + " on device.");
538             return;
539         }
540 
541         Slog.d(TAG, "Killing package " + packageName + " (UID " + uid + ").");
542         killUid(UserHandle.getAppId(uid));
543     }
544 
545     @SuppressWarnings("unused")
killPackage$ravenwood(String packageName)546     private void killPackage$ravenwood(String packageName) {
547         // TODO Maybe crash if the package is the self.
548         Slog.w(TAG, "killPackage() is ignored on Ravenwood: packageName=" + packageName);
549     }
550 
551     @android.ravenwood.annotation.RavenwoodReplace
killUid(int appId)552     private void killUid(int appId) {
553         final long identity = Binder.clearCallingIdentity();
554         try {
555             IActivityManager am = ActivityManager.getService();
556             if (am != null) {
557                 am.killUid(appId, UserHandle.USER_ALL, "PlatformCompat overrides");
558             }
559         } catch (RemoteException e) {
560             /* ignore - same process */
561         } finally {
562             Binder.restoreCallingIdentity(identity);
563         }
564     }
565 
566     @SuppressWarnings("unused")
killUid$ravenwood(int appId)567     private void killUid$ravenwood(int appId) {
568         // TODO Maybe crash if the UID is the self.
569         Slog.w(TAG, "killUid() is ignored on Ravenwood: appId=" + appId);
570     }
571 
checkAllCompatOverridesAreOverridable(Collection<Long> changeIds)572     private void checkAllCompatOverridesAreOverridable(Collection<Long> changeIds) {
573         for (Long changeId : changeIds) {
574             if (isKnownChangeId(changeId) && !mCompatConfig.isOverridable(changeId)) {
575                 throw new SecurityException("Only change ids marked as Overridable can be "
576                         + "overridden.");
577             }
578         }
579     }
580 
isShownInUI(CompatibilityChangeInfo change)581     private boolean isShownInUI(CompatibilityChangeInfo change) {
582         if (change.getLoggingOnly()) {
583             return false;
584         }
585         if (change.getId() == CompatChange.CTS_SYSTEM_API_CHANGEID) {
586             return false;
587         }
588         if (change.getEnableSinceTargetSdk() > 0) {
589             return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q
590                     && change.getEnableSinceTargetSdk() <= mBuildClassifier.platformTargetSdk();
591         }
592         return true;
593     }
594 
595     /**
596      * Registers a listener for change state overrides.
597      *
598      * <p>Only one listener per change is allowed.
599      *
600      * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with
601      * packageName before the app is killed upon an override change. The state of a change is not
602      * guaranteed to change when {@code listener.onCompatChange(String)} is called.
603      *
604      * @param changeId to get updates for
605      * @param listener the listener that will be called upon a potential change for package
606      * @return {@code true} if a change with changeId was already known, or (@code false}
607      * otherwise
608      * @throws IllegalStateException if a listener was already registered for changeId
609      */
registerListener(long changeId, CompatChange.ChangeListener listener)610     public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
611         return mCompatConfig.registerListener(changeId, listener);
612     }
613 
614     /**
615      * Registers a broadcast receiver that listens for package install, replace or remove.
616      *
617      * @param context the context where the receiver should be registered
618      */
registerPackageReceiver(Context context)619     public void registerPackageReceiver(Context context) {
620         final BroadcastReceiver receiver = new BroadcastReceiver() {
621             @Override
622             public void onReceive(Context context, Intent intent) {
623                 if (intent == null) {
624                     return;
625                 }
626                 final Uri packageData = intent.getData();
627                 if (packageData == null) {
628                     return;
629                 }
630                 final String packageName = packageData.getSchemeSpecificPart();
631                 if (packageName == null) {
632                     return;
633                 }
634                 mCompatConfig.recheckOverrides(packageName);
635             }
636         };
637         IntentFilter filter = new IntentFilter();
638         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
639         filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
640         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
641         filter.addDataScheme("package");
642         context.registerReceiverForAllUsers(receiver, filter, /* broadcastPermission= */
643                 null, /* scheduler= */ null);
644     }
645 
646     /**
647      * Registers the observer for
648      * {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT}.
649      */
registerContentObserver()650     public void registerContentObserver() {
651         mCompatConfig.registerContentObserver();
652     }
653 }
654