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