LauncherAppsService.java revision 19b41f34a5cb29c621848e352220017b46cf66f1
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 17package com.android.server.pm; 18 19import android.annotation.NonNull; 20import android.annotation.UserIdInt; 21import android.app.ActivityManager; 22import android.app.ActivityManagerInternal; 23import android.app.AppGlobals; 24import android.app.PendingIntent; 25import android.content.ComponentName; 26import android.content.Context; 27import android.content.Intent; 28import android.content.IntentSender; 29import android.content.pm.ActivityInfo; 30import android.content.pm.ApplicationInfo; 31import android.content.pm.ILauncherApps; 32import android.content.pm.IOnAppsChangedListener; 33import android.content.pm.LauncherApps.ShortcutQuery; 34import android.content.pm.PackageInfo; 35import android.content.pm.PackageManager; 36import android.content.pm.PackageManagerInternal; 37import android.content.pm.ParceledListSlice; 38import android.content.pm.ResolveInfo; 39import android.content.pm.ShortcutInfo; 40import android.content.pm.ShortcutServiceInternal; 41import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; 42import android.graphics.Rect; 43import android.net.Uri; 44import android.os.Binder; 45import android.os.Bundle; 46import android.os.Handler; 47import android.os.IInterface; 48import android.os.ParcelFileDescriptor; 49import android.os.RemoteCallbackList; 50import android.os.RemoteException; 51import android.os.UserHandle; 52import android.os.UserManagerInternal; 53import android.provider.Settings; 54import android.util.Log; 55import android.util.Slog; 56 57import com.android.internal.annotations.VisibleForTesting; 58import com.android.internal.content.PackageMonitor; 59import com.android.internal.os.BackgroundThread; 60import com.android.internal.util.Preconditions; 61import com.android.server.LocalServices; 62import com.android.server.SystemService; 63 64import java.util.Collections; 65import java.util.List; 66 67/** 68 * Service that manages requests and callbacks for launchers that support 69 * managed profiles. 70 */ 71public class LauncherAppsService extends SystemService { 72 73 private final LauncherAppsImpl mLauncherAppsImpl; 74 75 public LauncherAppsService(Context context) { 76 super(context); 77 mLauncherAppsImpl = new LauncherAppsImpl(context); 78 } 79 80 @Override 81 public void onStart() { 82 publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl); 83 } 84 85 static class BroadcastCookie { 86 public final UserHandle user; 87 public final String packageName; 88 public final int callingUid; 89 public final int callingPid; 90 91 BroadcastCookie(UserHandle userHandle, String packageName, int callingPid, int callingUid) { 92 this.user = userHandle; 93 this.packageName = packageName; 94 this.callingUid = callingUid; 95 this.callingPid = callingPid; 96 } 97 } 98 99 @VisibleForTesting 100 static class LauncherAppsImpl extends ILauncherApps.Stub { 101 private static final boolean DEBUG = false; 102 private static final String TAG = "LauncherAppsService"; 103 private final Context mContext; 104 private final UserManagerInternal mUserManagerInternal; 105 private final ActivityManagerInternal mActivityManagerInternal; 106 private final ShortcutServiceInternal mShortcutServiceInternal; 107 private final PackageCallbackList<IOnAppsChangedListener> mListeners 108 = new PackageCallbackList<IOnAppsChangedListener>(); 109 110 private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); 111 112 private final Handler mCallbackHandler; 113 114 public LauncherAppsImpl(Context context) { 115 mContext = context; 116 mUserManagerInternal = Preconditions.checkNotNull( 117 LocalServices.getService(UserManagerInternal.class)); 118 mActivityManagerInternal = Preconditions.checkNotNull( 119 LocalServices.getService(ActivityManagerInternal.class)); 120 mShortcutServiceInternal = Preconditions.checkNotNull( 121 LocalServices.getService(ShortcutServiceInternal.class)); 122 mShortcutServiceInternal.addListener(mPackageMonitor); 123 mCallbackHandler = BackgroundThread.getHandler(); 124 } 125 126 @VisibleForTesting 127 int injectBinderCallingUid() { 128 return getCallingUid(); 129 } 130 131 @VisibleForTesting 132 int injectBinderCallingPid() { 133 return getCallingPid(); 134 } 135 136 final int injectCallingUserId() { 137 return UserHandle.getUserId(injectBinderCallingUid()); 138 } 139 140 @VisibleForTesting 141 long injectClearCallingIdentity() { 142 return Binder.clearCallingIdentity(); 143 } 144 145 // Injection point. 146 @VisibleForTesting 147 void injectRestoreCallingIdentity(long token) { 148 Binder.restoreCallingIdentity(token); 149 } 150 151 private int getCallingUserId() { 152 return UserHandle.getUserId(injectBinderCallingUid()); 153 } 154 155 /* 156 * @see android.content.pm.ILauncherApps#addOnAppsChangedListener( 157 * android.content.pm.IOnAppsChangedListener) 158 */ 159 @Override 160 public void addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener) 161 throws RemoteException { 162 verifyCallingPackage(callingPackage); 163 synchronized (mListeners) { 164 if (DEBUG) { 165 Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle()); 166 } 167 if (mListeners.getRegisteredCallbackCount() == 0) { 168 if (DEBUG) { 169 Log.d(TAG, "Starting package monitoring"); 170 } 171 startWatchingPackageBroadcasts(); 172 } 173 mListeners.unregister(listener); 174 mListeners.register(listener, new BroadcastCookie(UserHandle.of(getCallingUserId()), 175 callingPackage, injectBinderCallingPid(), injectBinderCallingUid())); 176 } 177 } 178 179 /* 180 * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener( 181 * android.content.pm.IOnAppsChangedListener) 182 */ 183 @Override 184 public void removeOnAppsChangedListener(IOnAppsChangedListener listener) 185 throws RemoteException { 186 synchronized (mListeners) { 187 if (DEBUG) { 188 Log.d(TAG, "Removing listener from " + Binder.getCallingUserHandle()); 189 } 190 mListeners.unregister(listener); 191 if (mListeners.getRegisteredCallbackCount() == 0) { 192 stopWatchingPackageBroadcasts(); 193 } 194 } 195 } 196 197 /** 198 * Register a receiver to watch for package broadcasts 199 */ 200 private void startWatchingPackageBroadcasts() { 201 mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler); 202 } 203 204 /** 205 * Unregister package broadcast receiver 206 */ 207 private void stopWatchingPackageBroadcasts() { 208 if (DEBUG) { 209 Log.d(TAG, "Stopped watching for packages"); 210 } 211 mPackageMonitor.unregister(); 212 } 213 214 void checkCallbackCount() { 215 synchronized (mListeners) { 216 if (DEBUG) { 217 Log.d(TAG, "Callback count = " + mListeners.getRegisteredCallbackCount()); 218 } 219 if (mListeners.getRegisteredCallbackCount() == 0) { 220 stopWatchingPackageBroadcasts(); 221 } 222 } 223 } 224 225 /** 226 * Checks if the calling user is in the same group as {@code targetUser}, and allowed 227 * to access it. 228 * 229 * @return TRUE if the calling user can access {@code targetUserId}. FALSE if not *but 230 * they're still in the same profile group*. 231 * 232 * @throws SecurityException if the calling user and {@code targetUser} are not in the same 233 * group. 234 */ 235 private boolean canAccessProfile(int targetUserId, String message) { 236 return mUserManagerInternal.isProfileAccessible(injectCallingUserId(), targetUserId, 237 message, true); 238 } 239 240 @VisibleForTesting // We override it in unit tests 241 void verifyCallingPackage(String callingPackage) { 242 int packageUid = -1; 243 try { 244 packageUid = AppGlobals.getPackageManager().getPackageUid(callingPackage, 245 PackageManager.MATCH_DIRECT_BOOT_AWARE 246 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 247 | PackageManager.MATCH_UNINSTALLED_PACKAGES, 248 UserHandle.getUserId(getCallingUid())); 249 } catch (RemoteException ignore) { 250 } 251 if (packageUid < 0) { 252 Log.e(TAG, "Package not found: " + callingPackage); 253 } 254 if (packageUid != injectBinderCallingUid()) { 255 throw new SecurityException("Calling package name mismatch"); 256 } 257 } 258 259 @Override 260 public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage, 261 String packageName, UserHandle user) 262 throws RemoteException { 263 return queryActivitiesForUser(callingPackage, 264 new Intent(Intent.ACTION_MAIN) 265 .addCategory(Intent.CATEGORY_LAUNCHER) 266 .setPackage(packageName), 267 user); 268 } 269 270 @Override 271 public ActivityInfo resolveActivity( 272 String callingPackage, ComponentName component, UserHandle user) 273 throws RemoteException { 274 if (!canAccessProfile(user.getIdentifier(), "Cannot resolve activity")) { 275 return null; 276 } 277 278 final int callingUid = injectBinderCallingUid(); 279 long ident = Binder.clearCallingIdentity(); 280 try { 281 final PackageManagerInternal pmInt = 282 LocalServices.getService(PackageManagerInternal.class); 283 return pmInt.getActivityInfo(component, 284 PackageManager.MATCH_DIRECT_BOOT_AWARE 285 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 286 callingUid, user.getIdentifier()); 287 } finally { 288 Binder.restoreCallingIdentity(ident); 289 } 290 } 291 292 @Override 293 public ParceledListSlice getShortcutConfigActivities( 294 String callingPackage, String packageName, UserHandle user) 295 throws RemoteException { 296 return queryActivitiesForUser(callingPackage, 297 new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user); 298 } 299 300 private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage, 301 Intent intent, UserHandle user) { 302 if (!canAccessProfile(user.getIdentifier(), "Cannot retrieve activities")) { 303 return null; 304 } 305 306 final int callingUid = injectBinderCallingUid(); 307 long ident = injectClearCallingIdentity(); 308 try { 309 final PackageManagerInternal pmInt = 310 LocalServices.getService(PackageManagerInternal.class); 311 List<ResolveInfo> apps = pmInt.queryIntentActivities(intent, 312 PackageManager.MATCH_DIRECT_BOOT_AWARE 313 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 314 callingUid, user.getIdentifier()); 315 return new ParceledListSlice<>(apps); 316 } finally { 317 injectRestoreCallingIdentity(ident); 318 } 319 } 320 321 @Override 322 public IntentSender getShortcutConfigActivityIntent(String callingPackage, 323 ComponentName component, UserHandle user) throws RemoteException { 324 ensureShortcutPermission(callingPackage); 325 if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { 326 return null; 327 } 328 Preconditions.checkNotNull(component); 329 330 // All right, create the sender. 331 Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component); 332 final long identity = Binder.clearCallingIdentity(); 333 try { 334 final PendingIntent pi = PendingIntent.getActivityAsUser( 335 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT 336 | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT, 337 null, user); 338 return pi == null ? null : pi.getIntentSender(); 339 } finally { 340 Binder.restoreCallingIdentity(identity); 341 } 342 } 343 344 @Override 345 public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user) 346 throws RemoteException { 347 if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { 348 return false; 349 } 350 351 final int callingUid = injectBinderCallingUid(); 352 long ident = Binder.clearCallingIdentity(); 353 try { 354 final PackageManagerInternal pmInt = 355 LocalServices.getService(PackageManagerInternal.class); 356 PackageInfo info = pmInt.getPackageInfo(packageName, 357 PackageManager.MATCH_DIRECT_BOOT_AWARE 358 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 359 callingUid, user.getIdentifier()); 360 return info != null && info.applicationInfo.enabled; 361 } finally { 362 Binder.restoreCallingIdentity(ident); 363 } 364 } 365 366 @Override 367 public Bundle getSuspendedPackageLauncherExtras(String packageName, 368 UserHandle user) { 369 if (!canAccessProfile(user.getIdentifier(), "Cannot get launcher extras")) { 370 return null; 371 } 372 final PackageManagerInternal pmi = 373 LocalServices.getService(PackageManagerInternal.class); 374 return pmi.getSuspendedPackageLauncherExtras(packageName, user.getIdentifier()); 375 } 376 377 @Override 378 public ApplicationInfo getApplicationInfo( 379 String callingPackage, String packageName, int flags, UserHandle user) 380 throws RemoteException { 381 if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { 382 return null; 383 } 384 385 final int callingUid = injectBinderCallingUid(); 386 long ident = Binder.clearCallingIdentity(); 387 try { 388 final PackageManagerInternal pmInt = 389 LocalServices.getService(PackageManagerInternal.class); 390 ApplicationInfo info = pmInt.getApplicationInfo(packageName, flags, 391 callingUid, user.getIdentifier()); 392 return info; 393 } finally { 394 Binder.restoreCallingIdentity(ident); 395 } 396 } 397 398 private void ensureShortcutPermission(@NonNull String callingPackage) { 399 verifyCallingPackage(callingPackage); 400 if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), 401 callingPackage, injectBinderCallingPid(), injectBinderCallingUid())) { 402 throw new SecurityException("Caller can't access shortcut information"); 403 } 404 } 405 406 @Override 407 public ParceledListSlice getShortcuts(String callingPackage, long changedSince, 408 String packageName, List shortcutIds, ComponentName componentName, int flags, 409 UserHandle targetUser) { 410 ensureShortcutPermission(callingPackage); 411 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) { 412 return new ParceledListSlice<>(Collections.EMPTY_LIST); 413 } 414 if (shortcutIds != null && packageName == null) { 415 throw new IllegalArgumentException( 416 "To query by shortcut ID, package name must also be set"); 417 } 418 419 // TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below. 420 return new ParceledListSlice<>((List<ShortcutInfo>) 421 mShortcutServiceInternal.getShortcuts(getCallingUserId(), 422 callingPackage, changedSince, packageName, shortcutIds, 423 componentName, flags, targetUser.getIdentifier(), 424 injectBinderCallingPid(), injectBinderCallingUid())); 425 } 426 427 @Override 428 public void pinShortcuts(String callingPackage, String packageName, List<String> ids, 429 UserHandle targetUser) { 430 ensureShortcutPermission(callingPackage); 431 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot pin shortcuts")) { 432 return; 433 } 434 435 mShortcutServiceInternal.pinShortcuts(getCallingUserId(), 436 callingPackage, packageName, ids, targetUser.getIdentifier()); 437 } 438 439 @Override 440 public int getShortcutIconResId(String callingPackage, String packageName, String id, 441 int targetUserId) { 442 ensureShortcutPermission(callingPackage); 443 if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) { 444 return 0; 445 } 446 447 return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(), 448 callingPackage, packageName, id, targetUserId); 449 } 450 451 @Override 452 public ParcelFileDescriptor getShortcutIconFd(String callingPackage, 453 String packageName, String id, int targetUserId) { 454 ensureShortcutPermission(callingPackage); 455 if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) { 456 return null; 457 } 458 459 return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(), 460 callingPackage, packageName, id, targetUserId); 461 } 462 463 @Override 464 public boolean hasShortcutHostPermission(String callingPackage) { 465 verifyCallingPackage(callingPackage); 466 return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), 467 callingPackage, injectBinderCallingPid(), injectBinderCallingUid()); 468 } 469 470 @Override 471 public boolean startShortcut(String callingPackage, String packageName, String shortcutId, 472 Rect sourceBounds, Bundle startActivityOptions, int targetUserId) { 473 verifyCallingPackage(callingPackage); 474 if (!canAccessProfile(targetUserId, "Cannot start activity")) { 475 return false; 476 } 477 478 // Even without the permission, pinned shortcuts are always launchable. 479 if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(), 480 callingPackage, packageName, shortcutId, targetUserId)) { 481 ensureShortcutPermission(callingPackage); 482 } 483 484 final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( 485 getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId, 486 injectBinderCallingPid(), injectBinderCallingUid()); 487 if (intents == null || intents.length == 0) { 488 return false; 489 } 490 // Note the target activity doesn't have to be exported. 491 492 intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 493 intents[0].setSourceBounds(sourceBounds); 494 495 return startShortcutIntentsAsPublisher( 496 intents, packageName, startActivityOptions, targetUserId); 497 } 498 499 private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, 500 @NonNull String publisherPackage, Bundle startActivityOptions, int userId) { 501 final int code; 502 try { 503 code = mActivityManagerInternal.startActivitiesAsPackage(publisherPackage, 504 userId, intents, startActivityOptions); 505 if (ActivityManager.isStartResultSuccessful(code)) { 506 return true; // Success 507 } else { 508 Log.e(TAG, "Couldn't start activity, code=" + code); 509 } 510 return false; 511 } catch (SecurityException e) { 512 if (DEBUG) { 513 Slog.d(TAG, "SecurityException while launching intent", e); 514 } 515 return false; 516 } 517 } 518 519 @Override 520 public boolean isActivityEnabled( 521 String callingPackage, ComponentName component, UserHandle user) 522 throws RemoteException { 523 if (!canAccessProfile(user.getIdentifier(), "Cannot check component")) { 524 return false; 525 } 526 527 final int callingUid = injectBinderCallingUid(); 528 long ident = Binder.clearCallingIdentity(); 529 try { 530 final PackageManagerInternal pmInt = 531 LocalServices.getService(PackageManagerInternal.class); 532 ActivityInfo info = pmInt.getActivityInfo(component, 533 PackageManager.MATCH_DIRECT_BOOT_AWARE 534 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 535 callingUid, user.getIdentifier()); 536 return info != null; 537 } finally { 538 Binder.restoreCallingIdentity(ident); 539 } 540 } 541 542 @Override 543 public void startActivityAsUser(String callingPackage, 544 ComponentName component, Rect sourceBounds, 545 Bundle opts, UserHandle user) throws RemoteException { 546 if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) { 547 return; 548 } 549 550 Intent launchIntent = new Intent(Intent.ACTION_MAIN); 551 launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); 552 launchIntent.setSourceBounds(sourceBounds); 553 launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 554 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 555 launchIntent.setPackage(component.getPackageName()); 556 557 final int callingUid = injectBinderCallingUid(); 558 long ident = Binder.clearCallingIdentity(); 559 try { 560 final PackageManagerInternal pmInt = 561 LocalServices.getService(PackageManagerInternal.class); 562 ActivityInfo info = pmInt.getActivityInfo(component, 563 PackageManager.MATCH_DIRECT_BOOT_AWARE 564 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 565 callingUid, user.getIdentifier()); 566 if (!info.exported) { 567 throw new SecurityException("Cannot launch non-exported components " 568 + component); 569 } 570 571 // Check that the component actually has Intent.CATEGORY_LAUCNCHER 572 // as calling startActivityAsUser ignores the category and just 573 // resolves based on the component if present. 574 List<ResolveInfo> apps = pmInt.queryIntentActivities(launchIntent, 575 PackageManager.MATCH_DIRECT_BOOT_AWARE 576 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 577 callingUid, user.getIdentifier()); 578 final int size = apps.size(); 579 for (int i = 0; i < size; ++i) { 580 ActivityInfo activityInfo = apps.get(i).activityInfo; 581 if (activityInfo.packageName.equals(component.getPackageName()) && 582 activityInfo.name.equals(component.getClassName())) { 583 // Found an activity with category launcher that matches 584 // this component so ok to launch. 585 launchIntent.setPackage(null); 586 launchIntent.setComponent(component); 587 mContext.startActivityAsUser(launchIntent, opts, user); 588 return; 589 } 590 } 591 throw new SecurityException("Attempt to launch activity without " 592 + " category Intent.CATEGORY_LAUNCHER " + component); 593 } finally { 594 Binder.restoreCallingIdentity(ident); 595 } 596 } 597 598 @Override 599 public void showAppDetailsAsUser(String callingPackage, ComponentName component, 600 Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { 601 if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) { 602 return; 603 } 604 605 long ident = Binder.clearCallingIdentity(); 606 try { 607 String packageName = component.getPackageName(); 608 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, 609 Uri.fromParts("package", packageName, null)); 610 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 611 intent.setSourceBounds(sourceBounds); 612 mContext.startActivityAsUser(intent, opts, user); 613 } finally { 614 Binder.restoreCallingIdentity(ident); 615 } 616 } 617 618 /** Checks if user is a profile of or same as listeningUser. 619 * and the user is enabled. */ 620 private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user, 621 String debugMsg) { 622 return mUserManagerInternal.isProfileAccessible(listeningUser.getIdentifier(), 623 user.getIdentifier(), debugMsg, false); 624 } 625 626 @VisibleForTesting 627 void postToPackageMonitorHandler(Runnable r) { 628 mCallbackHandler.post(r); 629 } 630 631 private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener { 632 633 // TODO Simplify with lambdas. 634 635 @Override 636 public void onPackageAdded(String packageName, int uid) { 637 UserHandle user = new UserHandle(getChangingUserId()); 638 final int n = mListeners.beginBroadcast(); 639 try { 640 for (int i = 0; i < n; i++) { 641 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 642 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 643 if (!isEnabledProfileOf(cookie.user, user, "onPackageAdded")) continue; 644 try { 645 listener.onPackageAdded(user, packageName); 646 } catch (RemoteException re) { 647 Slog.d(TAG, "Callback failed ", re); 648 } 649 } 650 } finally { 651 mListeners.finishBroadcast(); 652 } 653 654 super.onPackageAdded(packageName, uid); 655 } 656 657 @Override 658 public void onPackageRemoved(String packageName, int uid) { 659 UserHandle user = new UserHandle(getChangingUserId()); 660 final int n = mListeners.beginBroadcast(); 661 try { 662 for (int i = 0; i < n; i++) { 663 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 664 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 665 if (!isEnabledProfileOf(cookie.user, user, "onPackageRemoved")) continue; 666 try { 667 listener.onPackageRemoved(user, packageName); 668 } catch (RemoteException re) { 669 Slog.d(TAG, "Callback failed ", re); 670 } 671 } 672 } finally { 673 mListeners.finishBroadcast(); 674 } 675 676 super.onPackageRemoved(packageName, uid); 677 } 678 679 @Override 680 public void onPackageModified(String packageName) { 681 UserHandle user = new UserHandle(getChangingUserId()); 682 final int n = mListeners.beginBroadcast(); 683 try { 684 for (int i = 0; i < n; i++) { 685 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 686 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 687 if (!isEnabledProfileOf(cookie.user, user, "onPackageModified")) continue; 688 try { 689 listener.onPackageChanged(user, packageName); 690 } catch (RemoteException re) { 691 Slog.d(TAG, "Callback failed ", re); 692 } 693 } 694 } finally { 695 mListeners.finishBroadcast(); 696 } 697 698 super.onPackageModified(packageName); 699 } 700 701 @Override 702 public void onPackagesAvailable(String[] packages) { 703 UserHandle user = new UserHandle(getChangingUserId()); 704 final int n = mListeners.beginBroadcast(); 705 try { 706 for (int i = 0; i < n; i++) { 707 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 708 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 709 if (!isEnabledProfileOf(cookie.user, user, "onPackagesAvailable")) continue; 710 try { 711 listener.onPackagesAvailable(user, packages, isReplacing()); 712 } catch (RemoteException re) { 713 Slog.d(TAG, "Callback failed ", re); 714 } 715 } 716 } finally { 717 mListeners.finishBroadcast(); 718 } 719 720 super.onPackagesAvailable(packages); 721 } 722 723 @Override 724 public void onPackagesUnavailable(String[] packages) { 725 UserHandle user = new UserHandle(getChangingUserId()); 726 final int n = mListeners.beginBroadcast(); 727 try { 728 for (int i = 0; i < n; i++) { 729 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 730 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 731 if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnavailable")) continue; 732 try { 733 listener.onPackagesUnavailable(user, packages, isReplacing()); 734 } catch (RemoteException re) { 735 Slog.d(TAG, "Callback failed ", re); 736 } 737 } 738 } finally { 739 mListeners.finishBroadcast(); 740 } 741 742 super.onPackagesUnavailable(packages); 743 } 744 745 @Override 746 public void onPackagesSuspended(String[] packages, Bundle launcherExtras) { 747 UserHandle user = new UserHandle(getChangingUserId()); 748 final int n = mListeners.beginBroadcast(); 749 try { 750 for (int i = 0; i < n; i++) { 751 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 752 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 753 if (!isEnabledProfileOf(cookie.user, user, "onPackagesSuspended")) continue; 754 try { 755 listener.onPackagesSuspended(user, packages, launcherExtras); 756 } catch (RemoteException re) { 757 Slog.d(TAG, "Callback failed ", re); 758 } 759 } 760 } finally { 761 mListeners.finishBroadcast(); 762 } 763 764 super.onPackagesSuspended(packages, launcherExtras); 765 } 766 767 @Override 768 public void onPackagesUnsuspended(String[] packages) { 769 UserHandle user = new UserHandle(getChangingUserId()); 770 final int n = mListeners.beginBroadcast(); 771 try { 772 for (int i = 0; i < n; i++) { 773 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 774 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 775 if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnsuspended")) continue; 776 try { 777 listener.onPackagesUnsuspended(user, packages); 778 } catch (RemoteException re) { 779 Slog.d(TAG, "Callback failed ", re); 780 } 781 } 782 } finally { 783 mListeners.finishBroadcast(); 784 } 785 786 super.onPackagesUnsuspended(packages); 787 } 788 789 @Override 790 public void onShortcutChanged(@NonNull String packageName, 791 @UserIdInt int userId) { 792 postToPackageMonitorHandler(() -> onShortcutChangedInner(packageName, userId)); 793 } 794 795 private void onShortcutChangedInner(@NonNull String packageName, 796 @UserIdInt int userId) { 797 final int n = mListeners.beginBroadcast(); 798 try { 799 final UserHandle user = UserHandle.of(userId); 800 801 for (int i = 0; i < n; i++) { 802 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 803 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 804 if (!isEnabledProfileOf(cookie.user, user, "onShortcutChanged")) continue; 805 806 final int launcherUserId = cookie.user.getIdentifier(); 807 808 // Make sure the caller has the permission. 809 if (!mShortcutServiceInternal.hasShortcutHostPermission( 810 launcherUserId, cookie.packageName, 811 cookie.callingPid, cookie.callingUid)) { 812 continue; 813 } 814 // Each launcher has a different set of pinned shortcuts, so we need to do a 815 // query in here. 816 // (As of now, only one launcher has the permission at a time, so it's bit 817 // moot, but we may change the permission model eventually.) 818 final List<ShortcutInfo> list = 819 mShortcutServiceInternal.getShortcuts(launcherUserId, 820 cookie.packageName, 821 /* changedSince= */ 0, packageName, /* shortcutIds=*/ null, 822 /* component= */ null, 823 ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY 824 | ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED 825 , userId, cookie.callingPid, cookie.callingUid); 826 try { 827 listener.onShortcutChanged(user, packageName, 828 new ParceledListSlice<>(list)); 829 } catch (RemoteException re) { 830 Slog.d(TAG, "Callback failed ", re); 831 } 832 } 833 } catch (RuntimeException e) { 834 // When the user is locked we get IllegalState, so just catch all. 835 Log.w(TAG, e.getMessage(), e); 836 } finally { 837 mListeners.finishBroadcast(); 838 } 839 } 840 } 841 842 class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> { 843 @Override 844 public void onCallbackDied(T callback, Object cookie) { 845 checkCallbackCount(); 846 } 847 } 848 } 849} 850