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