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