LauncherAppsService.java revision 86389b3edc86994b8f59a4562ce2a499294d96bf
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 // TODO: Make it SecurityException. See b/34650921 236 // throw new SecurityException(message + " for another profile " + targetUserId); 237 238 // TODO: Report caller package name. 239 Slog.wtfStack(TAG, message + " for another profile " + targetUserId 240 + " from " + callingUserId); 241 } 242 243 UserInfo targetUserInfo = mUm.getUserInfo(targetUserId); 244 if (targetUserInfo == null 245 || targetUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID 246 || targetUserInfo.profileGroupId != callingUserInfo.profileGroupId) { 247 throw new SecurityException(message + " for unrelated profile " + targetUserId); 248 } 249 } finally { 250 injectRestoreCallingIdentity(ident); 251 } 252 } 253 254 @VisibleForTesting // We override it in unit tests 255 void verifyCallingPackage(String callingPackage) { 256 int packageUid = -1; 257 try { 258 packageUid = mPm.getPackageUidAsUser(callingPackage, 259 PackageManager.MATCH_DIRECT_BOOT_AWARE 260 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 261 | PackageManager.MATCH_UNINSTALLED_PACKAGES, 262 UserHandle.getUserId(getCallingUid())); 263 } catch (NameNotFoundException e) { 264 Log.e(TAG, "Package not found: " + callingPackage); 265 } 266 if (packageUid != Binder.getCallingUid()) { 267 throw new SecurityException("Calling package name mismatch"); 268 } 269 } 270 271 /** 272 * Checks if the user is enabled. 273 */ 274 private boolean isUserEnabled(UserHandle user) { 275 return isUserEnabled(user.getIdentifier()); 276 } 277 278 private boolean isUserEnabled(int userId) { 279 long ident = injectClearCallingIdentity(); 280 try { 281 UserInfo targetUserInfo = mUm.getUserInfo(userId); 282 return targetUserInfo != null && targetUserInfo.isEnabled(); 283 } finally { 284 injectRestoreCallingIdentity(ident); 285 } 286 } 287 288 @Override 289 public ParceledListSlice<ResolveInfo> getLauncherActivities(String packageName, UserHandle user) 290 throws RemoteException { 291 return queryActivitiesForUser( 292 new Intent(Intent.ACTION_MAIN) 293 .addCategory(Intent.CATEGORY_LAUNCHER) 294 .setPackage(packageName), 295 user); 296 } 297 298 @Override 299 public ActivityInfo resolveActivity(ComponentName component, UserHandle user) 300 throws RemoteException { 301 ensureInUserProfiles(user, "Cannot resolve activity"); 302 if (!isUserEnabled(user)) { 303 return null; 304 } 305 306 long ident = Binder.clearCallingIdentity(); 307 try { 308 IPackageManager pm = AppGlobals.getPackageManager(); 309 return pm.getActivityInfo(component, 310 PackageManager.MATCH_DIRECT_BOOT_AWARE 311 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 312 user.getIdentifier()); 313 } finally { 314 Binder.restoreCallingIdentity(ident); 315 } 316 } 317 318 @Override 319 public ParceledListSlice getShortcutConfigActivities(String packageName, UserHandle user) 320 throws RemoteException { 321 return queryActivitiesForUser( 322 new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user); 323 } 324 325 private ParceledListSlice<ResolveInfo> queryActivitiesForUser(Intent intent, 326 UserHandle user) { 327 ensureInUserProfiles(user, "Cannot retrieve activities"); 328 if (!isUserEnabled(user)) { 329 return null; 330 } 331 332 long ident = injectClearCallingIdentity(); 333 try { 334 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(intent, 335 PackageManager.MATCH_DIRECT_BOOT_AWARE 336 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 337 user.getIdentifier()); 338 return new ParceledListSlice<>(apps); 339 } finally { 340 injectRestoreCallingIdentity(ident); 341 } 342 } 343 344 @Override 345 public IntentSender getShortcutConfigActivityIntent(String callingPackage, 346 ComponentName component, UserHandle user) throws RemoteException { 347 ensureShortcutPermission(callingPackage, user); 348 Preconditions.checkNotNull(component); 349 Preconditions.checkArgument(isUserEnabled(user), "User not enabled"); 350 351 // All right, create the sender. 352 Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component); 353 final long identity = Binder.clearCallingIdentity(); 354 try { 355 return PendingIntent.getActivityAsUser( 356 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT 357 | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT, 358 null, user) 359 .getIntentSender(); 360 } finally { 361 Binder.restoreCallingIdentity(identity); 362 } 363 } 364 365 @Override 366 public boolean isPackageEnabled(String packageName, UserHandle user) 367 throws RemoteException { 368 ensureInUserProfiles(user, "Cannot check package"); 369 if (!isUserEnabled(user)) { 370 return false; 371 } 372 373 long ident = Binder.clearCallingIdentity(); 374 try { 375 IPackageManager pm = AppGlobals.getPackageManager(); 376 PackageInfo info = pm.getPackageInfo(packageName, 377 PackageManager.MATCH_DIRECT_BOOT_AWARE 378 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 379 user.getIdentifier()); 380 return info != null && info.applicationInfo.enabled; 381 } finally { 382 Binder.restoreCallingIdentity(ident); 383 } 384 } 385 386 @Override 387 public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) 388 throws RemoteException { 389 ensureInUserProfiles(user, "Cannot check package"); 390 if (!isUserEnabled(user)) { 391 return null; 392 } 393 394 long ident = Binder.clearCallingIdentity(); 395 try { 396 IPackageManager pm = AppGlobals.getPackageManager(); 397 ApplicationInfo info = pm.getApplicationInfo(packageName, flags, 398 user.getIdentifier()); 399 return info; 400 } finally { 401 Binder.restoreCallingIdentity(ident); 402 } 403 } 404 405 private void ensureShortcutPermission(@NonNull String callingPackage, UserHandle user) { 406 ensureShortcutPermission(callingPackage, user.getIdentifier()); 407 } 408 409 private void ensureShortcutPermission(@NonNull String callingPackage, int userId) { 410 verifyCallingPackage(callingPackage); 411 ensureInUserProfiles(userId, "Cannot access shortcuts"); 412 413 if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), 414 callingPackage)) { 415 throw new SecurityException("Caller can't access shortcut information"); 416 } 417 } 418 419 @Override 420 public ParceledListSlice getShortcuts(String callingPackage, long changedSince, 421 String packageName, List shortcutIds, ComponentName componentName, int flags, 422 UserHandle user) { 423 ensureShortcutPermission(callingPackage, user); 424 if (!isUserEnabled(user)) { 425 return new ParceledListSlice<>(new ArrayList(0)); 426 } 427 if (shortcutIds != null && packageName == null) { 428 throw new IllegalArgumentException( 429 "To query by shortcut ID, package name must also be set"); 430 } 431 432 // TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below. 433 return new ParceledListSlice<>((List<ShortcutInfo>) 434 mShortcutServiceInternal.getShortcuts(getCallingUserId(), 435 callingPackage, changedSince, packageName, shortcutIds, 436 componentName, flags, user.getIdentifier())); 437 } 438 439 @Override 440 public void pinShortcuts(String callingPackage, String packageName, List<String> ids, 441 UserHandle user) { 442 ensureShortcutPermission(callingPackage, user); 443 if (!isUserEnabled(user)) { 444 throw new IllegalStateException("Cannot pin shortcuts for disabled profile " 445 + user); 446 } 447 448 mShortcutServiceInternal.pinShortcuts(getCallingUserId(), 449 callingPackage, packageName, ids, user.getIdentifier()); 450 } 451 452 @Override 453 public int getShortcutIconResId(String callingPackage, String packageName, String id, 454 int userId) { 455 ensureShortcutPermission(callingPackage, userId); 456 if (!isUserEnabled(userId)) { 457 return 0; 458 } 459 460 return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(), 461 callingPackage, packageName, id, userId); 462 } 463 464 @Override 465 public ParcelFileDescriptor getShortcutIconFd(String callingPackage, 466 String packageName, String id, int userId) { 467 ensureShortcutPermission(callingPackage, userId); 468 if (!isUserEnabled(userId)) { 469 return null; 470 } 471 472 return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(), 473 callingPackage, packageName, id, userId); 474 } 475 476 @Override 477 public boolean hasShortcutHostPermission(String callingPackage) { 478 verifyCallingPackage(callingPackage); 479 return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), 480 callingPackage); 481 } 482 483 @Override 484 public boolean startShortcut(String callingPackage, String packageName, String shortcutId, 485 Rect sourceBounds, Bundle startActivityOptions, int userId) { 486 verifyCallingPackage(callingPackage); 487 ensureInUserProfiles(userId, "Cannot start activity"); 488 489 if (!isUserEnabled(userId)) { 490 throw new IllegalStateException("Cannot start a shortcut for disabled profile " 491 + userId); 492 } 493 494 // Even without the permission, pinned shortcuts are always launchable. 495 if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(), 496 callingPackage, packageName, shortcutId, userId)) { 497 ensureShortcutPermission(callingPackage, userId); 498 } 499 500 final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( 501 getCallingUserId(), callingPackage, packageName, shortcutId, userId); 502 if (intents == null || intents.length == 0) { 503 return false; 504 } 505 // Note the target activity doesn't have to be exported. 506 507 intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 508 intents[0].setSourceBounds(sourceBounds); 509 510 return startShortcutIntentsAsPublisher( 511 intents, packageName, startActivityOptions, userId); 512 } 513 514 private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, 515 @NonNull String publisherPackage, Bundle startActivityOptions, int userId) { 516 final int code; 517 final long ident = injectClearCallingIdentity(); 518 try { 519 code = mActivityManagerInternal.startActivitiesAsPackage(publisherPackage, 520 userId, intents, startActivityOptions); 521 if (code >= ActivityManager.START_SUCCESS) { 522 return true; // Success 523 } else { 524 Log.e(TAG, "Couldn't start activity, code=" + code); 525 } 526 return code >= ActivityManager.START_SUCCESS; 527 } catch (SecurityException e) { 528 if (DEBUG) { 529 Slog.d(TAG, "SecurityException while launching intent", e); 530 } 531 return false; 532 } finally { 533 injectRestoreCallingIdentity(ident); 534 } 535 } 536 537 @Override 538 public boolean isActivityEnabled(ComponentName component, UserHandle user) 539 throws RemoteException { 540 ensureInUserProfiles(user, "Cannot check component"); 541 if (!isUserEnabled(user)) { 542 return false; 543 } 544 545 long ident = Binder.clearCallingIdentity(); 546 try { 547 IPackageManager pm = AppGlobals.getPackageManager(); 548 ActivityInfo info = pm.getActivityInfo(component, 549 PackageManager.MATCH_DIRECT_BOOT_AWARE 550 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 551 user.getIdentifier()); 552 return info != null; 553 } finally { 554 Binder.restoreCallingIdentity(ident); 555 } 556 } 557 558 @Override 559 public void startActivityAsUser(ComponentName component, Rect sourceBounds, 560 Bundle opts, UserHandle user) throws RemoteException { 561 ensureInUserProfiles(user, "Cannot start activity"); 562 if (!isUserEnabled(user)) { 563 throw new IllegalStateException("Cannot start activity for disabled profile " + user); 564 } 565 566 Intent launchIntent = new Intent(Intent.ACTION_MAIN); 567 launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); 568 launchIntent.setSourceBounds(sourceBounds); 569 launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 570 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 571 launchIntent.setPackage(component.getPackageName()); 572 573 long ident = Binder.clearCallingIdentity(); 574 try { 575 IPackageManager pm = AppGlobals.getPackageManager(); 576 ActivityInfo info = pm.getActivityInfo(component, 577 PackageManager.MATCH_DIRECT_BOOT_AWARE 578 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 579 user.getIdentifier()); 580 if (!info.exported) { 581 throw new SecurityException("Cannot launch non-exported components " 582 + component); 583 } 584 585 // Check that the component actually has Intent.CATEGORY_LAUCNCHER 586 // as calling startActivityAsUser ignores the category and just 587 // resolves based on the component if present. 588 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(launchIntent, 589 PackageManager.MATCH_DIRECT_BOOT_AWARE 590 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 591 user.getIdentifier()); 592 final int size = apps.size(); 593 for (int i = 0; i < size; ++i) { 594 ActivityInfo activityInfo = apps.get(i).activityInfo; 595 if (activityInfo.packageName.equals(component.getPackageName()) && 596 activityInfo.name.equals(component.getClassName())) { 597 // Found an activity with category launcher that matches 598 // this component so ok to launch. 599 launchIntent.setComponent(component); 600 mContext.startActivityAsUser(launchIntent, opts, user); 601 return; 602 } 603 } 604 throw new SecurityException("Attempt to launch activity without " 605 + " category Intent.CATEGORY_LAUNCHER " + component); 606 } finally { 607 Binder.restoreCallingIdentity(ident); 608 } 609 } 610 611 @Override 612 public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds, 613 Bundle opts, UserHandle user) throws RemoteException { 614 ensureInUserProfiles(user, "Cannot show app details"); 615 if (!isUserEnabled(user)) { 616 throw new IllegalStateException("Cannot show app details for disabled profile " 617 + user); 618 } 619 620 long ident = Binder.clearCallingIdentity(); 621 try { 622 String packageName = component.getPackageName(); 623 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, 624 Uri.fromParts("package", packageName, null)); 625 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 626 intent.setSourceBounds(sourceBounds); 627 mContext.startActivityAsUser(intent, opts, user); 628 } finally { 629 Binder.restoreCallingIdentity(ident); 630 } 631 } 632 633 /** Checks if user is a profile of or same as listeningUser. 634 * and the user is enabled. */ 635 private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, 636 String debugMsg) { 637 if (user.getIdentifier() == listeningUser.getIdentifier()) { 638 if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg); 639 return true; 640 } 641 long ident = injectClearCallingIdentity(); 642 try { 643 UserInfo userInfo = mUm.getUserInfo(user.getIdentifier()); 644 UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier()); 645 if (userInfo == null || listeningUserInfo == null 646 || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID 647 || userInfo.profileGroupId != listeningUserInfo.profileGroupId 648 || !userInfo.isEnabled()) { 649 if (DEBUG) { 650 Log.d(TAG, "Not delivering msg from " + user + " to " + listeningUser + ":" 651 + debugMsg); 652 } 653 return false; 654 } else { 655 if (DEBUG) { 656 Log.d(TAG, "Delivering msg from " + user + " to " + listeningUser + ":" 657 + debugMsg); 658 } 659 return true; 660 } 661 } finally { 662 injectRestoreCallingIdentity(ident); 663 } 664 } 665 666 @VisibleForTesting 667 void postToPackageMonitorHandler(Runnable r) { 668 mCallbackHandler.post(r); 669 } 670 671 private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener { 672 673 // TODO Simplify with lambdas. 674 675 @Override 676 public void onPackageAdded(String packageName, int uid) { 677 UserHandle user = new UserHandle(getChangingUserId()); 678 final int n = mListeners.beginBroadcast(); 679 try { 680 for (int i = 0; i < n; i++) { 681 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 682 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 683 if (!isEnabledProfileOf(user, cookie.user, "onPackageAdded")) continue; 684 try { 685 listener.onPackageAdded(user, packageName); 686 } catch (RemoteException re) { 687 Slog.d(TAG, "Callback failed ", re); 688 } 689 } 690 } finally { 691 mListeners.finishBroadcast(); 692 } 693 694 super.onPackageAdded(packageName, uid); 695 } 696 697 @Override 698 public void onPackageRemoved(String packageName, int uid) { 699 UserHandle user = new UserHandle(getChangingUserId()); 700 final int n = mListeners.beginBroadcast(); 701 try { 702 for (int i = 0; i < n; i++) { 703 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 704 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 705 if (!isEnabledProfileOf(user, cookie.user, "onPackageRemoved")) continue; 706 try { 707 listener.onPackageRemoved(user, packageName); 708 } catch (RemoteException re) { 709 Slog.d(TAG, "Callback failed ", re); 710 } 711 } 712 } finally { 713 mListeners.finishBroadcast(); 714 } 715 716 super.onPackageRemoved(packageName, uid); 717 } 718 719 @Override 720 public void onPackageModified(String packageName) { 721 UserHandle user = new UserHandle(getChangingUserId()); 722 final int n = mListeners.beginBroadcast(); 723 try { 724 for (int i = 0; i < n; i++) { 725 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 726 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 727 if (!isEnabledProfileOf(user, cookie.user, "onPackageModified")) continue; 728 try { 729 listener.onPackageChanged(user, packageName); 730 } catch (RemoteException re) { 731 Slog.d(TAG, "Callback failed ", re); 732 } 733 } 734 } finally { 735 mListeners.finishBroadcast(); 736 } 737 738 super.onPackageModified(packageName); 739 } 740 741 @Override 742 public void onPackagesAvailable(String[] packages) { 743 UserHandle user = new UserHandle(getChangingUserId()); 744 final int n = mListeners.beginBroadcast(); 745 try { 746 for (int i = 0; i < n; i++) { 747 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 748 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 749 if (!isEnabledProfileOf(user, cookie.user, "onPackagesAvailable")) continue; 750 try { 751 listener.onPackagesAvailable(user, packages, isReplacing()); 752 } catch (RemoteException re) { 753 Slog.d(TAG, "Callback failed ", re); 754 } 755 } 756 } finally { 757 mListeners.finishBroadcast(); 758 } 759 760 super.onPackagesAvailable(packages); 761 } 762 763 @Override 764 public void onPackagesUnavailable(String[] packages) { 765 UserHandle user = new UserHandle(getChangingUserId()); 766 final int n = mListeners.beginBroadcast(); 767 try { 768 for (int i = 0; i < n; i++) { 769 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 770 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 771 if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnavailable")) continue; 772 try { 773 listener.onPackagesUnavailable(user, packages, isReplacing()); 774 } catch (RemoteException re) { 775 Slog.d(TAG, "Callback failed ", re); 776 } 777 } 778 } finally { 779 mListeners.finishBroadcast(); 780 } 781 782 super.onPackagesUnavailable(packages); 783 } 784 785 @Override 786 public void onPackagesSuspended(String[] packages) { 787 UserHandle user = new UserHandle(getChangingUserId()); 788 final int n = mListeners.beginBroadcast(); 789 try { 790 for (int i = 0; i < n; i++) { 791 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 792 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 793 if (!isEnabledProfileOf(user, cookie.user, "onPackagesSuspended")) continue; 794 try { 795 listener.onPackagesSuspended(user, packages); 796 } catch (RemoteException re) { 797 Slog.d(TAG, "Callback failed ", re); 798 } 799 } 800 } finally { 801 mListeners.finishBroadcast(); 802 } 803 804 super.onPackagesSuspended(packages); 805 } 806 807 @Override 808 public void onPackagesUnsuspended(String[] packages) { 809 UserHandle user = new UserHandle(getChangingUserId()); 810 final int n = mListeners.beginBroadcast(); 811 try { 812 for (int i = 0; i < n; i++) { 813 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 814 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 815 if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnsuspended")) continue; 816 try { 817 listener.onPackagesUnsuspended(user, packages); 818 } catch (RemoteException re) { 819 Slog.d(TAG, "Callback failed ", re); 820 } 821 } 822 } finally { 823 mListeners.finishBroadcast(); 824 } 825 826 super.onPackagesUnsuspended(packages); 827 } 828 829 @Override 830 public void onShortcutChanged(@NonNull String packageName, 831 @UserIdInt int userId) { 832 postToPackageMonitorHandler(() -> onShortcutChangedInner(packageName, userId)); 833 } 834 835 private void onShortcutChangedInner(@NonNull String packageName, 836 @UserIdInt int userId) { 837 final int n = mListeners.beginBroadcast(); 838 try { 839 final UserHandle user = UserHandle.of(userId); 840 841 for (int i = 0; i < n; i++) { 842 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 843 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 844 if (!isEnabledProfileOf(user, cookie.user, "onShortcutChanged")) continue; 845 846 final int launcherUserId = cookie.user.getIdentifier(); 847 848 // Make sure the caller has the permission. 849 if (!mShortcutServiceInternal.hasShortcutHostPermission( 850 launcherUserId, cookie.packageName)) { 851 continue; 852 } 853 // Each launcher has a different set of pinned shortcuts, so we need to do a 854 // query in here. 855 // (As of now, only one launcher has the permission at a time, so it's bit 856 // moot, but we may change the permission model eventually.) 857 final List<ShortcutInfo> list = 858 mShortcutServiceInternal.getShortcuts(launcherUserId, 859 cookie.packageName, 860 /* changedSince= */ 0, packageName, /* shortcutIds=*/ null, 861 /* component= */ null, 862 ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY 863 | ShortcutQuery.FLAG_GET_ALL_KINDS 864 , userId); 865 try { 866 listener.onShortcutChanged(user, packageName, 867 new ParceledListSlice<>(list)); 868 } catch (RemoteException re) { 869 Slog.d(TAG, "Callback failed ", re); 870 } 871 } 872 } catch (RuntimeException e) { 873 // When the user is locked we get IllegalState, so just catch all. 874 Log.w(TAG, e.getMessage(), e); 875 } finally { 876 mListeners.finishBroadcast(); 877 } 878 } 879 } 880 881 class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> { 882 @Override 883 public void onCallbackDied(T callback, Object cookie) { 884 checkCallbackCount(); 885 } 886 } 887 } 888} 889