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