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