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.policy; 18 19 import static android.app.AppOpsManager.MODE_ALLOWED; 20 import static android.app.AppOpsManager.MODE_FOREGROUND; 21 import static android.app.AppOpsManager.MODE_IGNORED; 22 import static android.app.AppOpsManager.OP_NONE; 23 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; 24 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; 25 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT; 26 import static android.content.pm.PackageManager.GET_PERMISSIONS; 27 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.annotation.UserIdInt; 31 import android.app.AppOpsManager; 32 import android.app.AppOpsManagerInternal; 33 import android.content.BroadcastReceiver; 34 import android.content.ContentResolver; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.IntentFilter; 38 import android.content.pm.ApplicationInfo; 39 import android.content.pm.PackageInfo; 40 import android.content.pm.PackageManager; 41 import android.content.pm.PackageManager.NameNotFoundException; 42 import android.content.pm.PackageManagerInternal; 43 import android.content.pm.PackageManagerInternal.PackageListObserver; 44 import android.content.pm.PermissionInfo; 45 import android.os.Build; 46 import android.os.Process; 47 import android.os.RemoteException; 48 import android.os.ServiceManager; 49 import android.os.UserHandle; 50 import android.permission.PermissionControllerManager; 51 import android.provider.Settings; 52 import android.provider.Telephony; 53 import android.telecom.TelecomManager; 54 import android.util.ArrayMap; 55 import android.util.ArraySet; 56 import android.util.LongSparseLongArray; 57 import android.util.Pair; 58 import android.util.Slog; 59 import android.util.SparseBooleanArray; 60 61 import com.android.internal.annotations.GuardedBy; 62 import com.android.internal.app.IAppOpsCallback; 63 import com.android.internal.app.IAppOpsService; 64 import com.android.internal.infra.AndroidFuture; 65 import com.android.internal.util.IntPair; 66 import com.android.internal.util.function.pooled.PooledLambda; 67 import com.android.server.FgThread; 68 import com.android.server.LocalServices; 69 import com.android.server.SystemService; 70 import com.android.server.pm.UserManagerInternal; 71 import com.android.server.pm.parsing.pkg.AndroidPackage; 72 import com.android.server.pm.permission.PermissionManagerServiceInternal; 73 import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback; 74 75 import java.util.ArrayList; 76 import java.util.Collections; 77 import java.util.HashMap; 78 import java.util.List; 79 import java.util.Map; 80 import java.util.concurrent.ExecutionException; 81 82 /** 83 * This is a permission policy that governs over all permission mechanism 84 * such as permissions, app ops, etc. For example, the policy ensures that 85 * permission state and app ops is synchronized for cases where there is a 86 * dependency between permission state (permissions or permission flags) 87 * and app ops - and vise versa. 88 */ 89 public final class PermissionPolicyService extends SystemService { 90 private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName(); 91 private static final boolean DEBUG = false; 92 private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 60000; 93 94 private final Object mLock = new Object(); 95 96 private IAppOpsCallback mAppOpsCallback; 97 98 /** Whether the user is started but not yet stopped */ 99 @GuardedBy("mLock") 100 private final SparseBooleanArray mIsStarted = new SparseBooleanArray(); 101 102 /** Callbacks for when a user is initialized */ 103 @GuardedBy("mLock") 104 private OnInitializedCallback mOnInitializedCallback; 105 106 /** 107 * Whether an async {@link #synchronizePackagePermissionsAndAppOpsForUser} is currently 108 * scheduled for a package/user. 109 */ 110 @GuardedBy("mLock") 111 private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>(); 112 113 /** 114 * Whether an async {@link #resetAppOpPermissionsIfNotRequestedForUid} is currently 115 * scheduled for a uid. 116 */ 117 @GuardedBy("mLock") 118 private final SparseBooleanArray mIsUidSyncScheduled = new SparseBooleanArray(); 119 120 private List<String> mAppOpPermissions; 121 PermissionPolicyService(@onNull Context context)122 public PermissionPolicyService(@NonNull Context context) { 123 super(context); 124 125 LocalServices.addService(PermissionPolicyInternal.class, new Internal()); 126 } 127 128 @Override onStart()129 public void onStart() { 130 final PackageManagerInternal packageManagerInternal = LocalServices.getService( 131 PackageManagerInternal.class); 132 final PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService( 133 PermissionManagerServiceInternal.class); 134 final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface( 135 ServiceManager.getService(Context.APP_OPS_SERVICE)); 136 137 packageManagerInternal.getPackageList(new PackageListObserver() { 138 @Override 139 public void onPackageAdded(String packageName, int uid) { 140 final int userId = UserHandle.getUserId(uid); 141 if (isStarted(userId)) { 142 synchronizePackagePermissionsAndAppOpsForUser(packageName, userId); 143 } 144 } 145 146 @Override 147 public void onPackageChanged(String packageName, int uid) { 148 final int userId = UserHandle.getUserId(uid); 149 if (isStarted(userId)) { 150 synchronizePackagePermissionsAndAppOpsForUser(packageName, userId); 151 resetAppOpPermissionsIfNotRequestedForUid(uid); 152 } 153 } 154 155 @Override 156 public void onPackageRemoved(String packageName, int uid) { 157 final int userId = UserHandle.getUserId(uid); 158 if (isStarted(userId)) { 159 resetAppOpPermissionsIfNotRequestedForUid(uid); 160 } 161 } 162 }); 163 164 permissionManagerInternal.addOnRuntimePermissionStateChangedListener( 165 this::synchronizePackagePermissionsAndAppOpsAsyncForUser); 166 167 mAppOpsCallback = new IAppOpsCallback.Stub() { 168 public void opChanged(int op, int uid, String packageName) { 169 synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName, 170 UserHandle.getUserId(uid)); 171 resetAppOpPermissionsIfNotRequestedForUidAsync(uid); 172 } 173 }; 174 175 final ArrayList<PermissionInfo> dangerousPerms = 176 permissionManagerInternal.getAllPermissionsWithProtection( 177 PermissionInfo.PROTECTION_DANGEROUS); 178 try { 179 int numDangerousPerms = dangerousPerms.size(); 180 for (int i = 0; i < numDangerousPerms; i++) { 181 PermissionInfo perm = dangerousPerms.get(i); 182 183 if (perm.isRuntime()) { 184 appOpsService.startWatchingMode(getSwitchOp(perm.name), null, mAppOpsCallback); 185 } 186 if (perm.isSoftRestricted()) { 187 SoftRestrictedPermissionPolicy policy = 188 SoftRestrictedPermissionPolicy.forPermission(null, null, null, 189 null, perm.name); 190 int extraAppOp = policy.getExtraAppOpCode(); 191 if (extraAppOp != OP_NONE) { 192 appOpsService.startWatchingMode(extraAppOp, null, mAppOpsCallback); 193 } 194 } 195 } 196 } catch (RemoteException doesNotHappen) { 197 Slog.wtf(LOG_TAG, "Cannot set up app-ops listener"); 198 } 199 200 final List<PermissionInfo> appOpPermissionInfos = 201 permissionManagerInternal.getAllPermissionsWithProtectionFlags( 202 PermissionInfo.PROTECTION_FLAG_APPOP); 203 mAppOpPermissions = new ArrayList<>(); 204 final int appOpPermissionInfosSize = appOpPermissionInfos.size(); 205 for (int i = 0; i < appOpPermissionInfosSize; i++) { 206 final PermissionInfo appOpPermissionInfo = appOpPermissionInfos.get(i); 207 208 switch (appOpPermissionInfo.name) { 209 case android.Manifest.permission.ACCESS_NOTIFICATIONS: 210 case android.Manifest.permission.MANAGE_IPSEC_TUNNELS: 211 continue; 212 case android.Manifest.permission.REQUEST_INSTALL_PACKAGES: 213 // Settings allows the user to control the app op if it's not in the default 214 // mode, regardless of whether the app has requested the permission, so we 215 // should not reset it. 216 continue; 217 default: 218 final int appOpCode = AppOpsManager.permissionToOpCode( 219 appOpPermissionInfo.name); 220 if (appOpCode != OP_NONE) { 221 mAppOpPermissions.add(appOpPermissionInfo.name); 222 try { 223 appOpsService.startWatchingMode(appOpCode, null, mAppOpsCallback); 224 } catch (RemoteException e) { 225 Slog.wtf(LOG_TAG, "Cannot set up app-ops listener", e); 226 } 227 } 228 } 229 } 230 231 IntentFilter intentFilter = new IntentFilter(); 232 intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 233 intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 234 intentFilter.addDataScheme("package"); 235 236 getContext().registerReceiverAsUser(new BroadcastReceiver() { 237 final List<Integer> mUserSetupUids = new ArrayList<>(200); 238 final Map<UserHandle, PermissionControllerManager> mPermControllerManagers = 239 new HashMap<>(); 240 241 @Override 242 public void onReceive(Context context, Intent intent) { 243 boolean hasSetupRun = true; 244 try { 245 final ContentResolver cr = getContext().getContentResolver(); 246 hasSetupRun = Settings.Secure.getIntForUser(cr, 247 Settings.Secure.USER_SETUP_COMPLETE, cr.getUserId()) != 0; 248 } catch (Settings.SettingNotFoundException e) { 249 // Ignore error, assume setup has run 250 } 251 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 252 // If there is no valid package for the given UID, return immediately 253 if (packageManagerInternal.getPackage(uid) == null) { 254 return; 255 } 256 257 if (hasSetupRun) { 258 if (!mUserSetupUids.isEmpty()) { 259 synchronized (mUserSetupUids) { 260 for (int i = mUserSetupUids.size() - 1; i >= 0; i--) { 261 updateUid(mUserSetupUids.get(i)); 262 } 263 mUserSetupUids.clear(); 264 } 265 } 266 updateUid(uid); 267 } else { 268 synchronized (mUserSetupUids) { 269 if (!mUserSetupUids.contains(uid)) { 270 mUserSetupUids.add(uid); 271 } 272 } 273 } 274 } 275 276 private void updateUid(int uid) { 277 UserHandle user = UserHandle.getUserHandleForUid(uid); 278 PermissionControllerManager manager = mPermControllerManagers.get(user); 279 if (manager == null) { 280 manager = new PermissionControllerManager( 281 getUserContext(getContext(), user), FgThread.getHandler()); 282 mPermControllerManagers.put(user, manager); 283 } 284 manager.updateUserSensitiveForApp(uid); 285 } 286 }, UserHandle.ALL, intentFilter, null, null); 287 288 PermissionControllerManager manager = new PermissionControllerManager( 289 getUserContext(getContext(), Process.myUserHandle()), FgThread.getHandler()); 290 FgThread.getHandler().postDelayed(manager::updateUserSensitive, 291 USER_SENSITIVE_UPDATE_DELAY_MS); 292 } 293 294 /** 295 * Get op that controls the access related to the permission. 296 * 297 * <p>Usually the permission-op relationship is 1:1 but some permissions (e.g. fine location) 298 * {@link AppOpsManager#sOpToSwitch share an op} to control the access. 299 * 300 * @param permission The permission 301 * @return The op that controls the access of the permission 302 */ getSwitchOp(@onNull String permission)303 private static int getSwitchOp(@NonNull String permission) { 304 int op = AppOpsManager.permissionToOpCode(permission); 305 if (op == OP_NONE) { 306 return OP_NONE; 307 } 308 309 return AppOpsManager.opToSwitch(op); 310 } 311 synchronizePackagePermissionsAndAppOpsAsyncForUser(@onNull String packageName, @UserIdInt int changedUserId)312 private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName, 313 @UserIdInt int changedUserId) { 314 if (isStarted(changedUserId)) { 315 synchronized (mLock) { 316 if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) { 317 FgThread.getHandler().sendMessage(PooledLambda.obtainMessage( 318 PermissionPolicyService 319 ::synchronizePackagePermissionsAndAppOpsForUser, 320 this, packageName, changedUserId)); 321 } else { 322 if (DEBUG) { 323 Slog.v(LOG_TAG, "sync for " + packageName + "/" + changedUserId 324 + " already scheduled"); 325 } 326 } 327 } 328 } 329 } 330 331 @Override onBootPhase(int phase)332 public void onBootPhase(int phase) { 333 if (DEBUG) Slog.i(LOG_TAG, "onBootPhase(" + phase + ")"); 334 335 if (phase == PHASE_ACTIVITY_MANAGER_READY) { 336 final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class); 337 338 // For some users we might not receive a onStartUser, hence force one here 339 for (int userId : um.getUserIds()) { 340 if (um.isUserRunning(userId)) { 341 onStartUser(userId); 342 } 343 } 344 } 345 } 346 347 /** 348 * @return Whether the user is started but not yet stopped 349 */ isStarted(@serIdInt int userId)350 private boolean isStarted(@UserIdInt int userId) { 351 synchronized (mLock) { 352 return mIsStarted.get(userId); 353 } 354 } 355 356 @Override onUserStarting(@onNull TargetUser user)357 public void onUserStarting(@NonNull TargetUser user) { 358 onStartUser(user.getUserIdentifier()); 359 } 360 onStartUser(@serIdInt int userId)361 private void onStartUser(@UserIdInt int userId) { 362 if (DEBUG) Slog.i(LOG_TAG, "onStartUser(" + userId + ")"); 363 364 if (isStarted(userId)) { 365 return; 366 } 367 368 grantOrUpgradeDefaultRuntimePermissionsIfNeeded(userId); 369 370 final OnInitializedCallback callback; 371 372 synchronized (mLock) { 373 mIsStarted.put(userId, true); 374 callback = mOnInitializedCallback; 375 } 376 377 // Force synchronization as permissions might have changed 378 synchronizePermissionsAndAppOpsForUser(userId); 379 380 // Tell observers we are initialized for this user. 381 if (callback != null) { 382 callback.onInitialized(userId); 383 } 384 } 385 386 @Override onUserStopping(@onNull TargetUser user)387 public void onUserStopping(@NonNull TargetUser user) { 388 if (DEBUG) Slog.i(LOG_TAG, "onStopUser(" + user + ")"); 389 390 synchronized (mLock) { 391 mIsStarted.delete(user.getUserIdentifier()); 392 } 393 } 394 grantOrUpgradeDefaultRuntimePermissionsIfNeeded(@serIdInt int userId)395 private void grantOrUpgradeDefaultRuntimePermissionsIfNeeded(@UserIdInt int userId) { 396 if (DEBUG) Slog.i(LOG_TAG, "grantOrUpgradeDefaultPermsIfNeeded(" + userId + ")"); 397 398 final PackageManagerInternal packageManagerInternal = 399 LocalServices.getService(PackageManagerInternal.class); 400 final PermissionManagerServiceInternal permissionManagerInternal = 401 LocalServices.getService(PermissionManagerServiceInternal.class); 402 if (packageManagerInternal.isPermissionUpgradeNeeded(userId)) { 403 if (DEBUG) Slog.i(LOG_TAG, "defaultPermsWereGrantedSinceBoot(" + userId + ")"); 404 405 // Now call into the permission controller to apply policy around permissions 406 final AndroidFuture<Boolean> future = new AndroidFuture<>(); 407 408 // We need to create a local manager that does not schedule work on the main 409 // there as we are on the main thread and want to block until the work is 410 // completed or we time out. 411 final PermissionControllerManager permissionControllerManager = 412 new PermissionControllerManager( 413 getUserContext(getContext(), UserHandle.of(userId)), 414 FgThread.getHandler()); 415 permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions( 416 FgThread.getExecutor(), successful -> { 417 if (successful) { 418 future.complete(null); 419 } else { 420 // We are in an undefined state now, let us crash and have 421 // rescue party suggest a wipe to recover to a good one. 422 final String message = "Error granting/upgrading runtime permissions" 423 + " for user " + userId; 424 Slog.wtf(LOG_TAG, message); 425 future.completeExceptionally(new IllegalStateException(message)); 426 } 427 }); 428 try { 429 future.get(); 430 } catch (InterruptedException | ExecutionException e) { 431 throw new IllegalStateException(e); 432 } 433 434 permissionControllerManager.updateUserSensitive(); 435 436 packageManagerInternal.updateRuntimePermissionsFingerprint(userId); 437 } 438 } 439 getUserContext(@onNull Context context, @Nullable UserHandle user)440 private static @Nullable Context getUserContext(@NonNull Context context, 441 @Nullable UserHandle user) { 442 if (context.getUser().equals(user)) { 443 return context; 444 } else { 445 try { 446 return context.createPackageContextAsUser(context.getPackageName(), 0, user); 447 } catch (NameNotFoundException e) { 448 Slog.e(LOG_TAG, "Cannot create context for user " + user, e); 449 return null; 450 } 451 } 452 } 453 454 /** 455 * Synchronize a single package. 456 */ synchronizePackagePermissionsAndAppOpsForUser(@onNull String packageName, @UserIdInt int userId)457 private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName, 458 @UserIdInt int userId) { 459 synchronized (mLock) { 460 mIsPackageSyncsScheduled.remove(new Pair<>(packageName, userId)); 461 } 462 463 if (DEBUG) { 464 Slog.v(LOG_TAG, 465 "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", " 466 + userId + ")"); 467 } 468 469 final PackageManagerInternal packageManagerInternal = LocalServices.getService( 470 PackageManagerInternal.class); 471 final PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 0, 472 Process.SYSTEM_UID, userId); 473 if (pkg == null) { 474 return; 475 } 476 final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser( 477 getUserContext(getContext(), UserHandle.of(userId))); 478 synchroniser.addPackage(pkg.packageName); 479 final String[] sharedPkgNames = packageManagerInternal.getSharedUserPackagesForPackage( 480 pkg.packageName, userId); 481 482 for (String sharedPkgName : sharedPkgNames) { 483 final AndroidPackage sharedPkg = packageManagerInternal 484 .getPackage(sharedPkgName); 485 if (sharedPkg != null) { 486 synchroniser.addPackage(sharedPkg.getPackageName()); 487 } 488 } 489 synchroniser.syncPackages(); 490 } 491 492 /** 493 * Synchronize all packages 494 */ synchronizePermissionsAndAppOpsForUser(@serIdInt int userId)495 private void synchronizePermissionsAndAppOpsForUser(@UserIdInt int userId) { 496 if (DEBUG) Slog.i(LOG_TAG, "synchronizePermissionsAndAppOpsForUser(" + userId + ")"); 497 498 final PackageManagerInternal packageManagerInternal = LocalServices.getService( 499 PackageManagerInternal.class); 500 final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser( 501 getUserContext(getContext(), UserHandle.of(userId))); 502 packageManagerInternal.forEachPackage( 503 (pkg) -> synchronizer.addPackage(pkg.getPackageName())); 504 synchronizer.syncPackages(); 505 } 506 resetAppOpPermissionsIfNotRequestedForUidAsync(int uid)507 private void resetAppOpPermissionsIfNotRequestedForUidAsync(int uid) { 508 if (isStarted(UserHandle.getUserId(uid))) { 509 synchronized (mLock) { 510 if (!mIsUidSyncScheduled.get(uid)) { 511 mIsUidSyncScheduled.put(uid, true); 512 FgThread.getHandler().sendMessage(PooledLambda.obtainMessage( 513 PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid, 514 this, uid)); 515 } 516 } 517 } 518 } 519 resetAppOpPermissionsIfNotRequestedForUid(int uid)520 private void resetAppOpPermissionsIfNotRequestedForUid(int uid) { 521 synchronized (mLock) { 522 mIsUidSyncScheduled.delete(uid); 523 } 524 525 final Context context = getContext(); 526 final PackageManager userPackageManager = getUserContext(context, 527 UserHandle.getUserHandleForUid(uid)).getPackageManager(); 528 final String[] packageNames = userPackageManager.getPackagesForUid(uid); 529 if (packageNames == null || packageNames.length == 0) { 530 return; 531 } 532 533 final ArraySet<String> requestedPermissions = new ArraySet<>(); 534 for (String packageName : packageNames) { 535 final PackageInfo packageInfo; 536 try { 537 packageInfo = userPackageManager.getPackageInfo(packageName, GET_PERMISSIONS); 538 } catch (NameNotFoundException e) { 539 continue; 540 } 541 if (packageInfo == null || packageInfo.requestedPermissions == null) { 542 continue; 543 } 544 Collections.addAll(requestedPermissions, packageInfo.requestedPermissions); 545 } 546 547 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 548 final AppOpsManagerInternal appOpsManagerInternal = LocalServices.getService( 549 AppOpsManagerInternal.class); 550 final int appOpPermissionsSize = mAppOpPermissions.size(); 551 for (int i = 0; i < appOpPermissionsSize; i++) { 552 final String appOpPermission = mAppOpPermissions.get(i); 553 554 if (!requestedPermissions.contains(appOpPermission)) { 555 final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermission); 556 final int defaultAppOpMode = AppOpsManager.opToDefaultMode(appOpCode); 557 for (String packageName : packageNames) { 558 final int appOpMode = appOpsManager.unsafeCheckOpRawNoThrow(appOpCode, uid, 559 packageName); 560 if (appOpMode != defaultAppOpMode) { 561 appOpsManagerInternal.setUidModeFromPermissionPolicy(appOpCode, uid, 562 defaultAppOpMode, mAppOpsCallback); 563 appOpsManagerInternal.setModeFromPermissionPolicy(appOpCode, uid, 564 packageName, defaultAppOpMode, mAppOpsCallback); 565 } 566 } 567 } 568 } 569 } 570 571 /** 572 * Synchronizes permission to app ops. You *must* always sync all packages 573 * in a shared UID at the same time to ensure proper synchronization. 574 */ 575 private class PermissionToOpSynchroniser { 576 private final @NonNull Context mContext; 577 private final @NonNull PackageManager mPackageManager; 578 private final @NonNull AppOpsManager mAppOpsManager; 579 private final @NonNull AppOpsManagerInternal mAppOpsManagerInternal; 580 581 private final @NonNull ArrayMap<String, PermissionInfo> mRuntimeAndTheirBgPermissionInfos; 582 583 /** 584 * All ops that need to be flipped to allow. 585 * 586 * @see #syncPackages 587 */ 588 private final @NonNull ArrayList<OpToChange> mOpsToAllow = new ArrayList<>(); 589 590 /** 591 * All ops that need to be flipped to ignore. 592 * 593 * @see #syncPackages 594 */ 595 private final @NonNull ArrayList<OpToChange> mOpsToIgnore = new ArrayList<>(); 596 597 /** 598 * All ops that need to be flipped to ignore if not allowed. 599 * 600 * Currently, only used by soft restricted permissions logic. 601 * 602 * @see #syncPackages 603 */ 604 private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfNotAllowed = new ArrayList<>(); 605 606 /** 607 * All ops that need to be flipped to foreground. 608 * 609 * Currently, only used by the foreground/background permissions logic. 610 * 611 * @see #syncPackages 612 */ 613 private final @NonNull ArrayList<OpToChange> mOpsToForeground = new ArrayList<>(); 614 PermissionToOpSynchroniser(@onNull Context context)615 PermissionToOpSynchroniser(@NonNull Context context) { 616 mContext = context; 617 mPackageManager = context.getPackageManager(); 618 mAppOpsManager = context.getSystemService(AppOpsManager.class); 619 mAppOpsManagerInternal = LocalServices.getService(AppOpsManagerInternal.class); 620 621 mRuntimeAndTheirBgPermissionInfos = new ArrayMap<>(); 622 PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService( 623 PermissionManagerServiceInternal.class); 624 List<PermissionInfo> permissionInfos = 625 permissionManagerInternal.getAllPermissionsWithProtection( 626 PermissionInfo.PROTECTION_DANGEROUS); 627 int permissionInfosSize = permissionInfos.size(); 628 for (int i = 0; i < permissionInfosSize; i++) { 629 PermissionInfo permissionInfo = permissionInfos.get(i); 630 mRuntimeAndTheirBgPermissionInfos.put(permissionInfo.name, permissionInfo); 631 // Make sure we scoop up all background permissions as they may not be runtime 632 if (permissionInfo.backgroundPermission != null) { 633 String backgroundNonRuntimePermission = permissionInfo.backgroundPermission; 634 for (int j = 0; j < permissionInfosSize; j++) { 635 PermissionInfo bgPermissionCandidate = permissionInfos.get(j); 636 if (permissionInfo.backgroundPermission.equals( 637 bgPermissionCandidate.name)) { 638 backgroundNonRuntimePermission = null; 639 break; 640 } 641 } 642 if (backgroundNonRuntimePermission != null) { 643 try { 644 PermissionInfo backgroundPermissionInfo = mPackageManager 645 .getPermissionInfo(backgroundNonRuntimePermission, 0); 646 mRuntimeAndTheirBgPermissionInfos.put(backgroundPermissionInfo.name, 647 backgroundPermissionInfo); 648 } catch (NameNotFoundException e) { 649 Slog.w(LOG_TAG, "Unknown background permission: " 650 + backgroundNonRuntimePermission); 651 } 652 } 653 } 654 } 655 } 656 657 /** 658 * Set app ops that were added in {@link #addPackage}. 659 * 660 * <p>This processes ops previously added by {@link #addAppOps(PackageInfo, String)} 661 */ syncPackages()662 private void syncPackages() { 663 // Remember which ops were already set. This makes sure that we always set the most 664 // permissive mode if two OpChanges are scheduled. This can e.g. happen if two 665 // permissions change the same op. See {@link #getSwitchOp}. 666 LongSparseLongArray alreadySetAppOps = new LongSparseLongArray(); 667 668 final int allowCount = mOpsToAllow.size(); 669 for (int i = 0; i < allowCount; i++) { 670 final OpToChange op = mOpsToAllow.get(i); 671 672 setUidModeAllowed(op.code, op.uid, op.packageName); 673 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); 674 } 675 676 final int foregroundCount = mOpsToForeground.size(); 677 for (int i = 0; i < foregroundCount; i++) { 678 final OpToChange op = mOpsToForeground.get(i); 679 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { 680 continue; 681 } 682 683 setUidModeForeground(op.code, op.uid, op.packageName); 684 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); 685 } 686 687 final int ignoreCount = mOpsToIgnore.size(); 688 for (int i = 0; i < ignoreCount; i++) { 689 final OpToChange op = mOpsToIgnore.get(i); 690 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { 691 continue; 692 } 693 694 setUidModeIgnored(op.code, op.uid, op.packageName); 695 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); 696 } 697 698 final int ignoreIfNotAllowedCount = mOpsToIgnoreIfNotAllowed.size(); 699 for (int i = 0; i < ignoreIfNotAllowedCount; i++) { 700 final OpToChange op = mOpsToIgnoreIfNotAllowed.get(i); 701 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { 702 continue; 703 } 704 705 boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid, op.packageName); 706 if (wasSet) { 707 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); 708 } 709 } 710 } 711 712 /** 713 * Note: Called with the package lock held. Do <u>not</u> call into app-op manager. 714 */ addAppOps(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull String permissionName)715 private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, 716 @NonNull String permissionName) { 717 PermissionInfo permissionInfo = mRuntimeAndTheirBgPermissionInfos.get(permissionName); 718 if (permissionInfo == null) { 719 return; 720 } 721 addPermissionAppOp(packageInfo, pkg, permissionInfo); 722 addExtraAppOp(packageInfo, pkg, permissionInfo); 723 } 724 addPermissionAppOp(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo)725 private void addPermissionAppOp(@NonNull PackageInfo packageInfo, 726 @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) { 727 if (!permissionInfo.isRuntime()) { 728 return; 729 } 730 731 String permissionName = permissionInfo.name; 732 String packageName = packageInfo.packageName; 733 int permissionFlags = mPackageManager.getPermissionFlags(permissionName, 734 packageName, mContext.getUser()); 735 boolean isReviewRequired = (permissionFlags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0; 736 if (isReviewRequired) { 737 return; 738 } 739 740 // TODO: COARSE_LOCATION and FINE_LOCATION shares the same app op. We are solving this 741 // with switch op but once we start syncing single permission this won't work. 742 int appOpCode = getSwitchOp(permissionName); 743 if (appOpCode == OP_NONE) { 744 // Note that background permissions don't have an associated app op. 745 return; 746 } 747 748 int appOpMode; 749 boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, pkg, permissionInfo); 750 if (shouldGrantAppOp) { 751 if (permissionInfo.backgroundPermission != null) { 752 PermissionInfo backgroundPermissionInfo = mRuntimeAndTheirBgPermissionInfos.get( 753 permissionInfo.backgroundPermission); 754 boolean shouldGrantBackgroundAppOp = backgroundPermissionInfo != null 755 && shouldGrantAppOp(packageInfo, pkg, backgroundPermissionInfo); 756 appOpMode = shouldGrantBackgroundAppOp ? MODE_ALLOWED : MODE_FOREGROUND; 757 } else { 758 appOpMode = MODE_ALLOWED; 759 } 760 } else { 761 appOpMode = MODE_IGNORED; 762 } 763 764 int uid = packageInfo.applicationInfo.uid; 765 OpToChange opToChange = new OpToChange(uid, packageName, appOpCode); 766 switch (appOpMode) { 767 case MODE_ALLOWED: 768 mOpsToAllow.add(opToChange); 769 break; 770 case MODE_FOREGROUND: 771 mOpsToForeground.add(opToChange); 772 break; 773 case MODE_IGNORED: 774 mOpsToIgnore.add(opToChange); 775 break; 776 } 777 } 778 shouldGrantAppOp(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo)779 private boolean shouldGrantAppOp(@NonNull PackageInfo packageInfo, 780 @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) { 781 String permissionName = permissionInfo.name; 782 String packageName = packageInfo.packageName; 783 boolean isGranted = mPackageManager.checkPermission(permissionName, packageName) 784 == PackageManager.PERMISSION_GRANTED; 785 if (!isGranted) { 786 return false; 787 } 788 789 int permissionFlags = mPackageManager.getPermissionFlags(permissionName, packageName, 790 mContext.getUser()); 791 boolean isRevokedCompat = (permissionFlags & FLAG_PERMISSION_REVOKED_COMPAT) 792 == FLAG_PERMISSION_REVOKED_COMPAT; 793 if (isRevokedCompat) { 794 return false; 795 } 796 797 if (permissionInfo.isHardRestricted()) { 798 boolean shouldApplyRestriction = 799 (permissionFlags & FLAG_PERMISSION_APPLY_RESTRICTION) 800 == FLAG_PERMISSION_APPLY_RESTRICTION; 801 return !shouldApplyRestriction; 802 } else if (permissionInfo.isSoftRestricted()) { 803 SoftRestrictedPermissionPolicy policy = 804 SoftRestrictedPermissionPolicy.forPermission(mContext, 805 packageInfo.applicationInfo, pkg, mContext.getUser(), 806 permissionName); 807 return policy.mayGrantPermission(); 808 } else { 809 return true; 810 } 811 } 812 addExtraAppOp(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo)813 private void addExtraAppOp(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, 814 @NonNull PermissionInfo permissionInfo) { 815 if (!permissionInfo.isSoftRestricted()) { 816 return; 817 } 818 819 String permissionName = permissionInfo.name; 820 SoftRestrictedPermissionPolicy policy = 821 SoftRestrictedPermissionPolicy.forPermission(mContext, 822 packageInfo.applicationInfo, pkg, mContext.getUser(), permissionName); 823 int extraOpCode = policy.getExtraAppOpCode(); 824 if (extraOpCode == OP_NONE) { 825 return; 826 } 827 828 int uid = packageInfo.applicationInfo.uid; 829 String packageName = packageInfo.packageName; 830 OpToChange extraOpToChange = new OpToChange(uid, packageName, extraOpCode); 831 if (policy.mayAllowExtraAppOp()) { 832 mOpsToAllow.add(extraOpToChange); 833 } else { 834 if (policy.mayDenyExtraAppOpIfGranted()) { 835 mOpsToIgnore.add(extraOpToChange); 836 } else { 837 mOpsToIgnoreIfNotAllowed.add(extraOpToChange); 838 } 839 } 840 } 841 842 /** 843 * Add a package for {@link #syncPackages() processing} later. 844 * 845 * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. 846 * 847 * @param pkgName The package to add for later processing. 848 */ addPackage(@onNull String pkgName)849 void addPackage(@NonNull String pkgName) { 850 PackageManagerInternal pmInternal = 851 LocalServices.getService(PackageManagerInternal.class); 852 final PackageInfo pkgInfo; 853 final AndroidPackage pkg; 854 try { 855 pkgInfo = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS); 856 pkg = pmInternal.getPackage(pkgName); 857 } catch (NameNotFoundException e) { 858 return; 859 } 860 861 if (pkgInfo == null || pkg == null || pkgInfo.applicationInfo == null 862 || pkgInfo.requestedPermissions == null) { 863 return; 864 } 865 866 final int uid = pkgInfo.applicationInfo.uid; 867 if (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID) { 868 // Root and system server always pass permission checks, so don't touch their app 869 // ops to keep compatibility. 870 return; 871 } 872 873 for (String permission : pkgInfo.requestedPermissions) { 874 addAppOps(pkgInfo, pkg, permission); 875 } 876 } 877 setUidModeAllowed(int opCode, int uid, @NonNull String packageName)878 private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) { 879 setUidMode(opCode, uid, MODE_ALLOWED, packageName); 880 } 881 setUidModeForeground(int opCode, int uid, @NonNull String packageName)882 private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) { 883 setUidMode(opCode, uid, MODE_FOREGROUND, packageName); 884 } 885 setUidModeIgnored(int opCode, int uid, @NonNull String packageName)886 private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) { 887 setUidMode(opCode, uid, MODE_IGNORED, packageName); 888 } 889 setUidModeIgnoredIfNotAllowed(int opCode, int uid, @NonNull String packageName)890 private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid, 891 @NonNull String packageName) { 892 final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( 893 opCode), uid, packageName); 894 if (currentMode != MODE_ALLOWED) { 895 if (currentMode != MODE_IGNORED) { 896 mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, MODE_IGNORED, 897 mAppOpsCallback); 898 } 899 return true; 900 } 901 return false; 902 } 903 setUidMode(int opCode, int uid, int mode, @NonNull String packageName)904 private void setUidMode(int opCode, int uid, int mode, 905 @NonNull String packageName) { 906 final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( 907 opCode), uid, packageName); 908 if (oldMode != mode) { 909 mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, mode, 910 mAppOpsCallback); 911 final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( 912 opCode), uid, packageName); 913 if (newMode != mode) { 914 // Work around incorrectly-set package mode. It never makes sense for app ops 915 // related to runtime permissions, but can get in the way and we have to reset 916 // it. 917 mAppOpsManagerInternal.setModeFromPermissionPolicy(opCode, uid, packageName, 918 AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback); 919 } 920 } 921 } 922 923 private class OpToChange { 924 final int uid; 925 final @NonNull String packageName; 926 final int code; 927 OpToChange(int uid, @NonNull String packageName, int code)928 OpToChange(int uid, @NonNull String packageName, int code) { 929 this.uid = uid; 930 this.packageName = packageName; 931 this.code = code; 932 } 933 } 934 } 935 936 private class Internal extends PermissionPolicyInternal { 937 938 @Override checkStartActivity(@onNull Intent intent, int callingUid, @Nullable String callingPackage)939 public boolean checkStartActivity(@NonNull Intent intent, int callingUid, 940 @Nullable String callingPackage) { 941 if (callingPackage != null && isActionRemovedForCallingPackage(intent, callingUid, 942 callingPackage)) { 943 Slog.w(LOG_TAG, "Action Removed: starting " + intent.toString() + " from " 944 + callingPackage + " (uid=" + callingUid + ")"); 945 return false; 946 } 947 return true; 948 } 949 950 @Override isInitialized(int userId)951 public boolean isInitialized(int userId) { 952 return isStarted(userId); 953 } 954 955 @Override setOnInitializedCallback(@onNull OnInitializedCallback callback)956 public void setOnInitializedCallback(@NonNull OnInitializedCallback callback) { 957 synchronized (mLock) { 958 mOnInitializedCallback = callback; 959 } 960 } 961 962 /** 963 * Check if the intent action is removed for the calling package (often based on target SDK 964 * version). If the action is removed, we'll silently cancel the activity launch. 965 */ isActionRemovedForCallingPackage(@onNull Intent intent, int callingUid, @NonNull String callingPackage)966 private boolean isActionRemovedForCallingPackage(@NonNull Intent intent, int callingUid, 967 @NonNull String callingPackage) { 968 String action = intent.getAction(); 969 if (action == null) { 970 return false; 971 } 972 switch (action) { 973 case TelecomManager.ACTION_CHANGE_DEFAULT_DIALER: 974 case Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT: { 975 ApplicationInfo applicationInfo; 976 try { 977 applicationInfo = getContext().getPackageManager().getApplicationInfoAsUser( 978 callingPackage, 0, UserHandle.getUserId(callingUid)); 979 if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) { 980 // Applications targeting Q or higher should use 981 // RoleManager.createRequestRoleIntent() instead. 982 return true; 983 } 984 } catch (PackageManager.NameNotFoundException e) { 985 Slog.i(LOG_TAG, "Cannot find application info for " + callingPackage); 986 } 987 // Make sure RequestRoleActivity can know the calling package if we allow it. 988 intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage); 989 return false; 990 } 991 default: 992 return false; 993 } 994 } 995 } 996 } 997