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