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