1 /* 2 * Copyright (C) 2014 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.pm; 18 19 import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME; 20 import static android.app.PendingIntent.FLAG_IMMUTABLE; 21 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; 22 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; 23 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; 24 import static android.content.pm.LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS; 25 import static android.content.pm.LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS; 26 import static android.content.pm.LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS; 27 28 import android.annotation.AppIdInt; 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.annotation.UserIdInt; 32 import android.app.ActivityManager; 33 import android.app.ActivityManagerInternal; 34 import android.app.ActivityOptions; 35 import android.app.AppGlobals; 36 import android.app.IApplicationThread; 37 import android.app.PendingIntent; 38 import android.app.admin.DevicePolicyManager; 39 import android.app.usage.UsageStatsManagerInternal; 40 import android.content.ActivityNotFoundException; 41 import android.content.BroadcastReceiver; 42 import android.content.ComponentName; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.IntentFilter; 46 import android.content.IntentSender; 47 import android.content.LocusId; 48 import android.content.pm.ActivityInfo; 49 import android.content.pm.ApplicationInfo; 50 import android.content.pm.ILauncherApps; 51 import android.content.pm.IOnAppsChangedListener; 52 import android.content.pm.IPackageInstallerCallback; 53 import android.content.pm.IPackageManager; 54 import android.content.pm.IShortcutChangeCallback; 55 import android.content.pm.IncrementalStatesInfo; 56 import android.content.pm.LauncherActivityInfoInternal; 57 import android.content.pm.LauncherApps; 58 import android.content.pm.LauncherApps.ShortcutQuery; 59 import android.content.pm.PackageInfo; 60 import android.content.pm.PackageInstaller.SessionInfo; 61 import android.content.pm.PackageManager; 62 import android.content.pm.PackageManagerInternal; 63 import android.content.pm.ParceledListSlice; 64 import android.content.pm.ResolveInfo; 65 import android.content.pm.ShortcutInfo; 66 import android.content.pm.ShortcutQueryWrapper; 67 import android.content.pm.ShortcutServiceInternal; 68 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; 69 import android.content.pm.UserInfo; 70 import android.graphics.Rect; 71 import android.net.Uri; 72 import android.os.Binder; 73 import android.os.Bundle; 74 import android.os.Handler; 75 import android.os.IInterface; 76 import android.os.ParcelFileDescriptor; 77 import android.os.Process; 78 import android.os.RemoteCallbackList; 79 import android.os.RemoteException; 80 import android.os.ServiceManager; 81 import android.os.UserHandle; 82 import android.os.UserManager; 83 import android.provider.Settings; 84 import android.util.Log; 85 import android.util.Pair; 86 import android.util.Slog; 87 88 import com.android.internal.annotations.GuardedBy; 89 import com.android.internal.annotations.VisibleForTesting; 90 import com.android.internal.content.PackageMonitor; 91 import com.android.internal.os.BackgroundThread; 92 import com.android.internal.util.ArrayUtils; 93 import com.android.internal.util.CollectionUtils; 94 import com.android.internal.util.Preconditions; 95 import com.android.server.LocalServices; 96 import com.android.server.SystemService; 97 import com.android.server.pm.parsing.pkg.AndroidPackage; 98 import com.android.server.wm.ActivityTaskManagerInternal; 99 100 import java.util.ArrayList; 101 import java.util.Arrays; 102 import java.util.Collections; 103 import java.util.HashSet; 104 import java.util.List; 105 import java.util.Objects; 106 107 /** 108 * Service that manages requests and callbacks for launchers that support 109 * managed profiles. 110 */ 111 public class LauncherAppsService extends SystemService { 112 113 private final LauncherAppsImpl mLauncherAppsImpl; 114 LauncherAppsService(Context context)115 public LauncherAppsService(Context context) { 116 super(context); 117 mLauncherAppsImpl = new LauncherAppsImpl(context); 118 } 119 120 @Override onStart()121 public void onStart() { 122 publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl); 123 mLauncherAppsImpl.registerLoadingProgressForIncrementalApps(); 124 } 125 126 static class BroadcastCookie { 127 public final UserHandle user; 128 public final String packageName; 129 public final int callingUid; 130 public final int callingPid; 131 BroadcastCookie(UserHandle userHandle, String packageName, int callingPid, int callingUid)132 BroadcastCookie(UserHandle userHandle, String packageName, int callingPid, int callingUid) { 133 this.user = userHandle; 134 this.packageName = packageName; 135 this.callingUid = callingUid; 136 this.callingPid = callingPid; 137 } 138 } 139 140 @VisibleForTesting 141 static class LauncherAppsImpl extends ILauncherApps.Stub { 142 private static final boolean DEBUG = false; 143 private static final String TAG = "LauncherAppsService"; 144 145 private final Context mContext; 146 private final UserManager mUm; 147 private final IPackageManager mIPM; 148 private final UserManagerInternal mUserManagerInternal; 149 private final UsageStatsManagerInternal mUsageStatsManagerInternal; 150 private final ActivityManagerInternal mActivityManagerInternal; 151 private final ActivityTaskManagerInternal mActivityTaskManagerInternal; 152 private final ShortcutServiceInternal mShortcutServiceInternal; 153 private final PackageManagerInternal mPackageManagerInternal; 154 private final PackageCallbackList<IOnAppsChangedListener> mListeners 155 = new PackageCallbackList<IOnAppsChangedListener>(); 156 private final DevicePolicyManager mDpm; 157 158 private final PackageRemovedListener mPackageRemovedListener = 159 new PackageRemovedListener(); 160 private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); 161 162 @GuardedBy("mListeners") 163 private boolean mIsWatchingPackageBroadcasts = false; 164 165 private final ShortcutChangeHandler mShortcutChangeHandler; 166 167 private final Handler mCallbackHandler; 168 169 private PackageInstallerService mPackageInstallerService; 170 LauncherAppsImpl(Context context)171 public LauncherAppsImpl(Context context) { 172 mContext = context; 173 mIPM = AppGlobals.getPackageManager(); 174 mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 175 mUserManagerInternal = Objects.requireNonNull( 176 LocalServices.getService(UserManagerInternal.class)); 177 mUsageStatsManagerInternal = Objects.requireNonNull( 178 LocalServices.getService(UsageStatsManagerInternal.class)); 179 mActivityManagerInternal = Objects.requireNonNull( 180 LocalServices.getService(ActivityManagerInternal.class)); 181 mActivityTaskManagerInternal = Objects.requireNonNull( 182 LocalServices.getService(ActivityTaskManagerInternal.class)); 183 mShortcutServiceInternal = Objects.requireNonNull( 184 LocalServices.getService(ShortcutServiceInternal.class)); 185 mPackageManagerInternal = Objects.requireNonNull( 186 LocalServices.getService(PackageManagerInternal.class)); 187 mShortcutServiceInternal.addListener(mPackageMonitor); 188 mShortcutChangeHandler = new ShortcutChangeHandler(mUserManagerInternal); 189 mShortcutServiceInternal.addShortcutChangeCallback(mShortcutChangeHandler); 190 mCallbackHandler = BackgroundThread.getHandler(); 191 mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 192 } 193 194 @VisibleForTesting injectBinderCallingUid()195 int injectBinderCallingUid() { 196 return getCallingUid(); 197 } 198 199 @VisibleForTesting injectBinderCallingPid()200 int injectBinderCallingPid() { 201 return getCallingPid(); 202 } 203 injectCallingUserId()204 final int injectCallingUserId() { 205 return UserHandle.getUserId(injectBinderCallingUid()); 206 } 207 208 @VisibleForTesting injectClearCallingIdentity()209 long injectClearCallingIdentity() { 210 return Binder.clearCallingIdentity(); 211 } 212 213 // Injection point. 214 @VisibleForTesting injectRestoreCallingIdentity(long token)215 void injectRestoreCallingIdentity(long token) { 216 Binder.restoreCallingIdentity(token); 217 } 218 getCallingUserId()219 private int getCallingUserId() { 220 return UserHandle.getUserId(injectBinderCallingUid()); 221 } 222 223 /* 224 * @see android.content.pm.ILauncherApps#addOnAppsChangedListener 225 */ 226 @Override addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener)227 public void addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener) 228 throws RemoteException { 229 verifyCallingPackage(callingPackage); 230 synchronized (mListeners) { 231 if (DEBUG) { 232 Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle()); 233 } 234 if (mListeners.getRegisteredCallbackCount() == 0) { 235 if (DEBUG) { 236 Log.d(TAG, "Starting package monitoring"); 237 } 238 startWatchingPackageBroadcasts(); 239 } 240 mListeners.unregister(listener); 241 mListeners.register(listener, new BroadcastCookie(UserHandle.of(getCallingUserId()), 242 callingPackage, injectBinderCallingPid(), injectBinderCallingUid())); 243 } 244 } 245 246 /* 247 * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener 248 */ 249 @Override removeOnAppsChangedListener(IOnAppsChangedListener listener)250 public void removeOnAppsChangedListener(IOnAppsChangedListener listener) 251 throws RemoteException { 252 synchronized (mListeners) { 253 if (DEBUG) { 254 Log.d(TAG, "Removing listener from " + Binder.getCallingUserHandle()); 255 } 256 mListeners.unregister(listener); 257 if (mListeners.getRegisteredCallbackCount() == 0) { 258 stopWatchingPackageBroadcasts(); 259 } 260 } 261 } 262 263 /** 264 * @see android.content.pm.ILauncherApps#registerPackageInstallerCallback 265 */ 266 @Override registerPackageInstallerCallback(String callingPackage, IPackageInstallerCallback callback)267 public void registerPackageInstallerCallback(String callingPackage, 268 IPackageInstallerCallback callback) { 269 verifyCallingPackage(callingPackage); 270 UserHandle callingIdUserHandle = new UserHandle(getCallingUserId()); 271 getPackageInstallerService().registerCallback(callback, eventUserId -> 272 isEnabledProfileOf(callingIdUserHandle, 273 new UserHandle(eventUserId), "shouldReceiveEvent")); 274 } 275 276 @Override getAllSessions(String callingPackage)277 public ParceledListSlice<SessionInfo> getAllSessions(String callingPackage) { 278 verifyCallingPackage(callingPackage); 279 List<SessionInfo> sessionInfos = new ArrayList<>(); 280 int[] userIds = mUm.getEnabledProfileIds(getCallingUserId()); 281 final long token = Binder.clearCallingIdentity(); 282 try { 283 for (int userId : userIds) { 284 sessionInfos.addAll(getPackageInstallerService().getAllSessions(userId) 285 .getList()); 286 } 287 } finally { 288 Binder.restoreCallingIdentity(token); 289 } 290 return new ParceledListSlice<>(sessionInfos); 291 } 292 getPackageInstallerService()293 private PackageInstallerService getPackageInstallerService() { 294 if (mPackageInstallerService == null) { 295 mPackageInstallerService = ((PackageInstallerService) ((PackageManagerService) 296 ServiceManager.getService("package")).getPackageInstaller()); 297 } 298 return mPackageInstallerService; 299 } 300 301 /** 302 * Register a receiver to watch for package broadcasts 303 */ startWatchingPackageBroadcasts()304 private void startWatchingPackageBroadcasts() { 305 if (!mIsWatchingPackageBroadcasts) { 306 final IntentFilter filter = new IntentFilter(); 307 filter.addAction(Intent.ACTION_PACKAGE_REMOVED_INTERNAL); 308 filter.addDataScheme("package"); 309 mContext.registerReceiverAsUser(mPackageRemovedListener, UserHandle.ALL, filter, 310 /* broadcastPermission= */ null, mCallbackHandler); 311 mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler); 312 mIsWatchingPackageBroadcasts = true; 313 } 314 } 315 316 /** 317 * Unregister package broadcast receiver 318 */ stopWatchingPackageBroadcasts()319 private void stopWatchingPackageBroadcasts() { 320 if (DEBUG) { 321 Log.d(TAG, "Stopped watching for packages"); 322 } 323 if (mIsWatchingPackageBroadcasts) { 324 mContext.unregisterReceiver(mPackageRemovedListener); 325 mPackageMonitor.unregister(); 326 mIsWatchingPackageBroadcasts = false; 327 } 328 } 329 checkCallbackCount()330 void checkCallbackCount() { 331 synchronized (mListeners) { 332 if (DEBUG) { 333 Log.d(TAG, "Callback count = " + mListeners.getRegisteredCallbackCount()); 334 } 335 if (mListeners.getRegisteredCallbackCount() == 0) { 336 stopWatchingPackageBroadcasts(); 337 } 338 } 339 } 340 341 /** 342 * Checks if the calling user is in the same group as {@code targetUser}, and allowed 343 * to access it. 344 * 345 * @return TRUE if the calling user can access {@code targetUserId}. FALSE if not *but 346 * they're still in the same profile group*. 347 * 348 * @throws SecurityException if the calling user and {@code targetUser} are not in the same 349 * group. 350 */ canAccessProfile(int targetUserId, String message)351 private boolean canAccessProfile(int targetUserId, String message) { 352 final int callingUserId = injectCallingUserId(); 353 354 if (targetUserId == callingUserId) return true; 355 if (injectHasInteractAcrossUsersFullPermission(injectBinderCallingPid(), 356 injectBinderCallingUid())) { 357 return true; 358 } 359 360 long ident = injectClearCallingIdentity(); 361 try { 362 final UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); 363 if (callingUserInfo != null && callingUserInfo.isProfile()) { 364 Slog.w(TAG, message + " for another profile " 365 + targetUserId + " from " + callingUserId + " not allowed"); 366 return false; 367 } 368 } finally { 369 injectRestoreCallingIdentity(ident); 370 } 371 372 return mUserManagerInternal.isProfileAccessible(injectCallingUserId(), targetUserId, 373 message, true); 374 } 375 376 @VisibleForTesting // We override it in unit tests verifyCallingPackage(String callingPackage)377 void verifyCallingPackage(String callingPackage) { 378 int packageUid = -1; 379 try { 380 packageUid = AppGlobals.getPackageManager().getPackageUid(callingPackage, 381 PackageManager.MATCH_DIRECT_BOOT_AWARE 382 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 383 | PackageManager.MATCH_UNINSTALLED_PACKAGES, 384 UserHandle.getUserId(getCallingUid())); 385 } catch (RemoteException ignore) { 386 } 387 if (packageUid < 0) { 388 Log.e(TAG, "Package not found: " + callingPackage); 389 } 390 if (packageUid != injectBinderCallingUid()) { 391 throw new SecurityException("Calling package name mismatch"); 392 } 393 } 394 getHiddenAppActivityInfo(String packageName, int callingUid, UserHandle user)395 private LauncherActivityInfoInternal getHiddenAppActivityInfo(String packageName, 396 int callingUid, UserHandle user) { 397 Intent intent = new Intent(); 398 intent.setComponent(new ComponentName(packageName, 399 PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)); 400 final List<LauncherActivityInfoInternal> apps = queryIntentLauncherActivities(intent, 401 callingUid, user); 402 if (apps.size() > 0) { 403 return apps.get(0); 404 } 405 return null; 406 } 407 408 @Override shouldHideFromSuggestions(String packageName, UserHandle user)409 public boolean shouldHideFromSuggestions(String packageName, UserHandle user) { 410 if (!canAccessProfile(user.getIdentifier(), "cannot get shouldHideFromSuggestions")) { 411 return false; 412 } 413 final int flags = mPackageManagerInternal.getDistractingPackageRestrictions(packageName, 414 user.getIdentifier()); 415 return (flags & PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS) != 0; 416 } 417 418 @Override getLauncherActivities( String callingPackage, String packageName, UserHandle user)419 public ParceledListSlice<LauncherActivityInfoInternal> getLauncherActivities( 420 String callingPackage, String packageName, UserHandle user) throws RemoteException { 421 ParceledListSlice<LauncherActivityInfoInternal> launcherActivities = 422 queryActivitiesForUser(callingPackage, 423 new Intent(Intent.ACTION_MAIN) 424 .addCategory(Intent.CATEGORY_LAUNCHER) 425 .setPackage(packageName), 426 user); 427 if (Settings.Global.getInt(mContext.getContentResolver(), 428 Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 1) == 0) { 429 return launcherActivities; 430 } 431 if (launcherActivities == null) { 432 // Cannot access profile, so we don't even return any hidden apps. 433 return null; 434 } 435 436 final int callingUid = injectBinderCallingUid(); 437 final long ident = injectClearCallingIdentity(); 438 try { 439 if (mUm.getUserInfo(user.getIdentifier()).isManagedProfile()) { 440 // Managed profile should not show hidden apps 441 return launcherActivities; 442 } 443 if (mDpm.getDeviceOwnerComponentOnAnyUser() != null) { 444 // Device owner devices should not show hidden apps 445 return launcherActivities; 446 } 447 448 final ArrayList<LauncherActivityInfoInternal> result = new ArrayList<>( 449 launcherActivities.getList()); 450 if (packageName != null) { 451 // If this hidden app should not be shown, return the original list. 452 // Otherwise, inject hidden activity that forwards user to app details page. 453 if (result.size() > 0) { 454 return launcherActivities; 455 } 456 final ApplicationInfo appInfo = mPackageManagerInternal.getApplicationInfo( 457 packageName, /* flags= */ 0, callingUid, user.getIdentifier()); 458 if (shouldShowSyntheticActivity(user, appInfo)) { 459 LauncherActivityInfoInternal info = getHiddenAppActivityInfo(packageName, 460 callingUid, user); 461 if (info != null) { 462 result.add(info); 463 } 464 } 465 return new ParceledListSlice<>(result); 466 } 467 final HashSet<String> visiblePackages = new HashSet<>(); 468 for (LauncherActivityInfoInternal info : result) { 469 visiblePackages.add(info.getActivityInfo().packageName); 470 } 471 final List<ApplicationInfo> installedPackages = 472 mPackageManagerInternal.getInstalledApplications(/* flags= */ 0, 473 user.getIdentifier(), callingUid); 474 for (ApplicationInfo applicationInfo : installedPackages) { 475 if (!visiblePackages.contains(applicationInfo.packageName)) { 476 if (!shouldShowSyntheticActivity(user, applicationInfo)) { 477 continue; 478 } 479 LauncherActivityInfoInternal info = getHiddenAppActivityInfo( 480 applicationInfo.packageName, callingUid, user); 481 if (info != null) { 482 result.add(info); 483 } 484 } 485 } 486 return new ParceledListSlice<>(result); 487 } finally { 488 injectRestoreCallingIdentity(ident); 489 } 490 } 491 shouldShowSyntheticActivity(UserHandle user, ApplicationInfo appInfo)492 private boolean shouldShowSyntheticActivity(UserHandle user, ApplicationInfo appInfo) { 493 if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) { 494 return false; 495 } 496 if (isManagedProfileAdmin(user, appInfo.packageName)) { 497 return false; 498 } 499 final AndroidPackage pkg = mPackageManagerInternal.getPackage(appInfo.packageName); 500 if (pkg == null) { 501 // Should not happen, but we shouldn't be failing if it does 502 return false; 503 } 504 // If app does not have any default enabled launcher activity or any permissions, 505 // the app can legitimately have no icon so we do not show the synthetic activity. 506 return requestsPermissions(pkg) && hasDefaultEnableLauncherActivity( 507 appInfo.packageName); 508 } 509 requestsPermissions(@onNull AndroidPackage pkg)510 private boolean requestsPermissions(@NonNull AndroidPackage pkg) { 511 return !ArrayUtils.isEmpty(pkg.getRequestedPermissions()); 512 } 513 hasDefaultEnableLauncherActivity(@onNull String packageName)514 private boolean hasDefaultEnableLauncherActivity(@NonNull String packageName) { 515 final Intent matchIntent = new Intent(Intent.ACTION_MAIN); 516 matchIntent.addCategory(Intent.CATEGORY_LAUNCHER); 517 matchIntent.setPackage(packageName); 518 final List<ResolveInfo> infoList = mPackageManagerInternal.queryIntentActivities( 519 matchIntent, matchIntent.resolveTypeIfNeeded(mContext.getContentResolver()), 520 PackageManager.MATCH_DISABLED_COMPONENTS, Binder.getCallingUid(), 521 getCallingUserId()); 522 final int size = infoList.size(); 523 for (int i = 0; i < size; i++) { 524 if (infoList.get(i).activityInfo.enabled) { 525 return true; 526 } 527 } 528 return false; 529 } 530 isManagedProfileAdmin(UserHandle user, String packageName)531 private boolean isManagedProfileAdmin(UserHandle user, String packageName) { 532 final List<UserInfo> userInfoList = mUm.getProfiles(user.getIdentifier()); 533 for (int i = 0; i < userInfoList.size(); i++) { 534 UserInfo userInfo = userInfoList.get(i); 535 if (!userInfo.isManagedProfile()) { 536 continue; 537 } 538 ComponentName componentName = mDpm.getProfileOwnerAsUser(userInfo.getUserHandle()); 539 if (componentName == null) { 540 continue; 541 } 542 if (componentName.getPackageName().equals(packageName)) { 543 return true; 544 } 545 } 546 return false; 547 } 548 549 @Override resolveLauncherActivityInternal( String callingPackage, ComponentName component, UserHandle user)550 public LauncherActivityInfoInternal resolveLauncherActivityInternal( 551 String callingPackage, ComponentName component, UserHandle user) 552 throws RemoteException { 553 if (!canAccessProfile(user.getIdentifier(), "Cannot resolve activity")) { 554 return null; 555 } 556 557 final int callingUid = injectBinderCallingUid(); 558 final long ident = Binder.clearCallingIdentity(); 559 try { 560 final ActivityInfo activityInfo = mPackageManagerInternal.getActivityInfo(component, 561 PackageManager.MATCH_DIRECT_BOOT_AWARE 562 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 563 callingUid, user.getIdentifier()); 564 if (activityInfo == null) { 565 return null; 566 } 567 if (component == null || component.getPackageName() == null) { 568 // should not happen 569 return null; 570 } 571 final IncrementalStatesInfo incrementalStatesInfo = 572 mPackageManagerInternal.getIncrementalStatesInfo(component.getPackageName(), 573 callingUid, user.getIdentifier()); 574 if (incrementalStatesInfo == null) { 575 // package does not exist; should not happen 576 return null; 577 } 578 return new LauncherActivityInfoInternal(activityInfo, incrementalStatesInfo); 579 } finally { 580 Binder.restoreCallingIdentity(ident); 581 } 582 } 583 584 @Override getShortcutConfigActivities( String callingPackage, String packageName, UserHandle user)585 public ParceledListSlice getShortcutConfigActivities( 586 String callingPackage, String packageName, UserHandle user) 587 throws RemoteException { 588 return queryActivitiesForUser(callingPackage, 589 new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user); 590 } 591 queryActivitiesForUser( String callingPackage, Intent intent, UserHandle user)592 private ParceledListSlice<LauncherActivityInfoInternal> queryActivitiesForUser( 593 String callingPackage, Intent intent, UserHandle user) { 594 if (!canAccessProfile(user.getIdentifier(), "Cannot retrieve activities")) { 595 return null; 596 } 597 final int callingUid = injectBinderCallingUid(); 598 long ident = injectClearCallingIdentity(); 599 try { 600 return new ParceledListSlice<>(queryIntentLauncherActivities(intent, callingUid, 601 user)); 602 } finally { 603 injectRestoreCallingIdentity(ident); 604 } 605 } 606 queryIntentLauncherActivities( Intent intent, int callingUid, UserHandle user)607 private List<LauncherActivityInfoInternal> queryIntentLauncherActivities( 608 Intent intent, int callingUid, UserHandle user) { 609 final List<ResolveInfo> apps = mPackageManagerInternal.queryIntentActivities(intent, 610 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 611 PackageManager.MATCH_DIRECT_BOOT_AWARE 612 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 613 callingUid, user.getIdentifier()); 614 final int numResolveInfos = apps.size(); 615 List<LauncherActivityInfoInternal> results = new ArrayList<>(); 616 for (int i = 0; i < numResolveInfos; i++) { 617 final ResolveInfo ri = apps.get(i); 618 final String packageName = ri.activityInfo.packageName; 619 if (packageName == null) { 620 // should not happen 621 continue; 622 } 623 final IncrementalStatesInfo incrementalStatesInfo = 624 mPackageManagerInternal.getIncrementalStatesInfo(packageName, callingUid, 625 user.getIdentifier()); 626 if (incrementalStatesInfo == null) { 627 // package doesn't exist any more; should not happen 628 continue; 629 } 630 results.add(new LauncherActivityInfoInternal(ri.activityInfo, 631 incrementalStatesInfo)); 632 } 633 return results; 634 } 635 636 @Override getShortcutConfigActivityIntent(String callingPackage, ComponentName component, UserHandle user)637 public IntentSender getShortcutConfigActivityIntent(String callingPackage, 638 ComponentName component, UserHandle user) throws RemoteException { 639 ensureShortcutPermission(callingPackage); 640 if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { 641 return null; 642 } 643 Objects.requireNonNull(component); 644 645 // All right, create the sender. 646 final int callingUid = injectBinderCallingUid(); 647 final long identity = Binder.clearCallingIdentity(); 648 try { 649 Intent packageIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT) 650 .setPackage(component.getPackageName()); 651 List<ResolveInfo> apps = 652 mPackageManagerInternal.queryIntentActivities(packageIntent, 653 packageIntent.resolveTypeIfNeeded(mContext.getContentResolver()), 654 PackageManager.MATCH_DIRECT_BOOT_AWARE 655 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 656 callingUid, user.getIdentifier()); 657 // ensure that the component is present in the list 658 if (!apps.stream().anyMatch( 659 ri -> component.getClassName().equals(ri.activityInfo.name))) { 660 return null; 661 } 662 663 Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component); 664 final PendingIntent pi = PendingIntent.getActivityAsUser( 665 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT 666 | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT, 667 null, user); 668 return pi == null ? null : pi.getIntentSender(); 669 } finally { 670 Binder.restoreCallingIdentity(identity); 671 } 672 } 673 674 /** 675 * Returns the intents for a specific shortcut. 676 */ 677 @Nullable 678 @Override getShortcutIntent(@onNull final String callingPackage, @NonNull final String packageName, @NonNull final String shortcutId, @Nullable final Bundle opts, @NonNull final UserHandle user)679 public PendingIntent getShortcutIntent(@NonNull final String callingPackage, 680 @NonNull final String packageName, @NonNull final String shortcutId, 681 @Nullable final Bundle opts, @NonNull final UserHandle user) 682 throws RemoteException { 683 Objects.requireNonNull(callingPackage); 684 Objects.requireNonNull(packageName); 685 Objects.requireNonNull(shortcutId); 686 Objects.requireNonNull(user); 687 688 ensureShortcutPermission(callingPackage); 689 if (!canAccessProfile(user.getIdentifier(), "Cannot get shortcuts")) { 690 return null; 691 } 692 693 final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( 694 getCallingUserId(), callingPackage, packageName, shortcutId, 695 user.getIdentifier(), injectBinderCallingPid(), injectBinderCallingUid()); 696 if (intents == null || intents.length == 0) { 697 return null; 698 } 699 final long ident = Binder.clearCallingIdentity(); 700 try { 701 return injectCreatePendingIntent(0 /* requestCode */, intents, 702 FLAG_IMMUTABLE | FLAG_UPDATE_CURRENT, opts, packageName, 703 mPackageManagerInternal.getPackageUid( 704 packageName, PackageManager.MATCH_DIRECT_BOOT_AUTO, 705 user.getIdentifier())); 706 } finally { 707 Binder.restoreCallingIdentity(ident); 708 } 709 } 710 711 @Override isPackageEnabled(String callingPackage, String packageName, UserHandle user)712 public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user) 713 throws RemoteException { 714 if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { 715 return false; 716 } 717 718 final int callingUid = injectBinderCallingUid(); 719 final long ident = Binder.clearCallingIdentity(); 720 try { 721 final PackageInfo info = mPackageManagerInternal.getPackageInfo(packageName, 722 PackageManager.MATCH_DIRECT_BOOT_AWARE 723 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 724 callingUid, user.getIdentifier()); 725 return info != null && info.applicationInfo.enabled; 726 } finally { 727 Binder.restoreCallingIdentity(ident); 728 } 729 } 730 731 @Override getSuspendedPackageLauncherExtras(String packageName, UserHandle user)732 public Bundle getSuspendedPackageLauncherExtras(String packageName, 733 UserHandle user) { 734 if (!canAccessProfile(user.getIdentifier(), "Cannot get launcher extras")) { 735 return null; 736 } 737 return mPackageManagerInternal.getSuspendedPackageLauncherExtras(packageName, 738 user.getIdentifier()); 739 } 740 741 @Override getApplicationInfo( String callingPackage, String packageName, int flags, UserHandle user)742 public ApplicationInfo getApplicationInfo( 743 String callingPackage, String packageName, int flags, UserHandle user) 744 throws RemoteException { 745 if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { 746 return null; 747 } 748 749 final int callingUid = injectBinderCallingUid(); 750 final long ident = Binder.clearCallingIdentity(); 751 try { 752 final ApplicationInfo info = mPackageManagerInternal.getApplicationInfo(packageName, 753 flags, callingUid, user.getIdentifier()); 754 return info; 755 } finally { 756 Binder.restoreCallingIdentity(ident); 757 } 758 } 759 760 @Override getAppUsageLimit(String callingPackage, String packageName, UserHandle user)761 public LauncherApps.AppUsageLimit getAppUsageLimit(String callingPackage, 762 String packageName, UserHandle user) { 763 verifyCallingPackage(callingPackage); 764 if (!canAccessProfile(user.getIdentifier(), "Cannot access usage limit")) { 765 return null; 766 } 767 if (!mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid())) { 768 throw new SecurityException("Caller is not the recents app"); 769 } 770 771 final UsageStatsManagerInternal.AppUsageLimitData data = 772 mUsageStatsManagerInternal.getAppUsageLimit(packageName, user); 773 if (data == null) { 774 return null; 775 } 776 return new LauncherApps.AppUsageLimit( 777 data.getTotalUsageLimit(), data.getUsageRemaining()); 778 } 779 ensureShortcutPermission(@onNull String callingPackage)780 private void ensureShortcutPermission(@NonNull String callingPackage) { 781 verifyCallingPackage(callingPackage); 782 if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), 783 callingPackage, injectBinderCallingPid(), injectBinderCallingUid())) { 784 throw new SecurityException("Caller can't access shortcut information"); 785 } 786 } 787 ensureStrictAccessShortcutsPermission(@onNull String callingPackage)788 private void ensureStrictAccessShortcutsPermission(@NonNull String callingPackage) { 789 verifyCallingPackage(callingPackage); 790 if (!injectHasAccessShortcutsPermission(injectBinderCallingPid(), 791 injectBinderCallingUid())) { 792 throw new SecurityException("Caller can't access shortcut information"); 793 } 794 } 795 796 /** 797 * Returns true if the caller has the "ACCESS_SHORTCUTS" permission. 798 */ 799 @VisibleForTesting injectHasAccessShortcutsPermission(int callingPid, int callingUid)800 boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) { 801 return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS, 802 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; 803 } 804 805 /** 806 * Returns true if the caller has the "INTERACT_ACROSS_USERS_FULL" permission. 807 */ 808 @VisibleForTesting injectHasInteractAcrossUsersFullPermission(int callingPid, int callingUid)809 boolean injectHasInteractAcrossUsersFullPermission(int callingPid, int callingUid) { 810 return mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, 811 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; 812 } 813 814 @VisibleForTesting injectCreatePendingIntent(int requestCode, @NonNull Intent[] intents, int flags, Bundle options, String ownerPackage, int ownerUserId)815 PendingIntent injectCreatePendingIntent(int requestCode, @NonNull Intent[] intents, 816 int flags, Bundle options, String ownerPackage, int ownerUserId) { 817 return mActivityManagerInternal.getPendingIntentActivityAsApp(requestCode, intents, 818 flags, null /* options */, ownerPackage, ownerUserId); 819 } 820 821 @Override getShortcuts(@onNull final String callingPackage, @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser)822 public ParceledListSlice getShortcuts(@NonNull final String callingPackage, 823 @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser) { 824 ensureShortcutPermission(callingPackage); 825 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) { 826 return new ParceledListSlice<>(Collections.EMPTY_LIST); 827 } 828 829 final long changedSince = query.getChangedSince(); 830 final String packageName = query.getPackage(); 831 final List<String> shortcutIds = query.getShortcutIds(); 832 final List<LocusId> locusIds = query.getLocusIds(); 833 final ComponentName componentName = query.getActivity(); 834 final int flags = query.getQueryFlags(); 835 if (shortcutIds != null && packageName == null) { 836 throw new IllegalArgumentException( 837 "To query by shortcut ID, package name must also be set"); 838 } 839 if (locusIds != null && packageName == null) { 840 throw new IllegalArgumentException( 841 "To query by locus ID, package name must also be set"); 842 } 843 if ((query.getQueryFlags() & ShortcutQuery.FLAG_GET_PERSONS_DATA) != 0) { 844 ensureStrictAccessShortcutsPermission(callingPackage); 845 } 846 847 // TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below. 848 return new ParceledListSlice<>((List<ShortcutInfo>) 849 mShortcutServiceInternal.getShortcuts(getCallingUserId(), 850 callingPackage, changedSince, packageName, shortcutIds, locusIds, 851 componentName, flags, targetUser.getIdentifier(), 852 injectBinderCallingPid(), injectBinderCallingUid())); 853 } 854 855 @Override registerShortcutChangeCallback(@onNull final String callingPackage, @NonNull final ShortcutQueryWrapper query, @NonNull final IShortcutChangeCallback callback)856 public void registerShortcutChangeCallback(@NonNull final String callingPackage, 857 @NonNull final ShortcutQueryWrapper query, 858 @NonNull final IShortcutChangeCallback callback) { 859 860 ensureShortcutPermission(callingPackage); 861 862 if (query.getShortcutIds() != null && query.getPackage() == null) { 863 throw new IllegalArgumentException( 864 "To query by shortcut ID, package name must also be set"); 865 } 866 if (query.getLocusIds() != null && query.getPackage() == null) { 867 throw new IllegalArgumentException( 868 "To query by locus ID, package name must also be set"); 869 } 870 871 UserHandle user = UserHandle.of(injectCallingUserId()); 872 if (injectHasInteractAcrossUsersFullPermission(injectBinderCallingPid(), 873 injectBinderCallingUid())) { 874 user = null; 875 } 876 877 mShortcutChangeHandler.addShortcutChangeCallback(callback, query, user); 878 } 879 880 @Override unregisterShortcutChangeCallback(String callingPackage, IShortcutChangeCallback callback)881 public void unregisterShortcutChangeCallback(String callingPackage, 882 IShortcutChangeCallback callback) { 883 ensureShortcutPermission(callingPackage); 884 885 mShortcutChangeHandler.removeShortcutChangeCallback(callback); 886 } 887 888 @Override pinShortcuts(String callingPackage, String packageName, List<String> ids, UserHandle targetUser)889 public void pinShortcuts(String callingPackage, String packageName, List<String> ids, 890 UserHandle targetUser) { 891 ensureShortcutPermission(callingPackage); 892 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot pin shortcuts")) { 893 return; 894 } 895 896 mShortcutServiceInternal.pinShortcuts(getCallingUserId(), 897 callingPackage, packageName, ids, targetUser.getIdentifier()); 898 } 899 900 @Override cacheShortcuts(String callingPackage, String packageName, List<String> ids, UserHandle targetUser, int cacheFlags)901 public void cacheShortcuts(String callingPackage, String packageName, List<String> ids, 902 UserHandle targetUser, int cacheFlags) { 903 ensureStrictAccessShortcutsPermission(callingPackage); 904 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot cache shortcuts")) { 905 return; 906 } 907 908 mShortcutServiceInternal.cacheShortcuts( 909 getCallingUserId(), callingPackage, packageName, ids, 910 targetUser.getIdentifier(), toShortcutsCacheFlags(cacheFlags)); 911 } 912 913 @Override uncacheShortcuts(String callingPackage, String packageName, List<String> ids, UserHandle targetUser, int cacheFlags)914 public void uncacheShortcuts(String callingPackage, String packageName, List<String> ids, 915 UserHandle targetUser, int cacheFlags) { 916 ensureStrictAccessShortcutsPermission(callingPackage); 917 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot uncache shortcuts")) { 918 return; 919 } 920 921 mShortcutServiceInternal.uncacheShortcuts( 922 getCallingUserId(), callingPackage, packageName, ids, 923 targetUser.getIdentifier(), toShortcutsCacheFlags(cacheFlags)); 924 } 925 926 @Override getShortcutIconResId(String callingPackage, String packageName, String id, int targetUserId)927 public int getShortcutIconResId(String callingPackage, String packageName, String id, 928 int targetUserId) { 929 ensureShortcutPermission(callingPackage); 930 if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) { 931 return 0; 932 } 933 934 return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(), 935 callingPackage, packageName, id, targetUserId); 936 } 937 938 @Override getShortcutIconFd(String callingPackage, String packageName, String id, int targetUserId)939 public ParcelFileDescriptor getShortcutIconFd(String callingPackage, 940 String packageName, String id, int targetUserId) { 941 ensureShortcutPermission(callingPackage); 942 if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) { 943 return null; 944 } 945 946 return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(), 947 callingPackage, packageName, id, targetUserId); 948 } 949 950 @Override getShortcutIconUri(String callingPackage, String packageName, String shortcutId, int userId)951 public String getShortcutIconUri(String callingPackage, String packageName, 952 String shortcutId, int userId) { 953 ensureShortcutPermission(callingPackage); 954 if (!canAccessProfile(userId, "Cannot access shortcuts")) { 955 return null; 956 } 957 958 return mShortcutServiceInternal.getShortcutIconUri(getCallingUserId(), callingPackage, 959 packageName, shortcutId, userId); 960 } 961 962 @Override hasShortcutHostPermission(String callingPackage)963 public boolean hasShortcutHostPermission(String callingPackage) { 964 verifyCallingPackage(callingPackage); 965 return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), 966 callingPackage, injectBinderCallingPid(), injectBinderCallingUid()); 967 } 968 969 @Override startShortcut(String callingPackage, String packageName, String featureId, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int targetUserId)970 public boolean startShortcut(String callingPackage, String packageName, String featureId, 971 String shortcutId, Rect sourceBounds, Bundle startActivityOptions, 972 int targetUserId) { 973 verifyCallingPackage(callingPackage); 974 if (!canAccessProfile(targetUserId, "Cannot start activity")) { 975 return false; 976 } 977 978 // Even without the permission, pinned shortcuts are always launchable. 979 if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(), 980 callingPackage, packageName, shortcutId, targetUserId)) { 981 ensureShortcutPermission(callingPackage); 982 } 983 984 final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( 985 getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId, 986 injectBinderCallingPid(), injectBinderCallingUid()); 987 if (intents == null || intents.length == 0) { 988 return false; 989 } 990 // Note the target activity doesn't have to be exported. 991 992 // Flag for bubble 993 ActivityOptions options = ActivityOptions.fromBundle(startActivityOptions); 994 if (options != null && options.isApplyActivityFlagsForBubbles()) { 995 // Flag for bubble to make behaviour match documentLaunchMode=always. 996 intents[0].addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); 997 intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); 998 } 999 1000 intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1001 intents[0].setSourceBounds(sourceBounds); 1002 1003 // Replace theme for splash screen 1004 final String splashScreenThemeResName = 1005 mShortcutServiceInternal.getShortcutStartingThemeResName(getCallingUserId(), 1006 callingPackage, packageName, shortcutId, targetUserId); 1007 if (splashScreenThemeResName != null && !splashScreenThemeResName.isEmpty()) { 1008 if (startActivityOptions == null) { 1009 startActivityOptions = new Bundle(); 1010 } 1011 startActivityOptions.putString(KEY_SPLASH_SCREEN_THEME, splashScreenThemeResName); 1012 } 1013 return startShortcutIntentsAsPublisher( 1014 intents, packageName, featureId, startActivityOptions, targetUserId); 1015 } 1016 startShortcutIntentsAsPublisher(@onNull Intent[] intents, @NonNull String publisherPackage, @Nullable String publishedFeatureId, Bundle startActivityOptions, int userId)1017 private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, 1018 @NonNull String publisherPackage, @Nullable String publishedFeatureId, 1019 Bundle startActivityOptions, int userId) { 1020 final int code; 1021 try { 1022 code = mActivityTaskManagerInternal.startActivitiesAsPackage(publisherPackage, 1023 publishedFeatureId, userId, intents, startActivityOptions); 1024 if (ActivityManager.isStartResultSuccessful(code)) { 1025 return true; // Success 1026 } else { 1027 Log.e(TAG, "Couldn't start activity, code=" + code); 1028 } 1029 return false; 1030 } catch (SecurityException e) { 1031 if (DEBUG) { 1032 Slog.d(TAG, "SecurityException while launching intent", e); 1033 } 1034 return false; 1035 } 1036 } 1037 1038 @Override isActivityEnabled( String callingPackage, ComponentName component, UserHandle user)1039 public boolean isActivityEnabled( 1040 String callingPackage, ComponentName component, UserHandle user) 1041 throws RemoteException { 1042 if (!canAccessProfile(user.getIdentifier(), "Cannot check component")) { 1043 return false; 1044 } 1045 1046 final int callingUid = injectBinderCallingUid(); 1047 final int state = mPackageManagerInternal.getComponentEnabledSetting(component, 1048 callingUid, user.getIdentifier()); 1049 switch (state) { 1050 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 1051 break; // Need to check the manifest's enabled state. 1052 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 1053 return true; 1054 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 1055 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 1056 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: 1057 return false; 1058 } 1059 1060 final long ident = Binder.clearCallingIdentity(); 1061 try { 1062 final ActivityInfo info = mPackageManagerInternal.getActivityInfo(component, 1063 PackageManager.MATCH_DIRECT_BOOT_AWARE 1064 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 1065 callingUid, user.getIdentifier()); 1066 // Note we don't check "exported" because if the caller has the same UID as the 1067 // callee's UID, it can still be launched. 1068 // (If an app doesn't export a front door activity and causes issues with the 1069 // launcher, that's just the app's bug.) 1070 return info != null && info.isEnabled(); 1071 } finally { 1072 Binder.restoreCallingIdentity(ident); 1073 } 1074 } 1075 1076 @Override startSessionDetailsActivityAsUser(IApplicationThread caller, String callingPackage, String callingFeatureId, SessionInfo sessionInfo, Rect sourceBounds, Bundle opts, UserHandle userHandle)1077 public void startSessionDetailsActivityAsUser(IApplicationThread caller, 1078 String callingPackage, String callingFeatureId, SessionInfo sessionInfo, 1079 Rect sourceBounds, Bundle opts, UserHandle userHandle) throws RemoteException { 1080 int userId = userHandle.getIdentifier(); 1081 if (!canAccessProfile(userId, "Cannot start details activity")) { 1082 return; 1083 } 1084 1085 Intent i = new Intent(Intent.ACTION_VIEW) 1086 .setData(new Uri.Builder() 1087 .scheme("market") 1088 .authority("details") 1089 .appendQueryParameter("id", sessionInfo.appPackageName) 1090 .build()) 1091 .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app") 1092 .authority(callingPackage).build()); 1093 i.setSourceBounds(sourceBounds); 1094 1095 mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, 1096 callingFeatureId, i, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK, opts, 1097 userId); 1098 } 1099 1100 @Override getActivityLaunchIntent(ComponentName component, Bundle opts, UserHandle user)1101 public PendingIntent getActivityLaunchIntent(ComponentName component, Bundle opts, 1102 UserHandle user) { 1103 if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) { 1104 throw new ActivityNotFoundException("Activity could not be found"); 1105 } 1106 1107 final Intent launchIntent = getMainActivityLaunchIntent(component, user); 1108 if (launchIntent == null) { 1109 throw new SecurityException("Attempt to launch activity without " 1110 + " category Intent.CATEGORY_LAUNCHER " + component); 1111 } 1112 1113 final long ident = Binder.clearCallingIdentity(); 1114 try { 1115 // If we reach here, we've verified that the caller has access to the profile and 1116 // is launching an exported activity with CATEGORY_LAUNCHER so we can clear the 1117 // calling identity to mirror the startActivityAsUser() call which does not validate 1118 // the calling user 1119 return PendingIntent.getActivityAsUser(mContext, 0 /* requestCode */, launchIntent, 1120 FLAG_IMMUTABLE, null /* options */, user); 1121 } finally { 1122 Binder.restoreCallingIdentity(ident); 1123 } 1124 } 1125 1126 @Override startActivityAsUser(IApplicationThread caller, String callingPackage, String callingFeatureId, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user)1127 public void startActivityAsUser(IApplicationThread caller, String callingPackage, 1128 String callingFeatureId, ComponentName component, Rect sourceBounds, 1129 Bundle opts, UserHandle user) throws RemoteException { 1130 if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) { 1131 return; 1132 } 1133 1134 Intent launchIntent = getMainActivityLaunchIntent(component, user); 1135 if (launchIntent == null) { 1136 throw new SecurityException("Attempt to launch activity without " 1137 + " category Intent.CATEGORY_LAUNCHER " + component); 1138 } 1139 launchIntent.setSourceBounds(sourceBounds); 1140 1141 mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, 1142 callingFeatureId, launchIntent, /* resultTo= */ null, 1143 Intent.FLAG_ACTIVITY_NEW_TASK, opts, user.getIdentifier()); 1144 } 1145 1146 /** 1147 * Returns the main activity launch intent for the given component package. 1148 */ getMainActivityLaunchIntent(ComponentName component, UserHandle user)1149 private Intent getMainActivityLaunchIntent(ComponentName component, UserHandle user) { 1150 Intent launchIntent = new Intent(Intent.ACTION_MAIN); 1151 launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); 1152 launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1153 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 1154 launchIntent.setPackage(component.getPackageName()); 1155 1156 boolean canLaunch = false; 1157 1158 final int callingUid = injectBinderCallingUid(); 1159 final long ident = Binder.clearCallingIdentity(); 1160 try { 1161 // Check that the component actually has Intent.CATEGORY_LAUCNCHER 1162 // as calling startActivityAsUser ignores the category and just 1163 // resolves based on the component if present. 1164 final List<ResolveInfo> apps = mPackageManagerInternal.queryIntentActivities( 1165 launchIntent, 1166 launchIntent.resolveTypeIfNeeded(mContext.getContentResolver()), 1167 PackageManager.MATCH_DIRECT_BOOT_AWARE 1168 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 1169 callingUid, user.getIdentifier()); 1170 final int size = apps.size(); 1171 for (int i = 0; i < size; ++i) { 1172 ActivityInfo activityInfo = apps.get(i).activityInfo; 1173 if (activityInfo.packageName.equals(component.getPackageName()) && 1174 activityInfo.name.equals(component.getClassName())) { 1175 if (!activityInfo.exported) { 1176 throw new SecurityException("Cannot launch non-exported components " 1177 + component); 1178 } 1179 1180 // Found an activity with category launcher that matches 1181 // this component so ok to launch. 1182 launchIntent.setPackage(null); 1183 launchIntent.setComponent(component); 1184 canLaunch = true; 1185 break; 1186 } 1187 } 1188 if (!canLaunch) { 1189 return null; 1190 } 1191 } finally { 1192 Binder.restoreCallingIdentity(ident); 1193 } 1194 return launchIntent; 1195 } 1196 1197 @Override showAppDetailsAsUser(IApplicationThread caller, String callingPackage, String callingFeatureId, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user)1198 public void showAppDetailsAsUser(IApplicationThread caller, 1199 String callingPackage, String callingFeatureId, ComponentName component, 1200 Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { 1201 if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) { 1202 return; 1203 } 1204 1205 final Intent intent; 1206 final long ident = Binder.clearCallingIdentity(); 1207 try { 1208 String packageName = component.getPackageName(); 1209 int uId = -1; 1210 try { 1211 uId = mContext.getPackageManager().getApplicationInfo( 1212 packageName, PackageManager.MATCH_ANY_USER).uid; 1213 } catch (PackageManager.NameNotFoundException e) { 1214 Log.d(TAG, "package not found: " + e); 1215 } 1216 intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, 1217 Uri.fromParts("package", packageName, null)); 1218 intent.putExtra("uId", uId); 1219 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 1220 intent.setSourceBounds(sourceBounds); 1221 } finally { 1222 Binder.restoreCallingIdentity(ident); 1223 } 1224 mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, 1225 callingFeatureId, intent, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK, 1226 opts, user.getIdentifier()); 1227 } 1228 1229 /** Checks if user is a profile of or same as listeningUser. 1230 * and the user is enabled. */ isEnabledProfileOf(UserHandle listeningUser, UserHandle user, String debugMsg)1231 private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user, 1232 String debugMsg) { 1233 return mUserManagerInternal.isProfileAccessible(listeningUser.getIdentifier(), 1234 user.getIdentifier(), debugMsg, false); 1235 } 1236 1237 /** Returns whether or not the result to the listener should be filtered. */ isPackageVisibleToListener(String packageName, BroadcastCookie cookie)1238 private boolean isPackageVisibleToListener(String packageName, BroadcastCookie cookie) { 1239 return !mPackageManagerInternal.filterAppAccess(packageName, cookie.callingUid, 1240 cookie.user.getIdentifier()); 1241 } 1242 1243 /** Returns whether or not the given appId is in allow list */ isCallingAppIdAllowed(int[] appIdAllowList, @AppIdInt int appId)1244 private static boolean isCallingAppIdAllowed(int[] appIdAllowList, @AppIdInt int appId) { 1245 if (appIdAllowList == null) { 1246 return true; 1247 } 1248 return Arrays.binarySearch(appIdAllowList, appId) > -1; 1249 } 1250 getFilteredPackageNames(String[] packageNames, BroadcastCookie cookie)1251 private String[] getFilteredPackageNames(String[] packageNames, BroadcastCookie cookie) { 1252 final List<String> filteredPackageNames = new ArrayList<>(); 1253 for (String packageName : packageNames) { 1254 if (!isPackageVisibleToListener(packageName, cookie)) { 1255 continue; 1256 } 1257 filteredPackageNames.add(packageName); 1258 } 1259 return filteredPackageNames.toArray(new String[filteredPackageNames.size()]); 1260 } 1261 toShortcutsCacheFlags(int cacheFlags)1262 private int toShortcutsCacheFlags(int cacheFlags) { 1263 int ret = 0; 1264 if (cacheFlags == FLAG_CACHE_NOTIFICATION_SHORTCUTS) { 1265 ret = ShortcutInfo.FLAG_CACHED_NOTIFICATIONS; 1266 } else if (cacheFlags == FLAG_CACHE_BUBBLE_SHORTCUTS) { 1267 ret = ShortcutInfo.FLAG_CACHED_BUBBLES; 1268 } else if (cacheFlags == FLAG_CACHE_PEOPLE_TILE_SHORTCUTS) { 1269 ret = ShortcutInfo.FLAG_CACHED_PEOPLE_TILE; 1270 } 1271 Preconditions.checkArgumentPositive(ret, "Invalid cache owner"); 1272 1273 return ret; 1274 } 1275 1276 @VisibleForTesting postToPackageMonitorHandler(Runnable r)1277 void postToPackageMonitorHandler(Runnable r) { 1278 mCallbackHandler.post(r); 1279 } 1280 1281 /** 1282 * Check all installed apps and if a package is installed via Incremental and not fully 1283 * loaded, register loading progress listener. 1284 */ registerLoadingProgressForIncrementalApps()1285 void registerLoadingProgressForIncrementalApps() { 1286 final List<UserHandle> users = mUm.getUserProfiles(); 1287 if (users == null) { 1288 return; 1289 } 1290 for (UserHandle user : users) { 1291 mPackageManagerInternal.forEachInstalledPackage(pkg -> { 1292 final String packageName = pkg.getPackageName(); 1293 if (mPackageManagerInternal.getIncrementalStatesInfo(packageName, 1294 Process.myUid(), user.getIdentifier()).isLoading()) { 1295 mPackageManagerInternal.registerInstalledLoadingProgressCallback( 1296 packageName, new PackageLoadingProgressCallback(packageName, user), 1297 user.getIdentifier()); 1298 } 1299 }, user.getIdentifier()); 1300 } 1301 } 1302 1303 public static class ShortcutChangeHandler implements LauncherApps.ShortcutChangeCallback { 1304 private final UserManagerInternal mUserManagerInternal; 1305 ShortcutChangeHandler(UserManagerInternal userManager)1306 ShortcutChangeHandler(UserManagerInternal userManager) { 1307 mUserManagerInternal = userManager; 1308 } 1309 1310 private final RemoteCallbackList<IShortcutChangeCallback> mCallbacks = 1311 new RemoteCallbackList<>(); 1312 addShortcutChangeCallback(IShortcutChangeCallback callback, ShortcutQueryWrapper query, UserHandle user)1313 public synchronized void addShortcutChangeCallback(IShortcutChangeCallback callback, 1314 ShortcutQueryWrapper query, UserHandle user) { 1315 mCallbacks.unregister(callback); 1316 mCallbacks.register(callback, new Pair<>(query, user)); 1317 } 1318 removeShortcutChangeCallback( IShortcutChangeCallback callback)1319 public synchronized void removeShortcutChangeCallback( 1320 IShortcutChangeCallback callback) { 1321 mCallbacks.unregister(callback); 1322 } 1323 1324 @Override onShortcutsAddedOrUpdated(String packageName, List<ShortcutInfo> shortcuts, UserHandle user)1325 public void onShortcutsAddedOrUpdated(String packageName, List<ShortcutInfo> shortcuts, 1326 UserHandle user) { 1327 onShortcutEvent(packageName, shortcuts, user, false); 1328 } 1329 1330 @Override onShortcutsRemoved(String packageName, List<ShortcutInfo> shortcuts, UserHandle user)1331 public void onShortcutsRemoved(String packageName, List<ShortcutInfo> shortcuts, 1332 UserHandle user) { 1333 onShortcutEvent(packageName, shortcuts, user, true); 1334 } 1335 onShortcutEvent(String packageName, List<ShortcutInfo> shortcuts, UserHandle user, boolean shortcutsRemoved)1336 private void onShortcutEvent(String packageName, 1337 List<ShortcutInfo> shortcuts, UserHandle user, boolean shortcutsRemoved) { 1338 int count = mCallbacks.beginBroadcast(); 1339 1340 for (int i = 0; i < count; i++) { 1341 final IShortcutChangeCallback callback = mCallbacks.getBroadcastItem(i); 1342 final Pair<ShortcutQueryWrapper, UserHandle> cookie = 1343 (Pair<ShortcutQueryWrapper, UserHandle>) 1344 mCallbacks.getBroadcastCookie(i); 1345 1346 final UserHandle callbackUser = cookie.second; 1347 if (callbackUser != null && !hasUserAccess(callbackUser, user)) { 1348 // Callback owner does not have access to the shortcuts' user. 1349 continue; 1350 } 1351 1352 // Filter the list by query, if any matches exists, send via callback. 1353 List<ShortcutInfo> matchedList = filterShortcutsByQuery(packageName, shortcuts, 1354 cookie.first, shortcutsRemoved); 1355 if (!CollectionUtils.isEmpty(matchedList)) { 1356 try { 1357 if (shortcutsRemoved) { 1358 callback.onShortcutsRemoved(packageName, matchedList, user); 1359 } else { 1360 callback.onShortcutsAddedOrUpdated(packageName, matchedList, user); 1361 } 1362 } catch (RemoteException e) { 1363 // The RemoteCallbackList will take care of removing the dead object. 1364 } 1365 } 1366 } 1367 1368 mCallbacks.finishBroadcast(); 1369 } 1370 filterShortcutsByQuery(String packageName, List<ShortcutInfo> shortcuts, ShortcutQueryWrapper query, boolean shortcutsRemoved)1371 public static List<ShortcutInfo> filterShortcutsByQuery(String packageName, 1372 List<ShortcutInfo> shortcuts, ShortcutQueryWrapper query, 1373 boolean shortcutsRemoved) { 1374 final long changedSince = query.getChangedSince(); 1375 final String queryPackage = query.getPackage(); 1376 final List<String> shortcutIds = query.getShortcutIds(); 1377 final List<LocusId> locusIds = query.getLocusIds(); 1378 final ComponentName activity = query.getActivity(); 1379 final int flags = query.getQueryFlags(); 1380 1381 if (queryPackage != null && !queryPackage.equals(packageName)) { 1382 return null; 1383 } 1384 1385 List<ShortcutInfo> matches = new ArrayList<>(); 1386 1387 final boolean matchDynamic = (flags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0; 1388 final boolean matchPinned = (flags & ShortcutQuery.FLAG_MATCH_PINNED) != 0; 1389 final boolean matchManifest = (flags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0; 1390 final boolean matchCached = (flags & ShortcutQuery.FLAG_MATCH_CACHED) != 0; 1391 final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0) 1392 | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0) 1393 | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) 1394 | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); 1395 1396 for (int i = 0; i < shortcuts.size(); i++) { 1397 final ShortcutInfo si = shortcuts.get(i); 1398 1399 if (activity != null && !activity.equals(si.getActivity())) { 1400 continue; 1401 } 1402 if (changedSince != 0 && changedSince > si.getLastChangedTimestamp()) { 1403 continue; 1404 } 1405 if (shortcutIds != null && !shortcutIds.contains(si.getId())) { 1406 continue; 1407 } 1408 if (locusIds != null && !locusIds.contains(si.getLocusId())) { 1409 continue; 1410 } 1411 if (shortcutsRemoved || (shortcutFlags & si.getFlags()) != 0) { 1412 matches.add(si); 1413 } 1414 } 1415 1416 return matches; 1417 } 1418 hasUserAccess(UserHandle callbackUser, UserHandle shortcutUser)1419 private boolean hasUserAccess(UserHandle callbackUser, UserHandle shortcutUser) { 1420 final int callbackUserId = callbackUser.getIdentifier(); 1421 final int shortcutUserId = shortcutUser.getIdentifier(); 1422 1423 if (shortcutUser == callbackUser) return true; 1424 return mUserManagerInternal.isProfileAccessible(callbackUserId, shortcutUserId, 1425 null, false); 1426 } 1427 } 1428 1429 private class PackageRemovedListener extends BroadcastReceiver { 1430 1431 @Override onReceive(Context context, Intent intent)1432 public void onReceive(Context context, Intent intent) { 1433 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 1434 UserHandle.USER_NULL); 1435 if (userId == UserHandle.USER_NULL) { 1436 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent); 1437 return; 1438 } 1439 final String action = intent.getAction(); 1440 // Handle onPackageRemoved. 1441 if (Intent.ACTION_PACKAGE_REMOVED_INTERNAL.equals(action)) { 1442 final String packageName = getPackageName(intent); 1443 final int[] appIdAllowList = 1444 intent.getIntArrayExtra(Intent.EXTRA_VISIBILITY_ALLOW_LIST); 1445 // If {@link #EXTRA_REPLACING} is true, that will be onPackageChanged case. 1446 if (packageName != null && !intent.getBooleanExtra( 1447 Intent.EXTRA_REPLACING, /* defaultValue= */ false)) { 1448 final UserHandle user = new UserHandle(userId); 1449 final int n = mListeners.beginBroadcast(); 1450 try { 1451 for (int i = 0; i < n; i++) { 1452 final IOnAppsChangedListener listener = 1453 mListeners.getBroadcastItem(i); 1454 final BroadcastCookie cookie = 1455 (BroadcastCookie) mListeners.getBroadcastCookie(i); 1456 if (!isEnabledProfileOf(cookie.user, user, "onPackageRemoved")) { 1457 continue; 1458 } 1459 if (!isCallingAppIdAllowed(appIdAllowList, UserHandle.getAppId( 1460 cookie.callingUid))) { 1461 continue; 1462 } 1463 try { 1464 listener.onPackageRemoved(user, packageName); 1465 } catch (RemoteException re) { 1466 Slog.d(TAG, "Callback failed ", re); 1467 } 1468 } 1469 } finally { 1470 mListeners.finishBroadcast(); 1471 } 1472 } 1473 } 1474 } 1475 getPackageName(Intent intent)1476 private String getPackageName(Intent intent) { 1477 final Uri uri = intent.getData(); 1478 final String pkg = uri != null ? uri.getSchemeSpecificPart() : null; 1479 return pkg; 1480 } 1481 } 1482 1483 private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener { 1484 1485 // TODO Simplify with lambdas. 1486 1487 @Override onPackageAdded(String packageName, int uid)1488 public void onPackageAdded(String packageName, int uid) { 1489 UserHandle user = new UserHandle(getChangingUserId()); 1490 final int n = mListeners.beginBroadcast(); 1491 try { 1492 for (int i = 0; i < n; i++) { 1493 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1494 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1495 if (!isEnabledProfileOf(cookie.user, user, "onPackageAdded")) { 1496 continue; 1497 } 1498 if (!isPackageVisibleToListener(packageName, cookie)) { 1499 continue; 1500 } 1501 try { 1502 listener.onPackageAdded(user, packageName); 1503 } catch (RemoteException re) { 1504 Slog.d(TAG, "Callback failed ", re); 1505 } 1506 } 1507 } finally { 1508 mListeners.finishBroadcast(); 1509 } 1510 super.onPackageAdded(packageName, uid); 1511 mPackageManagerInternal.registerInstalledLoadingProgressCallback(packageName, 1512 new PackageLoadingProgressCallback(packageName, user), 1513 user.getIdentifier()); 1514 } 1515 1516 @Override onPackageModified(String packageName)1517 public void onPackageModified(String packageName) { 1518 onPackageChanged(packageName); 1519 super.onPackageModified(packageName); 1520 } 1521 onPackageChanged(String packageName)1522 private void onPackageChanged(String packageName) { 1523 UserHandle user = new UserHandle(getChangingUserId()); 1524 final int n = mListeners.beginBroadcast(); 1525 try { 1526 for (int i = 0; i < n; i++) { 1527 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1528 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1529 if (!isEnabledProfileOf(cookie.user, user, "onPackageModified")) { 1530 continue; 1531 } 1532 if (!isPackageVisibleToListener(packageName, cookie)) { 1533 continue; 1534 } 1535 try { 1536 listener.onPackageChanged(user, packageName); 1537 } catch (RemoteException re) { 1538 Slog.d(TAG, "Callback failed ", re); 1539 } 1540 } 1541 } finally { 1542 mListeners.finishBroadcast(); 1543 } 1544 } 1545 1546 @Override onPackagesAvailable(String[] packages)1547 public void onPackagesAvailable(String[] packages) { 1548 UserHandle user = new UserHandle(getChangingUserId()); 1549 final int n = mListeners.beginBroadcast(); 1550 try { 1551 for (int i = 0; i < n; i++) { 1552 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1553 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1554 if (!isEnabledProfileOf(cookie.user, user, "onPackagesAvailable")) { 1555 continue; 1556 } 1557 final String[] filteredPackages = getFilteredPackageNames(packages, cookie); 1558 // If all packages are filtered, skip notifying listener. 1559 if (ArrayUtils.isEmpty(filteredPackages)) { 1560 continue; 1561 } 1562 try { 1563 listener.onPackagesAvailable(user, filteredPackages, isReplacing()); 1564 } catch (RemoteException re) { 1565 Slog.d(TAG, "Callback failed ", re); 1566 } 1567 } 1568 } finally { 1569 mListeners.finishBroadcast(); 1570 } 1571 1572 super.onPackagesAvailable(packages); 1573 } 1574 1575 @Override onPackagesUnavailable(String[] packages)1576 public void onPackagesUnavailable(String[] packages) { 1577 UserHandle user = new UserHandle(getChangingUserId()); 1578 final int n = mListeners.beginBroadcast(); 1579 try { 1580 for (int i = 0; i < n; i++) { 1581 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1582 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1583 if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnavailable")) { 1584 continue; 1585 } 1586 final String[] filteredPackages = getFilteredPackageNames(packages, cookie); 1587 // If all packages are filtered, skip notifying listener. 1588 if (ArrayUtils.isEmpty(filteredPackages)) { 1589 continue; 1590 } 1591 try { 1592 listener.onPackagesUnavailable(user, filteredPackages, isReplacing()); 1593 } catch (RemoteException re) { 1594 Slog.d(TAG, "Callback failed ", re); 1595 } 1596 } 1597 } finally { 1598 mListeners.finishBroadcast(); 1599 } 1600 1601 super.onPackagesUnavailable(packages); 1602 } 1603 1604 @Override onPackagesSuspended(String[] packages)1605 public void onPackagesSuspended(String[] packages) { 1606 UserHandle user = new UserHandle(getChangingUserId()); 1607 final ArrayList<Pair<String, Bundle>> packagesWithExtras = new ArrayList<>(); 1608 final ArrayList<String> packagesWithoutExtras = new ArrayList<>(); 1609 for (String pkg : packages) { 1610 final Bundle launcherExtras = 1611 mPackageManagerInternal.getSuspendedPackageLauncherExtras(pkg, 1612 user.getIdentifier()); 1613 if (launcherExtras != null) { 1614 packagesWithExtras.add(new Pair<>(pkg, launcherExtras)); 1615 } else { 1616 packagesWithoutExtras.add(pkg); 1617 } 1618 } 1619 final String[] packagesNullExtras = packagesWithoutExtras.toArray( 1620 new String[packagesWithoutExtras.size()]); 1621 final int n = mListeners.beginBroadcast(); 1622 try { 1623 for (int i = 0; i < n; i++) { 1624 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1625 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1626 if (!isEnabledProfileOf(cookie.user, user, "onPackagesSuspended")) { 1627 continue; 1628 } 1629 final String[] filteredPackagesWithoutExtras = 1630 getFilteredPackageNames(packages, cookie); 1631 // If all packages are filtered, skip notifying listener. 1632 if (ArrayUtils.isEmpty(filteredPackagesWithoutExtras)) { 1633 continue; 1634 } 1635 try { 1636 listener.onPackagesSuspended(user, filteredPackagesWithoutExtras, 1637 /* launcherExtras= */ null); 1638 for (int idx = 0; idx < packagesWithExtras.size(); idx++) { 1639 Pair<String, Bundle> packageExtraPair = packagesWithExtras.get(idx); 1640 if (!isPackageVisibleToListener(packageExtraPair.first, cookie)) { 1641 continue; 1642 } 1643 listener.onPackagesSuspended(user, 1644 new String[]{packageExtraPair.first}, 1645 packageExtraPair.second); 1646 } 1647 } catch (RemoteException re) { 1648 Slog.d(TAG, "Callback failed ", re); 1649 } 1650 } 1651 } finally { 1652 mListeners.finishBroadcast(); 1653 } 1654 } 1655 1656 @Override onPackagesUnsuspended(String[] packages)1657 public void onPackagesUnsuspended(String[] packages) { 1658 UserHandle user = new UserHandle(getChangingUserId()); 1659 final int n = mListeners.beginBroadcast(); 1660 try { 1661 for (int i = 0; i < n; i++) { 1662 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1663 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1664 if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnsuspended")) { 1665 continue; 1666 } 1667 final String[] filteredPackages = getFilteredPackageNames(packages, cookie); 1668 // If all packages are filtered, skip notifying listener. 1669 if (ArrayUtils.isEmpty(filteredPackages)) { 1670 continue; 1671 } 1672 try { 1673 listener.onPackagesUnsuspended(user, filteredPackages); 1674 } catch (RemoteException re) { 1675 Slog.d(TAG, "Callback failed ", re); 1676 } 1677 } 1678 } finally { 1679 mListeners.finishBroadcast(); 1680 } 1681 1682 super.onPackagesUnsuspended(packages); 1683 } 1684 1685 @Override onShortcutChanged(@onNull String packageName, @UserIdInt int userId)1686 public void onShortcutChanged(@NonNull String packageName, 1687 @UserIdInt int userId) { 1688 postToPackageMonitorHandler(() -> onShortcutChangedInner(packageName, userId)); 1689 } 1690 onShortcutChangedInner(@onNull String packageName, @UserIdInt int userId)1691 private void onShortcutChangedInner(@NonNull String packageName, 1692 @UserIdInt int userId) { 1693 final int n = mListeners.beginBroadcast(); 1694 try { 1695 final UserHandle user = UserHandle.of(userId); 1696 1697 for (int i = 0; i < n; i++) { 1698 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1699 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1700 if (!isEnabledProfileOf(cookie.user, user, "onShortcutChanged")) { 1701 continue; 1702 } 1703 if (!isPackageVisibleToListener(packageName, cookie)) { 1704 continue; 1705 } 1706 final int launcherUserId = cookie.user.getIdentifier(); 1707 1708 // Make sure the caller has the permission. 1709 if (!mShortcutServiceInternal.hasShortcutHostPermission( 1710 launcherUserId, cookie.packageName, 1711 cookie.callingPid, cookie.callingUid)) { 1712 continue; 1713 } 1714 // Each launcher has a different set of pinned shortcuts, so we need to do a 1715 // query in here. 1716 // (As of now, only one launcher has the permission at a time, so it's bit 1717 // moot, but we may change the permission model eventually.) 1718 final List<ShortcutInfo> list = 1719 mShortcutServiceInternal.getShortcuts(launcherUserId, 1720 cookie.packageName, 1721 /* changedSince= */ 0, packageName, /* shortcutIds=*/ null, 1722 /* locusIds=*/ null, /* component= */ null, 1723 ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY 1724 | ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED 1725 , userId, cookie.callingPid, cookie.callingUid); 1726 try { 1727 listener.onShortcutChanged(user, packageName, 1728 new ParceledListSlice<>(list)); 1729 } catch (RemoteException re) { 1730 Slog.d(TAG, "Callback failed ", re); 1731 } 1732 1733 } 1734 } catch (RuntimeException e) { 1735 // When the user is locked we get IllegalState, so just catch all. 1736 Log.w(TAG, e.getMessage(), e); 1737 } finally { 1738 mListeners.finishBroadcast(); 1739 } 1740 } 1741 1742 @Override onPackageStateChanged(String packageName, int uid)1743 public void onPackageStateChanged(String packageName, int uid) { 1744 onPackageChanged(packageName); 1745 super.onPackageStateChanged(packageName, uid); 1746 } 1747 } 1748 1749 class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> { 1750 @Override onCallbackDied(T callback, Object cookie)1751 public void onCallbackDied(T callback, Object cookie) { 1752 checkCallbackCount(); 1753 } 1754 } 1755 1756 class PackageLoadingProgressCallback extends 1757 PackageManagerInternal.InstalledLoadingProgressCallback { 1758 private String mPackageName; 1759 private UserHandle mUser; 1760 PackageLoadingProgressCallback(String packageName, UserHandle user)1761 PackageLoadingProgressCallback(String packageName, UserHandle user) { 1762 super(mCallbackHandler); 1763 mPackageName = packageName; 1764 mUser = user; 1765 } 1766 1767 @Override onLoadingProgressChanged(float progress)1768 public void onLoadingProgressChanged(float progress) { 1769 final int n = mListeners.beginBroadcast(); 1770 try { 1771 for (int i = 0; i < n; i++) { 1772 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1773 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1774 if (!isEnabledProfileOf(cookie.user, mUser, "onLoadingProgressChanged")) { 1775 continue; 1776 } 1777 if (!isPackageVisibleToListener(mPackageName, cookie)) { 1778 continue; 1779 } 1780 try { 1781 listener.onPackageLoadingProgressChanged(mUser, mPackageName, progress); 1782 } catch (RemoteException re) { 1783 Slog.d(TAG, "Callback failed ", re); 1784 } 1785 } 1786 } finally { 1787 mListeners.finishBroadcast(); 1788 } 1789 } 1790 } 1791 } 1792 } 1793