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