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.Manifest.permission.POST_NOTIFICATIONS; 20 import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION; 21 import static android.app.AppOpsManager.MODE_ALLOWED; 22 import static android.app.AppOpsManager.MODE_FOREGROUND; 23 import static android.app.AppOpsManager.MODE_IGNORED; 24 import static android.app.AppOpsManager.OP_NONE; 25 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 26 import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; 27 import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS; 28 import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER; 29 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; 30 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; 31 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT; 32 import static android.content.pm.PackageManager.GET_PERMISSIONS; 33 34 import android.Manifest; 35 import android.annotation.NonNull; 36 import android.annotation.Nullable; 37 import android.annotation.UserIdInt; 38 import android.app.ActivityManager; 39 import android.app.ActivityOptions; 40 import android.app.ActivityTaskManager; 41 import android.app.AppOpsManager; 42 import android.app.AppOpsManagerInternal; 43 import android.app.KeyguardManager; 44 import android.app.TaskInfo; 45 import android.app.compat.CompatChanges; 46 import android.companion.virtual.VirtualDeviceManager; 47 import android.compat.annotation.ChangeId; 48 import android.compat.annotation.EnabledAfter; 49 import android.content.BroadcastReceiver; 50 import android.content.ContentResolver; 51 import android.content.Context; 52 import android.content.Intent; 53 import android.content.IntentFilter; 54 import android.content.pm.ActivityInfo; 55 import android.content.pm.ApplicationInfo; 56 import android.content.pm.PackageInfo; 57 import android.content.pm.PackageManager; 58 import android.content.pm.PackageManager.NameNotFoundException; 59 import android.content.pm.PackageManagerInternal; 60 import android.content.pm.PackageManagerInternal.PackageListObserver; 61 import android.content.pm.PermissionInfo; 62 import android.content.res.Resources; 63 import android.os.Build; 64 import android.os.Bundle; 65 import android.os.Handler; 66 import android.os.Looper; 67 import android.os.Process; 68 import android.os.RemoteException; 69 import android.os.ServiceManager; 70 import android.os.UserHandle; 71 import android.permission.LegacyPermissionManager; 72 import android.permission.PermissionControllerManager; 73 import android.permission.PermissionManager; 74 import android.provider.Settings; 75 import android.provider.Telephony; 76 import android.telecom.TelecomManager; 77 import android.telephony.TelephonyManager; 78 import android.util.ArrayMap; 79 import android.util.ArraySet; 80 import android.util.Log; 81 import android.util.LongSparseLongArray; 82 import android.util.Slog; 83 import android.util.SparseBooleanArray; 84 85 import com.android.internal.annotations.GuardedBy; 86 import com.android.internal.app.IAppOpsCallback; 87 import com.android.internal.app.IAppOpsService; 88 import com.android.internal.infra.AndroidFuture; 89 import com.android.internal.util.IntPair; 90 import com.android.internal.util.function.pooled.PooledLambda; 91 import com.android.server.FgThread; 92 import com.android.server.LocalServices; 93 import com.android.server.PermissionThread; 94 import com.android.server.SystemService; 95 import com.android.server.notification.NotificationManagerInternal; 96 import com.android.server.pm.UserManagerInternal; 97 import com.android.server.pm.permission.PermissionManagerServiceInternal; 98 import com.android.server.pm.pkg.AndroidPackage; 99 import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback; 100 import com.android.server.utils.TimingsTraceAndSlog; 101 import com.android.server.wm.ActivityInterceptorCallback; 102 import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo; 103 import com.android.server.wm.ActivityTaskManagerInternal; 104 105 import java.util.ArrayList; 106 import java.util.Collections; 107 import java.util.HashMap; 108 import java.util.List; 109 import java.util.Map; 110 import java.util.Objects; 111 import java.util.Set; 112 import java.util.concurrent.ExecutionException; 113 114 /** 115 * This is a permission policy that governs over all permission mechanism 116 * such as permissions, app ops, etc. For example, the policy ensures that 117 * permission state and app ops is synchronized for cases where there is a 118 * dependency between permission state (permissions or permission flags) 119 * and app ops - and vise versa. 120 */ 121 public final class PermissionPolicyService extends SystemService { 122 private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName(); 123 private static final String SYSTEM_PKG = "android"; 124 private static final boolean DEBUG = false; 125 private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 60000; 126 127 private final Object mLock = new Object(); 128 129 @GuardedBy("mLock") 130 private boolean mBootCompleted = false; 131 132 private IAppOpsCallback mAppOpsCallback; 133 134 /** Whether the user is started but not yet stopped */ 135 @GuardedBy("mLock") 136 private final SparseBooleanArray mIsStarted = new SparseBooleanArray(); 137 138 /** Callbacks for when a user is initialized */ 139 @GuardedBy("mLock") 140 private OnInitializedCallback mOnInitializedCallback; 141 142 /** 143 * Whether an async {@link #synchronizeUidPermissionsAndAppOps} is currently 144 * scheduled for a UID. 145 */ 146 @GuardedBy("mLock") 147 private final SparseBooleanArray mIsUidSyncScheduled = new SparseBooleanArray(); 148 149 /** 150 * Whether an async {@link #resetAppOpPermissionsIfNotRequestedForUid} is currently 151 * scheduled for a uid. 152 */ 153 @GuardedBy("mLock") 154 private final SparseBooleanArray mIsUidResetScheduled = new SparseBooleanArray(); 155 156 /** 157 * This change reflects the presence of the new Notification Permission 158 */ 159 @ChangeId 160 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) 161 private static final long NOTIFICATION_PERM_CHANGE_ID = 194833441L; 162 163 private List<String> mAppOpPermissions; 164 165 private Context mContext; 166 private PackageManagerInternal mPackageManagerInternal; 167 private PermissionManagerServiceInternal mPermissionManagerInternal; 168 private ActivityTaskManagerInternal mActivityTaskManagerInternal; 169 private NotificationManagerInternal mNotificationManager; 170 private TelephonyManager mTelephonyManager; 171 private final KeyguardManager mKeyguardManager; 172 private final PackageManager mPackageManager; 173 private final Handler mHandler; 174 PermissionPolicyService(@onNull Context context)175 public PermissionPolicyService(@NonNull Context context) { 176 super(context); 177 178 mContext = context; 179 mHandler = new Handler(Looper.getMainLooper()); 180 mPackageManager = context.getPackageManager(); 181 mKeyguardManager = context.getSystemService(KeyguardManager.class); 182 LocalServices.addService(PermissionPolicyInternal.class, new Internal()); 183 } 184 185 @Override onStart()186 public void onStart() { 187 mPackageManagerInternal = LocalServices.getService( 188 PackageManagerInternal.class); 189 mPermissionManagerInternal = LocalServices.getService( 190 PermissionManagerServiceInternal.class); 191 mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); 192 final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface( 193 ServiceManager.getService(Context.APP_OPS_SERVICE)); 194 195 mPackageManagerInternal.getPackageList(new PackageListObserver() { 196 @Override 197 public void onPackageAdded(String packageName, int appId) { 198 final int[] userIds = LocalServices.getService(UserManagerInternal.class) 199 .getUserIds(); 200 for (final int userId : userIds) { 201 if (isStarted(userId)) { 202 final int uid = UserHandle.getUid(userId, appId); 203 synchronizeUidPermissionsAndAppOps(uid); 204 } 205 } 206 } 207 208 @Override 209 public void onPackageChanged(String packageName, int appId) { 210 final int[] userIds = LocalServices.getService(UserManagerInternal.class) 211 .getUserIds(); 212 for (final int userId : userIds) { 213 if (isStarted(userId)) { 214 final int uid = UserHandle.getUid(userId, appId); 215 synchronizeUidPermissionsAndAppOps(uid); 216 resetAppOpPermissionsIfNotRequestedForUid(uid); 217 } 218 } 219 } 220 221 @Override 222 public void onPackageRemoved(String packageName, int appId) { 223 final int[] userIds = LocalServices.getService(UserManagerInternal.class) 224 .getUserIds(); 225 for (final int userId : userIds) { 226 if (isStarted(userId)) { 227 final int uid = UserHandle.getUid(userId, appId); 228 resetAppOpPermissionsIfNotRequestedForUid(uid); 229 } 230 } 231 } 232 }); 233 234 mPackageManager.addOnPermissionsChangeListener( 235 this::synchronizeUidPermissionsAndAppOpsAsync); 236 237 mAppOpsCallback = new IAppOpsCallback.Stub() { 238 public void opChanged(int op, int uid, String packageName, String persistentDeviceId) { 239 if (!Objects.equals(persistentDeviceId, 240 VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT) || uid < 0) { 241 return; 242 } 243 synchronizeUidPermissionsAndAppOpsAsync(uid); 244 resetAppOpPermissionsIfNotRequestedForUidAsync(uid); 245 } 246 }; 247 248 final List<PermissionInfo> dangerousPerms = 249 mPermissionManagerInternal.getAllPermissionsWithProtection( 250 PermissionInfo.PROTECTION_DANGEROUS); 251 try { 252 int numDangerousPerms = dangerousPerms.size(); 253 for (int i = 0; i < numDangerousPerms; i++) { 254 PermissionInfo perm = dangerousPerms.get(i); 255 256 if (perm.isRuntime()) { 257 appOpsService.startWatchingMode(getSwitchOp(perm.name), null, mAppOpsCallback); 258 } 259 if (perm.isSoftRestricted()) { 260 SoftRestrictedPermissionPolicy policy = 261 SoftRestrictedPermissionPolicy.forPermission(null, null, null, 262 null, perm.name); 263 int extraAppOp = policy.getExtraAppOpCode(); 264 if (extraAppOp != OP_NONE) { 265 appOpsService.startWatchingMode(extraAppOp, null, mAppOpsCallback); 266 } 267 } 268 } 269 } catch (RemoteException doesNotHappen) { 270 Slog.wtf(LOG_TAG, "Cannot set up app-ops listener"); 271 } 272 273 final List<PermissionInfo> appOpPermissionInfos = 274 mPermissionManagerInternal.getAllPermissionsWithProtectionFlags( 275 PermissionInfo.PROTECTION_FLAG_APPOP); 276 mAppOpPermissions = new ArrayList<>(); 277 final int appOpPermissionInfosSize = appOpPermissionInfos.size(); 278 for (int i = 0; i < appOpPermissionInfosSize; i++) { 279 final PermissionInfo appOpPermissionInfo = appOpPermissionInfos.get(i); 280 281 switch (appOpPermissionInfo.name) { 282 case Manifest.permission.ACCESS_NOTIFICATIONS: 283 case Manifest.permission.MANAGE_IPSEC_TUNNELS: 284 continue; 285 case Manifest.permission.REQUEST_INSTALL_PACKAGES: 286 // Settings allows the user to control the app op if it's not in the default 287 // mode, regardless of whether the app has requested the permission, so we 288 // should not reset it. 289 continue; 290 default: 291 final int appOpCode = AppOpsManager.permissionToOpCode( 292 appOpPermissionInfo.name); 293 if (appOpCode != OP_NONE) { 294 mAppOpPermissions.add(appOpPermissionInfo.name); 295 try { 296 appOpsService.startWatchingMode(appOpCode, null, mAppOpsCallback); 297 } catch (RemoteException e) { 298 Slog.wtf(LOG_TAG, "Cannot set up app-ops listener", e); 299 } 300 } 301 } 302 } 303 304 IntentFilter intentFilter = new IntentFilter(); 305 intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 306 intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 307 intentFilter.addDataScheme("package"); 308 309 getContext().registerReceiverAsUser(new BroadcastReceiver() { 310 final List<Integer> mUserSetupUids = new ArrayList<>(200); 311 final Map<UserHandle, PermissionControllerManager> mPermControllerManagers = 312 new HashMap<>(); 313 314 @Override 315 public void onReceive(Context context, Intent intent) { 316 boolean hasSetupRun = true; 317 try { 318 final ContentResolver cr = getContext().getContentResolver(); 319 hasSetupRun = Settings.Secure.getIntForUser(cr, 320 Settings.Secure.USER_SETUP_COMPLETE, cr.getUserId()) != 0; 321 } catch (Settings.SettingNotFoundException e) { 322 // Ignore error, assume setup has run 323 } 324 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 325 // If there is no valid package for the given UID, return immediately 326 if (mPackageManagerInternal.getPackage(uid) == null) { 327 return; 328 } 329 330 if (hasSetupRun) { 331 if (!mUserSetupUids.isEmpty()) { 332 synchronized (mUserSetupUids) { 333 for (int i = mUserSetupUids.size() - 1; i >= 0; i--) { 334 updateUid(mUserSetupUids.get(i)); 335 } 336 mUserSetupUids.clear(); 337 } 338 } 339 updateUid(uid); 340 } else { 341 synchronized (mUserSetupUids) { 342 if (!mUserSetupUids.contains(uid)) { 343 mUserSetupUids.add(uid); 344 } 345 } 346 } 347 } 348 349 private void updateUid(int uid) { 350 UserHandle user = UserHandle.getUserHandleForUid(uid); 351 PermissionControllerManager manager = mPermControllerManagers.get(user); 352 if (manager == null) { 353 try { 354 manager = new PermissionControllerManager( 355 getUserContext(getContext(), user), PermissionThread.getHandler()); 356 } catch (IllegalStateException exception) { 357 // There's a possible race condition when a user is being removed 358 Log.e(LOG_TAG, "Could not create PermissionControllerManager for user" 359 + user, exception); 360 return; 361 } 362 mPermControllerManagers.put(user, manager); 363 } 364 manager.updateUserSensitiveForApp(uid); 365 } 366 }, UserHandle.ALL, intentFilter, null, null); 367 368 PermissionControllerManager manager = new PermissionControllerManager( 369 getUserContext(getContext(), Process.myUserHandle()), 370 PermissionThread.getHandler()); 371 PermissionThread.getHandler().postDelayed(manager::updateUserSensitive, 372 USER_SENSITIVE_UPDATE_DELAY_MS); 373 } 374 375 /** 376 * Get op that controls the access related to the permission. 377 * 378 * <p>Usually the permission-op relationship is 1:1 but some permissions (e.g. fine location) 379 * {@link AppOpsManager#opToSwitch(int)} share an op} to control the access. 380 * 381 * @param permission The permission 382 * @return The op that controls the access of the permission 383 */ getSwitchOp(@onNull String permission)384 private static int getSwitchOp(@NonNull String permission) { 385 int op = AppOpsManager.permissionToOpCode(permission); 386 if (op == OP_NONE) { 387 return OP_NONE; 388 } 389 390 return AppOpsManager.opToSwitch(op); 391 } 392 synchronizeUidPermissionsAndAppOpsAsync(int uid)393 private void synchronizeUidPermissionsAndAppOpsAsync(int uid) { 394 final int userId = UserHandle.getUserId(uid); 395 if (isStarted(userId)) { 396 synchronized (mLock) { 397 if (!mIsUidSyncScheduled.get(uid)) { 398 // TODO(b/165030092): migrate this to PermissionThread.getHandler(). 399 // synchronizeUidPermissionsAndAppOps is a heavy operation. 400 // Dispatched on a PermissionThread, it interferes with user switch. 401 // FgThread is busy and schedules it after most of the switch is done. 402 // A possible solution is to delay the callback. 403 FgThread.getHandler().sendMessage(PooledLambda.obtainMessage( 404 PermissionPolicyService::synchronizeUidPermissionsAndAppOps, this, 405 uid)); 406 mIsUidSyncScheduled.put(uid, true); 407 } else { 408 if (DEBUG) { 409 Slog.v(LOG_TAG, "sync for UID " + uid + " already scheduled"); 410 } 411 } 412 } 413 } 414 } 415 416 @Override onBootPhase(int phase)417 public void onBootPhase(int phase) { 418 if (DEBUG) Slog.i(LOG_TAG, "onBootPhase(" + phase + ")"); 419 420 if (phase == PHASE_DEVICE_SPECIFIC_SERVICES_READY) { 421 registerCarrierPrivilegesCallbacks(); 422 IntentFilter filter = 423 new IntentFilter(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED); 424 mContext.registerReceiver(mSimConfigBroadcastReceiver, filter); 425 } 426 427 if (phase == PHASE_ACTIVITY_MANAGER_READY) { 428 final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class); 429 430 // For some users we might not receive a onStartUser, hence force one here 431 for (int userId : um.getUserIds()) { 432 if (um.isUserRunning(userId)) { 433 onStartUser(userId); 434 } 435 } 436 } 437 438 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 439 ((Internal) LocalServices.getService(PermissionPolicyInternal.class)) 440 .onActivityManagerReady(); 441 } 442 443 if (phase == SystemService.PHASE_BOOT_COMPLETED) { 444 synchronized (mLock) { 445 mBootCompleted = true; 446 } 447 } 448 449 } 450 initTelephonyManagerIfNeeded()451 private void initTelephonyManagerIfNeeded() { 452 if (mTelephonyManager == null) { 453 mTelephonyManager = TelephonyManager.from(mContext); 454 } 455 } 456 registerCarrierPrivilegesCallbacks()457 private void registerCarrierPrivilegesCallbacks() { 458 initTelephonyManagerIfNeeded(); 459 if (mTelephonyManager == null) { 460 return; 461 } 462 463 int numPhones = mTelephonyManager.getActiveModemCount(); 464 for (int i = 0; i < numPhones; i++) { 465 PhoneCarrierPrivilegesCallback callback = new PhoneCarrierPrivilegesCallback(i); 466 mPhoneCarrierPrivilegesCallbacks.add(callback); 467 mTelephonyManager.registerCarrierPrivilegesCallback(i, mContext.getMainExecutor(), 468 callback); 469 } 470 } 471 unregisterCarrierPrivilegesCallback()472 private void unregisterCarrierPrivilegesCallback() { 473 initTelephonyManagerIfNeeded(); 474 if (mTelephonyManager == null) { 475 return; 476 } 477 478 for (int i = 0; i < mPhoneCarrierPrivilegesCallbacks.size(); i++) { 479 PhoneCarrierPrivilegesCallback callback = mPhoneCarrierPrivilegesCallbacks.get(i); 480 if (callback != null) { 481 mTelephonyManager.unregisterCarrierPrivilegesCallback(callback); 482 } 483 } 484 mPhoneCarrierPrivilegesCallbacks.clear(); 485 } 486 487 private final class PhoneCarrierPrivilegesCallback 488 implements TelephonyManager.CarrierPrivilegesCallback { 489 private int mPhoneId; 490 PhoneCarrierPrivilegesCallback(int phoneId)491 PhoneCarrierPrivilegesCallback(int phoneId) { 492 mPhoneId = phoneId; 493 } 494 495 @Override onCarrierPrivilegesChanged( @onNull Set<String> privilegedPackageNames, @NonNull Set<Integer> privilegedUids)496 public void onCarrierPrivilegesChanged( 497 @NonNull Set<String> privilegedPackageNames, 498 @NonNull Set<Integer> privilegedUids) { 499 initTelephonyManagerIfNeeded(); 500 if (mTelephonyManager == null) { 501 Log.e(LOG_TAG, "Cannot grant default permissions to Carrier Service app. " 502 + "TelephonyManager is null"); 503 return; 504 } 505 506 String servicePkg = mTelephonyManager.getCarrierServicePackageNameForLogicalSlot( 507 mPhoneId); 508 if (servicePkg == null) { 509 return; 510 } 511 int[] users = LocalServices.getService(UserManagerInternal.class).getUserIds(); 512 LegacyPermissionManager legacyPermManager = 513 mContext.getSystemService(LegacyPermissionManager.class); 514 for (int i = 0; i < users.length; i++) { 515 try { 516 mPackageManager.getPackageInfoAsUser(servicePkg, 0, users[i]); 517 legacyPermManager.grantDefaultPermissionsToCarrierServiceApp( 518 servicePkg, users[i]); 519 } catch (PackageManager.NameNotFoundException e) { 520 // Do nothing if the package does not exist for the specified user 521 } 522 } 523 } 524 } 525 526 private final ArrayList<PhoneCarrierPrivilegesCallback> mPhoneCarrierPrivilegesCallbacks = 527 new ArrayList<>(); 528 529 private final BroadcastReceiver mSimConfigBroadcastReceiver = new BroadcastReceiver() { 530 @Override 531 public void onReceive(Context context, Intent intent) { 532 if (!TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED.equals(intent.getAction())) { 533 return; 534 } 535 unregisterCarrierPrivilegesCallback(); 536 registerCarrierPrivilegesCallbacks(); 537 } 538 }; 539 540 /** 541 * @return Whether the user is started but not yet stopped 542 */ isStarted(@serIdInt int userId)543 private boolean isStarted(@UserIdInt int userId) { 544 synchronized (mLock) { 545 return mIsStarted.get(userId); 546 } 547 } 548 549 @Override onUserStarting(@onNull TargetUser user)550 public void onUserStarting(@NonNull TargetUser user) { 551 onStartUser(user.getUserIdentifier()); 552 } 553 onStartUser(@serIdInt int userId)554 private void onStartUser(@UserIdInt int userId) { 555 if (DEBUG) Slog.i(LOG_TAG, "onStartUser(" + userId + ")"); 556 557 if (isStarted(userId)) { 558 return; 559 } 560 561 562 final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); 563 t.traceBegin("Permission_grant_default_permissions-" + userId); 564 if (mPackageManagerInternal.isPermissionUpgradeNeeded(userId)) { 565 grantOrUpgradeDefaultRuntimePermissions(userId); 566 updateUserSensitive(userId); 567 mPackageManagerInternal.updateRuntimePermissionsFingerprint(userId); 568 } 569 t.traceEnd(); 570 571 final OnInitializedCallback callback; 572 573 synchronized (mLock) { 574 mIsStarted.put(userId, true); 575 callback = mOnInitializedCallback; 576 } 577 578 // Force synchronization as permissions might have changed 579 t.traceBegin("Permission_synchronize_permissions-" + userId); 580 synchronizePermissionsAndAppOpsForUser(userId); 581 t.traceEnd(); 582 583 // Tell observers we are initialized for this user. 584 if (callback != null) { 585 t.traceBegin("Permission_onInitialized-" + userId); 586 callback.onInitialized(userId); 587 t.traceEnd(); 588 } 589 } 590 591 @Override onUserStopping(@onNull TargetUser user)592 public void onUserStopping(@NonNull TargetUser user) { 593 if (DEBUG) Slog.i(LOG_TAG, "onStopUser(" + user + ")"); 594 595 synchronized (mLock) { 596 mIsStarted.delete(user.getUserIdentifier()); 597 } 598 } 599 grantOrUpgradeDefaultRuntimePermissions(@serIdInt int userId)600 private void grantOrUpgradeDefaultRuntimePermissions(@UserIdInt int userId) { 601 if (PermissionManager.USE_ACCESS_CHECKING_SERVICE) { 602 return; 603 } 604 605 if (DEBUG) Slog.i(LOG_TAG, "grantOrUpgradeDefaultPerms(" + userId + ")"); 606 final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); 607 608 // Now call into the permission controller to apply policy around permissions 609 final AndroidFuture<Boolean> future = new AndroidFuture<>(); 610 611 // We need to create a local manager that does not schedule work on the main 612 // there as we are on the main thread and want to block until the work is 613 // completed or we time out. 614 final PermissionControllerManager permissionControllerManager = 615 new PermissionControllerManager( 616 getUserContext(getContext(), UserHandle.of(userId)), 617 PermissionThread.getHandler()); 618 permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions( 619 PermissionThread.getExecutor(), successful -> { 620 if (successful) { 621 future.complete(null); 622 } else { 623 // We are in an undefined state now, let us crash and have 624 // rescue party suggest a wipe to recover to a good one. 625 final String message = "Error granting/upgrading runtime permissions" 626 + " for user " + userId; 627 Slog.wtf(LOG_TAG, message); 628 future.completeExceptionally(new IllegalStateException(message)); 629 } 630 }); 631 try { 632 t.traceBegin("Permission_callback_waiting-" + userId); 633 future.get(); 634 } catch (InterruptedException | ExecutionException e) { 635 throw new IllegalStateException(e); 636 } finally { 637 t.traceEnd(); 638 } 639 } 640 updateUserSensitive(@serIdInt int userId)641 private void updateUserSensitive(@UserIdInt int userId) { 642 if (DEBUG) Slog.i(LOG_TAG, "updateUserSensitive(" + userId + ")"); 643 final PermissionControllerManager permissionControllerManager = 644 new PermissionControllerManager( 645 getUserContext(getContext(), UserHandle.of(userId)), 646 PermissionThread.getHandler()); 647 permissionControllerManager.updateUserSensitive(); 648 } 649 getUserContext(@onNull Context context, @Nullable UserHandle user)650 private static @Nullable Context getUserContext(@NonNull Context context, 651 @Nullable UserHandle user) { 652 if (context.getUser().equals(user)) { 653 return context; 654 } else { 655 try { 656 return context.createPackageContextAsUser(context.getPackageName(), 0, user); 657 } catch (NameNotFoundException e) { 658 Slog.e(LOG_TAG, "Cannot create context for user " + user, e); 659 return null; 660 } 661 } 662 } 663 664 /** 665 * Synchronize a single UID. 666 */ synchronizeUidPermissionsAndAppOps(int uid)667 private void synchronizeUidPermissionsAndAppOps(int uid) { 668 synchronized (mLock) { 669 mIsUidSyncScheduled.delete(uid); 670 } 671 672 if (DEBUG) { 673 Slog.v(LOG_TAG, 674 "synchronizePackagePermissionsAndAppOpsForUser(" + uid + ")"); 675 } 676 677 final UserHandle user = UserHandle.getUserHandleForUid(uid); 678 final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser( 679 getUserContext(getContext(), user)); 680 final int appId = UserHandle.getAppId(uid); 681 final List<AndroidPackage> pkgs = mPackageManagerInternal.getPackagesForAppId(appId); 682 final int pkgsSize = pkgs.size(); 683 for (int i = 0; i < pkgsSize; i++) { 684 final AndroidPackage pkg = pkgs.get(i); 685 synchroniser.addPackage(pkg.getPackageName()); 686 } 687 synchroniser.syncPackages(); 688 } 689 690 /** 691 * Synchronize all packages 692 */ synchronizePermissionsAndAppOpsForUser(@serIdInt int userId)693 private void synchronizePermissionsAndAppOpsForUser(@UserIdInt int userId) { 694 if (DEBUG) Slog.i(LOG_TAG, "synchronizePermissionsAndAppOpsForUser(" + userId + ")"); 695 final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); 696 697 final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser( 698 getUserContext(getContext(), UserHandle.of(userId))); 699 t.traceBegin("Permission_synchronize_addPackages-" + userId); 700 mPackageManagerInternal.forEachPackage( 701 (pkg) -> synchronizer.addPackage(pkg.getPackageName())); 702 t.traceEnd(); 703 t.traceBegin("Permission_syncPackages-" + userId); 704 synchronizer.syncPackages(); 705 t.traceEnd(); 706 } 707 resetAppOpPermissionsIfNotRequestedForUidAsync(int uid)708 private void resetAppOpPermissionsIfNotRequestedForUidAsync(int uid) { 709 if (isStarted(UserHandle.getUserId(uid))) { 710 synchronized (mLock) { 711 if (!mIsUidResetScheduled.get(uid)) { 712 mIsUidResetScheduled.put(uid, true); 713 PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage( 714 PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid, 715 this, uid)); 716 } 717 } 718 } 719 } 720 resetAppOpPermissionsIfNotRequestedForUid(int uid)721 private void resetAppOpPermissionsIfNotRequestedForUid(int uid) { 722 synchronized (mLock) { 723 mIsUidResetScheduled.delete(uid); 724 } 725 726 final Context context = getContext(); 727 final PackageManager userPackageManager = getUserContext(context, 728 UserHandle.getUserHandleForUid(uid)).getPackageManager(); 729 final String[] packageNames = userPackageManager.getPackagesForUid(uid); 730 if (packageNames == null || packageNames.length == 0) { 731 return; 732 } 733 734 final ArraySet<String> requestedPermissions = new ArraySet<>(); 735 for (String packageName : packageNames) { 736 final PackageInfo packageInfo; 737 try { 738 packageInfo = userPackageManager.getPackageInfo(packageName, GET_PERMISSIONS); 739 } catch (NameNotFoundException e) { 740 continue; 741 } 742 if (packageInfo == null || packageInfo.requestedPermissions == null) { 743 continue; 744 } 745 Collections.addAll(requestedPermissions, packageInfo.requestedPermissions); 746 } 747 748 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 749 final AppOpsManagerInternal appOpsManagerInternal = LocalServices.getService( 750 AppOpsManagerInternal.class); 751 final int appOpPermissionsSize = mAppOpPermissions.size(); 752 for (int i = 0; i < appOpPermissionsSize; i++) { 753 final String appOpPermission = mAppOpPermissions.get(i); 754 755 if (!requestedPermissions.contains(appOpPermission)) { 756 final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermission); 757 final int defaultAppOpMode = AppOpsManager.opToDefaultMode(appOpCode); 758 for (String packageName : packageNames) { 759 final int appOpMode = appOpsManager.unsafeCheckOpRawNoThrow(appOpCode, uid, 760 packageName); 761 if (appOpMode != defaultAppOpMode) { 762 appOpsManagerInternal.setUidModeFromPermissionPolicy(appOpCode, uid, 763 defaultAppOpMode, mAppOpsCallback); 764 appOpsManagerInternal.setModeFromPermissionPolicy(appOpCode, uid, 765 packageName, defaultAppOpMode, mAppOpsCallback); 766 } 767 } 768 } 769 } 770 } 771 772 /** 773 * Synchronizes permission to app ops. You *must* always sync all packages 774 * in a shared UID at the same time to ensure proper synchronization. 775 */ 776 private class PermissionToOpSynchroniser { 777 private final @NonNull Context mContext; 778 private final @NonNull PackageManager mPackageManager; 779 private final @NonNull AppOpsManager mAppOpsManager; 780 private final @NonNull AppOpsManagerInternal mAppOpsManagerInternal; 781 782 private final @NonNull ArrayMap<String, PermissionInfo> mRuntimeAndTheirBgPermissionInfos; 783 784 /** 785 * All ops that need to be flipped to allow. 786 * 787 * @see #syncPackages 788 */ 789 private final @NonNull ArrayList<OpToChange> mOpsToAllow = new ArrayList<>(); 790 791 /** 792 * All ops that need to be flipped to ignore. 793 * 794 * @see #syncPackages 795 */ 796 private final @NonNull ArrayList<OpToChange> mOpsToIgnore = new ArrayList<>(); 797 798 /** 799 * All ops that need to be flipped to ignore if not allowed. 800 * 801 * Currently, only used by soft restricted permissions logic. 802 * 803 * @see #syncPackages 804 */ 805 private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfNotAllowed = new ArrayList<>(); 806 807 /** 808 * All ops that need to be flipped to foreground. 809 * 810 * Currently, only used by the foreground/background permissions logic. 811 * 812 * @see #syncPackages 813 */ 814 private final @NonNull ArrayList<OpToChange> mOpsToForeground = new ArrayList<>(); 815 PermissionToOpSynchroniser(@onNull Context context)816 PermissionToOpSynchroniser(@NonNull Context context) { 817 mContext = context; 818 mPackageManager = context.getPackageManager(); 819 mAppOpsManager = context.getSystemService(AppOpsManager.class); 820 mAppOpsManagerInternal = LocalServices.getService(AppOpsManagerInternal.class); 821 822 mRuntimeAndTheirBgPermissionInfos = new ArrayMap<>(); 823 PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService( 824 PermissionManagerServiceInternal.class); 825 List<PermissionInfo> permissionInfos = 826 permissionManagerInternal.getAllPermissionsWithProtection( 827 PermissionInfo.PROTECTION_DANGEROUS); 828 int permissionInfosSize = permissionInfos.size(); 829 for (int i = 0; i < permissionInfosSize; i++) { 830 PermissionInfo permissionInfo = permissionInfos.get(i); 831 mRuntimeAndTheirBgPermissionInfos.put(permissionInfo.name, permissionInfo); 832 // Make sure we scoop up all background permissions as they may not be runtime 833 if (permissionInfo.backgroundPermission != null) { 834 String backgroundNonRuntimePermission = permissionInfo.backgroundPermission; 835 for (int j = 0; j < permissionInfosSize; j++) { 836 PermissionInfo bgPermissionCandidate = permissionInfos.get(j); 837 if (permissionInfo.backgroundPermission.equals( 838 bgPermissionCandidate.name)) { 839 backgroundNonRuntimePermission = null; 840 break; 841 } 842 } 843 if (backgroundNonRuntimePermission != null) { 844 try { 845 PermissionInfo backgroundPermissionInfo = mPackageManager 846 .getPermissionInfo(backgroundNonRuntimePermission, 0); 847 mRuntimeAndTheirBgPermissionInfos.put(backgroundPermissionInfo.name, 848 backgroundPermissionInfo); 849 } catch (NameNotFoundException e) { 850 Slog.w(LOG_TAG, "Unknown background permission: " 851 + backgroundNonRuntimePermission); 852 } 853 } 854 } 855 } 856 } 857 858 /** 859 * Set app ops that were added in {@link #addPackage}. 860 * 861 * <p>This processes ops previously added by {@link #addPackage(String)})} 862 */ syncPackages()863 private void syncPackages() { 864 // Remember which ops were already set. This makes sure that we always set the most 865 // permissive mode if two OpChanges are scheduled. This can e.g. happen if two 866 // permissions change the same op. See {@link #getSwitchOp}. 867 LongSparseLongArray alreadySetAppOps = new LongSparseLongArray(); 868 869 final int allowCount = mOpsToAllow.size(); 870 for (int i = 0; i < allowCount; i++) { 871 final OpToChange op = mOpsToAllow.get(i); 872 873 setUidModeAllowed(op.code, op.uid, op.packageName); 874 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); 875 } 876 877 final int foregroundCount = mOpsToForeground.size(); 878 for (int i = 0; i < foregroundCount; i++) { 879 final OpToChange op = mOpsToForeground.get(i); 880 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { 881 continue; 882 } 883 884 setUidModeForeground(op.code, op.uid, op.packageName); 885 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); 886 } 887 888 final int ignoreCount = mOpsToIgnore.size(); 889 for (int i = 0; i < ignoreCount; i++) { 890 final OpToChange op = mOpsToIgnore.get(i); 891 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { 892 continue; 893 } 894 895 setUidModeIgnored(op.code, op.uid, op.packageName); 896 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); 897 } 898 899 final int ignoreIfNotAllowedCount = mOpsToIgnoreIfNotAllowed.size(); 900 for (int i = 0; i < ignoreIfNotAllowedCount; i++) { 901 final OpToChange op = mOpsToIgnoreIfNotAllowed.get(i); 902 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { 903 continue; 904 } 905 906 boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid, op.packageName); 907 if (wasSet) { 908 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); 909 } 910 } 911 } 912 913 /** 914 * Note: Called with the package lock held. Do <u>not</u> call into app-op manager. 915 */ addAppOps(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull String permissionName)916 private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, 917 @NonNull String permissionName) { 918 PermissionInfo permissionInfo = mRuntimeAndTheirBgPermissionInfos.get(permissionName); 919 if (permissionInfo == null) { 920 return; 921 } 922 addPermissionAppOp(packageInfo, pkg, permissionInfo); 923 addExtraAppOp(packageInfo, pkg, permissionInfo); 924 } 925 addPermissionAppOp(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo)926 private void addPermissionAppOp(@NonNull PackageInfo packageInfo, 927 @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) { 928 if (!permissionInfo.isRuntime()) { 929 return; 930 } 931 932 String permissionName = permissionInfo.name; 933 String packageName = packageInfo.packageName; 934 UserHandle user = UserHandle.getUserHandleForUid(packageInfo.applicationInfo.uid); 935 int permissionFlags = mPackageManager.getPermissionFlags(permissionName, 936 packageName, mContext.getUser()); 937 boolean isReviewRequired = (permissionFlags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0; 938 if (isReviewRequired) { 939 return; 940 } 941 942 // TODO: COARSE_LOCATION and FINE_LOCATION shares the same app op. We are solving this 943 // with switch op but once we start syncing single permission this won't work. 944 int appOpCode = getSwitchOp(permissionName); 945 if (appOpCode == OP_NONE) { 946 // Note that background permissions don't have an associated app op. 947 return; 948 } 949 950 int appOpMode; 951 boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, pkg, permissionInfo); 952 if (shouldGrantAppOp) { 953 if (permissionInfo.backgroundPermission != null) { 954 PermissionInfo backgroundPermissionInfo = mRuntimeAndTheirBgPermissionInfos.get( 955 permissionInfo.backgroundPermission); 956 boolean shouldGrantBackgroundAppOp = backgroundPermissionInfo != null 957 && shouldGrantAppOp(packageInfo, pkg, backgroundPermissionInfo); 958 appOpMode = shouldGrantBackgroundAppOp ? MODE_ALLOWED : MODE_FOREGROUND; 959 } else { 960 appOpMode = MODE_ALLOWED; 961 } 962 } else { 963 appOpMode = MODE_IGNORED; 964 } 965 966 int uid = packageInfo.applicationInfo.uid; 967 OpToChange opToChange = new OpToChange(uid, packageName, appOpCode); 968 switch (appOpMode) { 969 case MODE_ALLOWED: 970 mOpsToAllow.add(opToChange); 971 break; 972 case MODE_FOREGROUND: 973 mOpsToForeground.add(opToChange); 974 break; 975 case MODE_IGNORED: 976 mOpsToIgnore.add(opToChange); 977 break; 978 } 979 } 980 shouldGrantAppOp(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo)981 private boolean shouldGrantAppOp(@NonNull PackageInfo packageInfo, 982 @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) { 983 String permissionName = permissionInfo.name; 984 String packageName = packageInfo.packageName; 985 boolean isGranted = mPackageManager.checkPermission(permissionName, packageName) 986 == PackageManager.PERMISSION_GRANTED; 987 if (!isGranted) { 988 return false; 989 } 990 991 int permissionFlags = mPackageManager.getPermissionFlags(permissionName, packageName, 992 mContext.getUser()); 993 boolean isRevokedCompat = (permissionFlags & FLAG_PERMISSION_REVOKED_COMPAT) 994 == FLAG_PERMISSION_REVOKED_COMPAT; 995 if (isRevokedCompat) { 996 return false; 997 } 998 999 if (permissionInfo.isHardRestricted()) { 1000 boolean shouldApplyRestriction = 1001 (permissionFlags & FLAG_PERMISSION_APPLY_RESTRICTION) 1002 == FLAG_PERMISSION_APPLY_RESTRICTION; 1003 return !shouldApplyRestriction; 1004 } else if (permissionInfo.isSoftRestricted()) { 1005 SoftRestrictedPermissionPolicy policy = 1006 SoftRestrictedPermissionPolicy.forPermission(mContext, 1007 packageInfo.applicationInfo, pkg, mContext.getUser(), 1008 permissionName); 1009 return policy.mayGrantPermission(); 1010 } else { 1011 return true; 1012 } 1013 } 1014 addExtraAppOp(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo)1015 private void addExtraAppOp(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, 1016 @NonNull PermissionInfo permissionInfo) { 1017 if (!permissionInfo.isSoftRestricted()) { 1018 return; 1019 } 1020 1021 String permissionName = permissionInfo.name; 1022 SoftRestrictedPermissionPolicy policy = 1023 SoftRestrictedPermissionPolicy.forPermission(mContext, 1024 packageInfo.applicationInfo, pkg, mContext.getUser(), permissionName); 1025 int extraOpCode = policy.getExtraAppOpCode(); 1026 if (extraOpCode == OP_NONE) { 1027 return; 1028 } 1029 1030 int uid = packageInfo.applicationInfo.uid; 1031 String packageName = packageInfo.packageName; 1032 OpToChange extraOpToChange = new OpToChange(uid, packageName, extraOpCode); 1033 if (policy.mayAllowExtraAppOp()) { 1034 mOpsToAllow.add(extraOpToChange); 1035 } else { 1036 if (policy.mayDenyExtraAppOpIfGranted()) { 1037 mOpsToIgnore.add(extraOpToChange); 1038 } else { 1039 mOpsToIgnoreIfNotAllowed.add(extraOpToChange); 1040 } 1041 } 1042 } 1043 1044 /** 1045 * Add a package for {@link #syncPackages() processing} later. 1046 * 1047 * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. 1048 * 1049 * @param pkgName The package to add for later processing. 1050 */ addPackage(@onNull String pkgName)1051 void addPackage(@NonNull String pkgName) { 1052 final PackageInfo pkgInfo; 1053 final AndroidPackage pkg; 1054 try { 1055 pkgInfo = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS); 1056 pkg = mPackageManagerInternal.getPackage(pkgName); 1057 } catch (NameNotFoundException e) { 1058 return; 1059 } 1060 1061 if (pkgInfo == null || pkg == null || pkgInfo.applicationInfo == null 1062 || pkgInfo.requestedPermissions == null) { 1063 return; 1064 } 1065 1066 final int uid = pkgInfo.applicationInfo.uid; 1067 if (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID) { 1068 // Root and system server always pass permission checks, so don't touch their app 1069 // ops to keep compatibility. 1070 return; 1071 } 1072 1073 for (String permission : pkgInfo.requestedPermissions) { 1074 addAppOps(pkgInfo, pkg, permission); 1075 } 1076 } 1077 setUidModeAllowed(int opCode, int uid, @NonNull String packageName)1078 private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) { 1079 setUidMode(opCode, uid, MODE_ALLOWED, packageName); 1080 } 1081 setUidModeForeground(int opCode, int uid, @NonNull String packageName)1082 private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) { 1083 setUidMode(opCode, uid, MODE_FOREGROUND, packageName); 1084 } 1085 setUidModeIgnored(int opCode, int uid, @NonNull String packageName)1086 private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) { 1087 setUidMode(opCode, uid, MODE_IGNORED, packageName); 1088 } 1089 setUidModeIgnoredIfNotAllowed(int opCode, int uid, @NonNull String packageName)1090 private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid, 1091 @NonNull String packageName) { 1092 final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( 1093 opCode), uid, packageName); 1094 if (currentMode != MODE_ALLOWED) { 1095 if (currentMode != MODE_IGNORED) { 1096 mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, MODE_IGNORED, 1097 mAppOpsCallback); 1098 } 1099 return true; 1100 } 1101 return false; 1102 } 1103 setUidMode(int opCode, int uid, int mode, @NonNull String packageName)1104 private void setUidMode(int opCode, int uid, int mode, 1105 @NonNull String packageName) { 1106 final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( 1107 opCode), uid, packageName); 1108 if (oldMode != mode) { 1109 mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, mode, 1110 mAppOpsCallback); 1111 final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( 1112 opCode), uid, packageName); 1113 if (newMode != mode) { 1114 // Work around incorrectly-set package mode. It never makes sense for app ops 1115 // related to runtime permissions, but can get in the way and we have to reset 1116 // it. 1117 mAppOpsManagerInternal.setModeFromPermissionPolicy(opCode, uid, packageName, 1118 AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback); 1119 } 1120 } 1121 } 1122 1123 private class OpToChange { 1124 final int uid; 1125 final @NonNull String packageName; 1126 final int code; 1127 OpToChange(int uid, @NonNull String packageName, int code)1128 OpToChange(int uid, @NonNull String packageName, int code) { 1129 this.uid = uid; 1130 this.packageName = packageName; 1131 this.code = code; 1132 } 1133 } 1134 } 1135 1136 private class Internal extends PermissionPolicyInternal { 1137 1138 private final ActivityInterceptorCallback mActivityInterceptorCallback = 1139 new ActivityInterceptorCallback() { 1140 @Nullable 1141 @Override 1142 public ActivityInterceptorCallback.ActivityInterceptResult 1143 onInterceptActivityLaunch(@NonNull ActivityInterceptorInfo info) { 1144 return null; 1145 } 1146 1147 @Override 1148 public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo, 1149 ActivityInterceptorInfo info) { 1150 if (!shouldShowNotificationDialogOrClearFlags(taskInfo, 1151 activityInfo.packageName, info.getCallingPackage(), 1152 info.getIntent(), info.getCheckedOptions(), activityInfo.name, 1153 true) 1154 || isNoDisplayActivity(activityInfo, info.getUserId())) { 1155 return; 1156 } 1157 UserHandle user = UserHandle.of(taskInfo.userId); 1158 if (!CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, 1159 activityInfo.packageName, user)) { 1160 // Post the activity start checks to ensure the notification channel 1161 // checks happen outside the WindowManager global lock. 1162 mHandler.post(() -> showNotificationPromptIfNeeded( 1163 activityInfo.packageName, taskInfo.userId, taskInfo.taskId, 1164 info)); 1165 } 1166 } 1167 }; 1168 onActivityManagerReady()1169 private void onActivityManagerReady() { 1170 mActivityTaskManagerInternal.registerActivityStartInterceptor( 1171 ActivityInterceptorCallback.PERMISSION_POLICY_ORDERED_ID, 1172 mActivityInterceptorCallback); 1173 } 1174 1175 @Override checkStartActivity(@onNull Intent intent, int callingUid, @Nullable String callingPackage)1176 public boolean checkStartActivity(@NonNull Intent intent, int callingUid, 1177 @Nullable String callingPackage) { 1178 if (callingPackage != null && isActionRemovedForCallingPackage(intent, callingUid, 1179 callingPackage)) { 1180 Slog.w(LOG_TAG, "Action Removed: starting " + intent.toString() + " from " 1181 + callingPackage + " (uid=" + callingUid + ")"); 1182 return false; 1183 } 1184 1185 if (ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(intent.getAction()) 1186 && (callingUid != Process.SYSTEM_UID || !SYSTEM_PKG.equals(callingPackage))) { 1187 return false; 1188 } 1189 1190 return true; 1191 } 1192 1193 @Override showNotificationPromptIfNeeded(@onNull String packageName, int userId, int taskId)1194 public void showNotificationPromptIfNeeded(@NonNull String packageName, int userId, 1195 int taskId) { 1196 showNotificationPromptIfNeeded(packageName, userId, taskId, null /* info */); 1197 } 1198 showNotificationPromptIfNeeded(@onNull String packageName, int userId, int taskId, @Nullable ActivityInterceptorInfo info)1199 void showNotificationPromptIfNeeded(@NonNull String packageName, int userId, 1200 int taskId, @Nullable ActivityInterceptorInfo info) { 1201 UserHandle user = UserHandle.of(userId); 1202 if (packageName == null || taskId == ActivityTaskManager.INVALID_TASK_ID 1203 || !shouldForceShowNotificationPermissionRequest(packageName, user)) { 1204 return; 1205 } 1206 1207 launchNotificationPermissionRequestDialog(packageName, user, taskId, info); 1208 } 1209 1210 @Override isIntentToPermissionDialog(@onNull Intent intent)1211 public boolean isIntentToPermissionDialog(@NonNull Intent intent) { 1212 return Objects.equals(intent.getPackage(), 1213 mPackageManager.getPermissionControllerPackageName()) 1214 && (Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS_FOR_OTHER) 1215 || Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS)); 1216 } 1217 1218 @Override shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg, String callingPkg, Intent intent, String activityName)1219 public boolean shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg, 1220 String callingPkg, Intent intent, String activityName) { 1221 return shouldShowNotificationDialogOrClearFlags(taskInfo, currPkg, callingPkg, intent, 1222 null, activityName, false); 1223 } 1224 isNoDisplayActivity(@onNull ActivityInfo aInfo, int userId)1225 private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo, int userId) { 1226 final int themeResource = aInfo.getThemeResource(); 1227 if (themeResource == Resources.ID_NULL) { 1228 return false; 1229 } 1230 1231 return mActivityTaskManagerInternal.isNoDisplay(aInfo.packageName, themeResource, 1232 userId); 1233 } 1234 1235 /** 1236 * Determine if a particular task is in the proper state to show a system-triggered 1237 * permission prompt. A prompt can be shown if the task is just starting, or the task is 1238 * currently focused, visible, and running, and, 1239 * 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or 1240 * 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER), or 1241 * 3. The activity belongs to the same package as the one which launched the task 1242 * originally, and the task was started with a launcher intent, or 1243 * 4. The activity is the first activity in a new task, and was started by the app the 1244 * activity belongs to, and that app has another task that is currently focused, which was 1245 * started with a launcher intent. This case seeks to identify cases where an app launches, 1246 * then immediately trampolines to a new activity and task. 1247 * @param taskInfo The task to be checked 1248 * @param currPkg The package of the current top visible activity 1249 * @param callingPkg The package that initiated this dialog action 1250 * @param intent The intent of the current top visible activity 1251 * @param options The ActivityOptions of the newly started activity, if this is called due 1252 * to an activity start 1253 * @param startedActivity The ActivityInfo of the newly started activity, if this is called 1254 * due to an activity start 1255 */ shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg, String callingPkg, Intent intent, ActivityOptions options, String topActivityName, boolean startedActivity)1256 private boolean shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg, 1257 String callingPkg, Intent intent, ActivityOptions options, 1258 String topActivityName, boolean startedActivity) { 1259 if (intent == null || currPkg == null || taskInfo == null || topActivityName == null 1260 || (!(taskInfo.isFocused && taskInfo.isVisible && taskInfo.isRunning) 1261 && !startedActivity)) { 1262 return false; 1263 } 1264 return isLauncherIntent(intent) 1265 || (options != null && options.isEligibleForLegacyPermissionPrompt()) 1266 || isTaskStartedFromLauncher(currPkg, taskInfo) 1267 || (isTaskPotentialTrampoline(topActivityName, currPkg, callingPkg, taskInfo, 1268 intent) 1269 && (!startedActivity || pkgHasRunningLauncherTask(currPkg, taskInfo))); 1270 } 1271 isTaskPotentialTrampoline(String activityName, String currPkg, String callingPkg, TaskInfo taskInfo, Intent intent)1272 private boolean isTaskPotentialTrampoline(String activityName, String currPkg, 1273 String callingPkg, TaskInfo taskInfo, Intent intent) { 1274 return currPkg.equals(callingPkg) && taskInfo.baseIntent.filterEquals(intent) 1275 && taskInfo.numActivities == 1 1276 && activityName.equals(taskInfo.topActivityInfo.name); 1277 } 1278 pkgHasRunningLauncherTask(String currPkg, TaskInfo taskInfo)1279 private boolean pkgHasRunningLauncherTask(String currPkg, TaskInfo taskInfo) { 1280 ActivityTaskManagerInternal m = 1281 LocalServices.getService(ActivityTaskManagerInternal.class); 1282 try { 1283 // TODO(b/230616478) Investigate alternatives like ActivityMetricsLaunchObserver 1284 List<ActivityManager.AppTask> tasks = 1285 m.getAppTasks(currPkg, mPackageManager.getPackageUid(currPkg, 0)); 1286 for (int i = 0; i < tasks.size(); i++) { 1287 TaskInfo other = tasks.get(i).getTaskInfo(); 1288 if (other.taskId != taskInfo.taskId && other.isFocused && other.isRunning 1289 && isTaskStartedFromLauncher(currPkg, other)) { 1290 return true; 1291 } 1292 } 1293 } catch (PackageManager.NameNotFoundException e) { 1294 // Fall through 1295 } 1296 return false; 1297 } 1298 isLauncherIntent(Intent intent)1299 private boolean isLauncherIntent(Intent intent) { 1300 return Intent.ACTION_MAIN.equals(intent.getAction()) 1301 && intent.getCategories() != null 1302 && (intent.getCategories().contains(Intent.CATEGORY_LAUNCHER) 1303 || intent.getCategories().contains(Intent.CATEGORY_LEANBACK_LAUNCHER) 1304 || intent.getCategories().contains(Intent.CATEGORY_CAR_LAUNCHER)); 1305 } 1306 isTaskStartedFromLauncher(String currPkg, TaskInfo taskInfo)1307 private boolean isTaskStartedFromLauncher(String currPkg, TaskInfo taskInfo) { 1308 return taskInfo.baseActivity != null 1309 && currPkg.equals(taskInfo.baseActivity.getPackageName()) 1310 && isLauncherIntent(taskInfo.baseIntent); 1311 } 1312 launchNotificationPermissionRequestDialog(String pkgName, UserHandle user, int taskId, @Nullable ActivityInterceptorInfo info)1313 private void launchNotificationPermissionRequestDialog(String pkgName, UserHandle user, 1314 int taskId, @Nullable ActivityInterceptorInfo info) { 1315 Intent grantPermission = mPackageManager 1316 .buildRequestPermissionsIntent(new String[] { POST_NOTIFICATIONS }); 1317 // Prevent the front-most activity entering pip due to overlay activity started on top. 1318 grantPermission.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_USER_ACTION); 1319 grantPermission.setAction( 1320 ACTION_REQUEST_PERMISSIONS_FOR_OTHER); 1321 grantPermission.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgName); 1322 1323 final boolean remoteAnimation = info != null && info.getCheckedOptions() != null 1324 && info.getCheckedOptions().getAnimationType() == ANIM_REMOTE_ANIMATION 1325 && info.getClearOptionsAnimationRunnable() != null; 1326 ActivityOptions options = remoteAnimation ? ActivityOptions.makeRemoteAnimation( 1327 info.getCheckedOptions().getRemoteAnimationAdapter(), 1328 info.getCheckedOptions().getRemoteTransition()) 1329 : new ActivityOptions(new Bundle()); 1330 options.setTaskOverlay(true, false); 1331 options.setLaunchTaskId(taskId); 1332 if (remoteAnimation) { 1333 // Remote animation set on the intercepted activity will be handled by the grant 1334 // permission activity, which is launched below. So we need to clear remote 1335 // animation from the intercepted activity and its siblings to prevent duplication. 1336 // This should trigger ActivityRecord#clearOptionsAnimationForSiblings for the 1337 // intercepted activity. 1338 info.getClearOptionsAnimationRunnable().run(); 1339 } 1340 try { 1341 mContext.startActivityAsUser(grantPermission, options.toBundle(), user); 1342 } catch (Exception e) { 1343 Log.e(LOG_TAG, "couldn't start grant permission dialog" 1344 + "for other package " + pkgName, e); 1345 } 1346 } 1347 1348 @Override isInitialized(int userId)1349 public boolean isInitialized(int userId) { 1350 return isStarted(userId); 1351 } 1352 1353 @Override setOnInitializedCallback(@onNull OnInitializedCallback callback)1354 public void setOnInitializedCallback(@NonNull OnInitializedCallback callback) { 1355 synchronized (mLock) { 1356 mOnInitializedCallback = callback; 1357 } 1358 } 1359 1360 /** 1361 * Check if the intent action is removed for the calling package (often based on target SDK 1362 * version). If the action is removed, we'll silently cancel the activity launch. 1363 */ isActionRemovedForCallingPackage(@onNull Intent intent, int callingUid, @NonNull String callingPackage)1364 private boolean isActionRemovedForCallingPackage(@NonNull Intent intent, int callingUid, 1365 @NonNull String callingPackage) { 1366 String action = intent.getAction(); 1367 if (action == null) { 1368 return false; 1369 } 1370 switch (action) { 1371 case TelecomManager.ACTION_CHANGE_DEFAULT_DIALER: 1372 case Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT: { 1373 ApplicationInfo applicationInfo; 1374 try { 1375 applicationInfo = getContext().getPackageManager().getApplicationInfoAsUser( 1376 callingPackage, 0, UserHandle.getUserId(callingUid)); 1377 if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) { 1378 // Applications targeting Q or higher should use 1379 // RoleManager.createRequestRoleIntent() instead. 1380 return true; 1381 } 1382 } catch (PackageManager.NameNotFoundException e) { 1383 Slog.i(LOG_TAG, "Cannot find application info for " + callingPackage); 1384 } 1385 // Make sure RequestRoleActivity can know the calling package if we allow it. 1386 intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage); 1387 return false; 1388 } 1389 default: 1390 return false; 1391 } 1392 } 1393 shouldForceShowNotificationPermissionRequest(@onNull String pkgName, @NonNull UserHandle user)1394 private boolean shouldForceShowNotificationPermissionRequest(@NonNull String pkgName, 1395 @NonNull UserHandle user) { 1396 AndroidPackage pkg = mPackageManagerInternal.getPackage(pkgName); 1397 if (pkg == null || pkg.getPackageName() == null 1398 || Objects.equals(pkgName, mPackageManager.getPermissionControllerPackageName()) 1399 || pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) { 1400 if (pkg == null) { 1401 Slog.w(LOG_TAG, "Cannot check for Notification prompt, no package for " 1402 + pkgName); 1403 } 1404 return false; 1405 } 1406 1407 synchronized (mLock) { 1408 if (!mBootCompleted) { 1409 return false; 1410 } 1411 } 1412 1413 if (!pkg.getRequestedPermissions().contains(POST_NOTIFICATIONS) 1414 || CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, pkgName, user) 1415 || mKeyguardManager.isKeyguardLocked()) { 1416 return false; 1417 } 1418 1419 int uid = user.getUid(pkg.getUid()); 1420 if (mNotificationManager == null) { 1421 mNotificationManager = LocalServices.getService(NotificationManagerInternal.class); 1422 } 1423 boolean hasCreatedNotificationChannels = mNotificationManager 1424 .getNumNotificationChannelsForPackage(pkgName, uid, true) > 0; 1425 boolean granted = mPermissionManagerInternal.checkUidPermission(uid, POST_NOTIFICATIONS, 1426 Context.DEVICE_ID_DEFAULT) == PackageManager.PERMISSION_GRANTED; 1427 int flags = mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName, user); 1428 boolean explicitlySet = (flags & PermissionManager.EXPLICIT_SET_FLAGS) != 0; 1429 return !granted && hasCreatedNotificationChannels && !explicitlySet; 1430 } 1431 } 1432 } 1433