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 17 package com.android.server.pm; 18 19 import static android.Manifest.permission.READ_FRAME_BUFFER; 20 import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME; 21 import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; 22 import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; 23 import static android.app.PendingIntent.FLAG_IMMUTABLE; 24 import static android.app.PendingIntent.FLAG_MUTABLE; 25 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; 26 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; 27 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; 28 import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; 29 import static android.content.PermissionChecker.PERMISSION_GRANTED; 30 import static android.content.PermissionChecker.checkCallingOrSelfPermissionForPreflight; 31 import static android.content.pm.LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS; 32 import static android.content.pm.LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS; 33 import static android.content.pm.LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS; 34 35 import android.annotation.AppIdInt; 36 import android.annotation.NonNull; 37 import android.annotation.Nullable; 38 import android.annotation.RequiresPermission; 39 import android.annotation.UserIdInt; 40 import android.app.ActivityManager; 41 import android.app.ActivityManagerInternal; 42 import android.app.ActivityOptions; 43 import android.app.AppGlobals; 44 import android.app.IApplicationThread; 45 import android.app.PendingIntent; 46 import android.app.admin.DevicePolicyCache; 47 import android.app.admin.DevicePolicyManager; 48 import android.app.usage.UsageStatsManagerInternal; 49 import android.content.ActivityNotFoundException; 50 import android.content.BroadcastReceiver; 51 import android.content.ComponentName; 52 import android.content.Context; 53 import android.content.Intent; 54 import android.content.IntentFilter; 55 import android.content.IntentSender; 56 import android.content.LocusId; 57 import android.content.pm.ActivityInfo; 58 import android.content.pm.ApplicationInfo; 59 import android.content.pm.ILauncherApps; 60 import android.content.pm.IOnAppsChangedListener; 61 import android.content.pm.IPackageInstallerCallback; 62 import android.content.pm.IPackageManager; 63 import android.content.pm.IShortcutChangeCallback; 64 import android.content.pm.IncrementalStatesInfo; 65 import android.content.pm.LauncherActivityInfoInternal; 66 import android.content.pm.LauncherApps; 67 import android.content.pm.LauncherApps.ShortcutQuery; 68 import android.content.pm.PackageInfo; 69 import android.content.pm.PackageInstaller.SessionInfo; 70 import android.content.pm.PackageManager; 71 import android.content.pm.PackageManagerInternal; 72 import android.content.pm.ParceledListSlice; 73 import android.content.pm.ResolveInfo; 74 import android.content.pm.ShortcutInfo; 75 import android.content.pm.ShortcutQueryWrapper; 76 import android.content.pm.ShortcutServiceInternal; 77 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; 78 import android.content.pm.UserInfo; 79 import android.graphics.Rect; 80 import android.net.Uri; 81 import android.os.Binder; 82 import android.os.Bundle; 83 import android.os.Handler; 84 import android.os.IInterface; 85 import android.os.ParcelFileDescriptor; 86 import android.os.Process; 87 import android.os.RemoteCallbackList; 88 import android.os.RemoteException; 89 import android.os.ResultReceiver; 90 import android.os.ServiceManager; 91 import android.os.ShellCallback; 92 import android.os.ShellCommand; 93 import android.os.UserHandle; 94 import android.os.UserManager; 95 import android.provider.Settings; 96 import android.util.ArrayMap; 97 import android.util.Log; 98 import android.util.Pair; 99 import android.util.Slog; 100 import android.window.IDumpCallback; 101 102 import com.android.internal.annotations.GuardedBy; 103 import com.android.internal.annotations.VisibleForTesting; 104 import com.android.internal.content.PackageMonitor; 105 import com.android.internal.infra.AndroidFuture; 106 import com.android.internal.os.BackgroundThread; 107 import com.android.internal.util.ArrayUtils; 108 import com.android.internal.util.CollectionUtils; 109 import com.android.internal.util.Preconditions; 110 import com.android.server.LocalServices; 111 import com.android.server.SystemService; 112 import com.android.server.pm.pkg.AndroidPackage; 113 import com.android.server.wm.ActivityTaskManagerInternal; 114 115 import java.io.FileDescriptor; 116 import java.io.IOException; 117 import java.io.InputStream; 118 import java.io.PrintWriter; 119 import java.nio.file.Files; 120 import java.nio.file.Path; 121 import java.nio.file.Paths; 122 import java.nio.file.StandardCopyOption; 123 import java.nio.file.attribute.PosixFilePermission; 124 import java.util.ArrayList; 125 import java.util.Arrays; 126 import java.util.Collections; 127 import java.util.HashSet; 128 import java.util.List; 129 import java.util.Map; 130 import java.util.Objects; 131 import java.util.Set; 132 import java.util.concurrent.ExecutionException; 133 import java.util.function.BiConsumer; 134 import java.util.zip.ZipEntry; 135 import java.util.zip.ZipOutputStream; 136 137 /** 138 * Service that manages requests and callbacks for launchers that support 139 * managed profiles. 140 */ 141 public class LauncherAppsService extends SystemService { 142 private static final String WM_TRACE_DIR = "/data/misc/wmtrace/"; 143 private static final String VC_FILE_SUFFIX = ".vc"; 144 145 private static final Set<PosixFilePermission> WM_TRACE_FILE_PERMISSIONS = Set.of( 146 PosixFilePermission.OWNER_WRITE, 147 PosixFilePermission.GROUP_READ, 148 PosixFilePermission.OTHERS_READ, 149 PosixFilePermission.OWNER_READ 150 ); 151 152 private final LauncherAppsImpl mLauncherAppsImpl; 153 LauncherAppsService(Context context)154 public LauncherAppsService(Context context) { 155 super(context); 156 mLauncherAppsImpl = new LauncherAppsImpl(context); 157 } 158 159 @Override onStart()160 public void onStart() { 161 publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl); 162 mLauncherAppsImpl.registerLoadingProgressForIncrementalApps(); 163 LocalServices.addService(LauncherAppsServiceInternal.class, mLauncherAppsImpl.mInternal); 164 } 165 166 static class BroadcastCookie { 167 public final UserHandle user; 168 public final String packageName; 169 public final int callingUid; 170 public final int callingPid; 171 BroadcastCookie(UserHandle userHandle, String packageName, int callingPid, int callingUid)172 BroadcastCookie(UserHandle userHandle, String packageName, int callingPid, int callingUid) { 173 this.user = userHandle; 174 this.packageName = packageName; 175 this.callingUid = callingUid; 176 this.callingPid = callingPid; 177 } 178 } 179 180 /** 181 * Local system service interface. 182 * @hide Only for use within system server 183 */ 184 public abstract static class LauncherAppsServiceInternal { 185 /** Same as startShortcut except supports forwarding of caller uid/pid. */ startShortcut(int callerUid, int callerPid, String callingPackage, String packageName, String featureId, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int targetUserId)186 public abstract boolean startShortcut(int callerUid, int callerPid, String callingPackage, 187 String packageName, String featureId, String shortcutId, Rect sourceBounds, 188 Bundle startActivityOptions, int targetUserId); 189 } 190 191 @VisibleForTesting 192 static class LauncherAppsImpl extends ILauncherApps.Stub { 193 private static final boolean DEBUG = false; 194 private static final String TAG = "LauncherAppsService"; 195 196 private final Context mContext; 197 private final UserManager mUm; 198 private final IPackageManager mIPM; 199 private final UserManagerInternal mUserManagerInternal; 200 private final UsageStatsManagerInternal mUsageStatsManagerInternal; 201 private final ActivityManagerInternal mActivityManagerInternal; 202 private final ActivityTaskManagerInternal mActivityTaskManagerInternal; 203 private final ShortcutServiceInternal mShortcutServiceInternal; 204 private final PackageManagerInternal mPackageManagerInternal; 205 private final PackageCallbackList<IOnAppsChangedListener> mListeners 206 = new PackageCallbackList<IOnAppsChangedListener>(); 207 private final DevicePolicyManager mDpm; 208 209 private final PackageRemovedListener mPackageRemovedListener = 210 new PackageRemovedListener(); 211 private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); 212 213 @GuardedBy("mListeners") 214 private boolean mIsWatchingPackageBroadcasts = false; 215 216 private final ShortcutChangeHandler mShortcutChangeHandler; 217 218 private final Handler mCallbackHandler; 219 220 private PackageInstallerService mPackageInstallerService; 221 222 final LauncherAppsServiceInternal mInternal; 223 224 @NonNull 225 private final RemoteCallbackList<IDumpCallback> mDumpCallbacks = new RemoteCallbackList<>(); 226 LauncherAppsImpl(Context context)227 public LauncherAppsImpl(Context context) { 228 mContext = context; 229 mIPM = AppGlobals.getPackageManager(); 230 mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 231 mUserManagerInternal = Objects.requireNonNull( 232 LocalServices.getService(UserManagerInternal.class)); 233 mUsageStatsManagerInternal = Objects.requireNonNull( 234 LocalServices.getService(UsageStatsManagerInternal.class)); 235 mActivityManagerInternal = Objects.requireNonNull( 236 LocalServices.getService(ActivityManagerInternal.class)); 237 mActivityTaskManagerInternal = Objects.requireNonNull( 238 LocalServices.getService(ActivityTaskManagerInternal.class)); 239 mShortcutServiceInternal = Objects.requireNonNull( 240 LocalServices.getService(ShortcutServiceInternal.class)); 241 mPackageManagerInternal = Objects.requireNonNull( 242 LocalServices.getService(PackageManagerInternal.class)); 243 mShortcutServiceInternal.addListener(mPackageMonitor); 244 mShortcutChangeHandler = new ShortcutChangeHandler(mUserManagerInternal); 245 mShortcutServiceInternal.addShortcutChangeCallback(mShortcutChangeHandler); 246 mCallbackHandler = BackgroundThread.getHandler(); 247 mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 248 mInternal = new LocalService(); 249 } 250 251 @VisibleForTesting injectBinderCallingUid()252 int injectBinderCallingUid() { 253 return getCallingUid(); 254 } 255 256 @VisibleForTesting injectBinderCallingPid()257 int injectBinderCallingPid() { 258 return getCallingPid(); 259 } 260 injectCallingUserId()261 final int injectCallingUserId() { 262 return UserHandle.getUserId(injectBinderCallingUid()); 263 } 264 265 @VisibleForTesting injectClearCallingIdentity()266 long injectClearCallingIdentity() { 267 return Binder.clearCallingIdentity(); 268 } 269 270 // Injection point. 271 @VisibleForTesting injectRestoreCallingIdentity(long token)272 void injectRestoreCallingIdentity(long token) { 273 Binder.restoreCallingIdentity(token); 274 } 275 getCallingUserId()276 private int getCallingUserId() { 277 return UserHandle.getUserId(injectBinderCallingUid()); 278 } 279 280 /* 281 * @see android.content.pm.ILauncherApps#addOnAppsChangedListener 282 */ 283 @Override addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener)284 public void addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener) 285 throws RemoteException { 286 verifyCallingPackage(callingPackage); 287 synchronized (mListeners) { 288 if (DEBUG) { 289 Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle()); 290 } 291 if (mListeners.getRegisteredCallbackCount() == 0) { 292 if (DEBUG) { 293 Log.d(TAG, "Starting package monitoring"); 294 } 295 startWatchingPackageBroadcasts(); 296 } 297 mListeners.unregister(listener); 298 mListeners.register(listener, new BroadcastCookie(UserHandle.of(getCallingUserId()), 299 callingPackage, injectBinderCallingPid(), injectBinderCallingUid())); 300 } 301 } 302 303 /* 304 * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener 305 */ 306 @Override removeOnAppsChangedListener(IOnAppsChangedListener listener)307 public void removeOnAppsChangedListener(IOnAppsChangedListener listener) 308 throws RemoteException { 309 synchronized (mListeners) { 310 if (DEBUG) { 311 Log.d(TAG, "Removing listener from " + Binder.getCallingUserHandle()); 312 } 313 mListeners.unregister(listener); 314 if (mListeners.getRegisteredCallbackCount() == 0) { 315 stopWatchingPackageBroadcasts(); 316 } 317 } 318 } 319 320 /** 321 * @see android.content.pm.ILauncherApps#registerPackageInstallerCallback 322 */ 323 @Override registerPackageInstallerCallback(String callingPackage, IPackageInstallerCallback callback)324 public void registerPackageInstallerCallback(String callingPackage, 325 IPackageInstallerCallback callback) { 326 verifyCallingPackage(callingPackage); 327 UserHandle callingIdUserHandle = new UserHandle(getCallingUserId()); 328 getPackageInstallerService().registerCallback(callback, eventUserId -> 329 isEnabledProfileOf(callingIdUserHandle, 330 new UserHandle(eventUserId), "shouldReceiveEvent")); 331 } 332 333 @Override getAllSessions(String callingPackage)334 public ParceledListSlice<SessionInfo> getAllSessions(String callingPackage) { 335 verifyCallingPackage(callingPackage); 336 List<SessionInfo> sessionInfos = new ArrayList<>(); 337 int[] userIds = mUm.getEnabledProfileIds(getCallingUserId()); 338 final int callingUid = Binder.getCallingUid(); 339 final long token = Binder.clearCallingIdentity(); 340 try { 341 for (int userId : userIds) { 342 sessionInfos.addAll(getPackageInstallerService().getAllSessions(userId) 343 .getList()); 344 } 345 } finally { 346 Binder.restoreCallingIdentity(token); 347 } 348 sessionInfos.removeIf(info -> shouldFilterSession(callingUid, info)); 349 return new ParceledListSlice<>(sessionInfos); 350 } 351 shouldFilterSession(int uid, SessionInfo session)352 private boolean shouldFilterSession(int uid, SessionInfo session) { 353 if (session == null) { 354 return false; 355 } 356 return uid != session.getInstallerUid() 357 && !mPackageManagerInternal.canQueryPackage(uid, session.getAppPackageName()); 358 } 359 getPackageInstallerService()360 private PackageInstallerService getPackageInstallerService() { 361 if (mPackageInstallerService == null) { 362 try { 363 mPackageInstallerService = ((PackageInstallerService) ((IPackageManager) 364 ServiceManager.getService("package")).getPackageInstaller()); 365 } catch (RemoteException e) { 366 Slog.wtf(TAG, "Error gettig IPackageInstaller", e); 367 } 368 } 369 return mPackageInstallerService; 370 } 371 372 /** 373 * Register a receiver to watch for package broadcasts 374 */ startWatchingPackageBroadcasts()375 private void startWatchingPackageBroadcasts() { 376 if (!mIsWatchingPackageBroadcasts) { 377 final IntentFilter filter = new IntentFilter(); 378 filter.addAction(Intent.ACTION_PACKAGE_REMOVED_INTERNAL); 379 filter.addDataScheme("package"); 380 mContext.registerReceiverAsUser(mPackageRemovedListener, UserHandle.ALL, filter, 381 /* broadcastPermission= */ null, mCallbackHandler); 382 mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler); 383 mIsWatchingPackageBroadcasts = true; 384 } 385 } 386 387 /** 388 * Unregister package broadcast receiver 389 */ stopWatchingPackageBroadcasts()390 private void stopWatchingPackageBroadcasts() { 391 if (DEBUG) { 392 Log.d(TAG, "Stopped watching for packages"); 393 } 394 if (mIsWatchingPackageBroadcasts) { 395 mContext.unregisterReceiver(mPackageRemovedListener); 396 mPackageMonitor.unregister(); 397 mIsWatchingPackageBroadcasts = false; 398 } 399 } 400 checkCallbackCount()401 void checkCallbackCount() { 402 synchronized (mListeners) { 403 if (DEBUG) { 404 Log.d(TAG, "Callback count = " + mListeners.getRegisteredCallbackCount()); 405 } 406 if (mListeners.getRegisteredCallbackCount() == 0) { 407 stopWatchingPackageBroadcasts(); 408 } 409 } 410 } 411 412 /** 413 * Checks if the calling user is in the same group as {@code targetUser}, and allowed 414 * to access it. 415 * 416 * @return TRUE if the calling user can access {@code targetUserId}. FALSE if not *but 417 * they're still in the same profile group*. 418 * 419 * @throws SecurityException if the calling user and {@code targetUser} are not in the same 420 * group. 421 */ canAccessProfile(int targetUserId, String message)422 private boolean canAccessProfile(int targetUserId, String message) { 423 return canAccessProfile(injectBinderCallingUid(), injectCallingUserId(), 424 injectBinderCallingPid(), targetUserId, message); 425 } 426 canAccessProfile(int callingUid, int callingUserId, int callingPid, int targetUserId, String message)427 private boolean canAccessProfile(int callingUid, int callingUserId, int callingPid, 428 int targetUserId, String message) { 429 430 if (targetUserId == callingUserId) return true; 431 if (injectHasInteractAcrossUsersFullPermission(callingPid, callingUid)) { 432 return true; 433 } 434 435 long ident = injectClearCallingIdentity(); 436 try { 437 final UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); 438 if (callingUserInfo != null && callingUserInfo.isProfile()) { 439 Slog.w(TAG, message + " for another profile " 440 + targetUserId + " from " + callingUserId + " not allowed"); 441 return false; 442 } 443 } finally { 444 injectRestoreCallingIdentity(ident); 445 } 446 447 return mUserManagerInternal.isProfileAccessible(callingUserId, targetUserId, 448 message, true); 449 } 450 verifyCallingPackage(String callingPackage)451 private void verifyCallingPackage(String callingPackage) { 452 verifyCallingPackage(callingPackage, injectBinderCallingUid()); 453 } 454 455 @VisibleForTesting // We override it in unit tests verifyCallingPackage(String callingPackage, int callerUid)456 void verifyCallingPackage(String callingPackage, int callerUid) { 457 int packageUid = -1; 458 try { 459 packageUid = mIPM.getPackageUid(callingPackage, 460 PackageManager.MATCH_DIRECT_BOOT_AWARE 461 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 462 | PackageManager.MATCH_UNINSTALLED_PACKAGES, 463 UserHandle.getUserId(callerUid)); 464 } catch (RemoteException ignore) { 465 } 466 if (packageUid < 0) { 467 Log.e(TAG, "Package not found: " + callingPackage); 468 } 469 if (packageUid != callerUid) { 470 throw new SecurityException("Calling package name mismatch"); 471 } 472 } 473 getHiddenAppActivityInfo(String packageName, int callingUid, UserHandle user)474 private LauncherActivityInfoInternal getHiddenAppActivityInfo(String packageName, 475 int callingUid, UserHandle user) { 476 Intent intent = new Intent(); 477 intent.setComponent(new ComponentName(packageName, 478 PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)); 479 final List<LauncherActivityInfoInternal> apps = queryIntentLauncherActivities(intent, 480 callingUid, user); 481 if (apps.size() > 0) { 482 return apps.get(0); 483 } 484 return null; 485 } 486 487 @Override shouldHideFromSuggestions(String packageName, UserHandle user)488 public boolean shouldHideFromSuggestions(String packageName, UserHandle user) { 489 final int userId = user.getIdentifier(); 490 if (!canAccessProfile(userId, "cannot get shouldHideFromSuggestions")) { 491 return false; 492 } 493 if (mPackageManagerInternal.filterAppAccess( 494 packageName, Binder.getCallingUid(), userId)) { 495 return false; 496 } 497 final int flags = mPackageManagerInternal.getDistractingPackageRestrictions( 498 packageName, userId); 499 return (flags & PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS) != 0; 500 } 501 502 @Override getLauncherActivities( String callingPackage, String packageName, UserHandle user)503 public ParceledListSlice<LauncherActivityInfoInternal> getLauncherActivities( 504 String callingPackage, String packageName, UserHandle user) throws RemoteException { 505 ParceledListSlice<LauncherActivityInfoInternal> launcherActivities = 506 queryActivitiesForUser(callingPackage, 507 new Intent(Intent.ACTION_MAIN) 508 .addCategory(Intent.CATEGORY_LAUNCHER) 509 .setPackage(packageName), 510 user); 511 if (Settings.Global.getInt(mContext.getContentResolver(), 512 Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 1) == 0) { 513 return launcherActivities; 514 } 515 if (launcherActivities == null) { 516 // Cannot access profile, so we don't even return any hidden apps. 517 return null; 518 } 519 520 final int callingUid = injectBinderCallingUid(); 521 final long ident = injectClearCallingIdentity(); 522 try { 523 if (mUm.getUserInfo(user.getIdentifier()).isManagedProfile()) { 524 // Managed profile should not show hidden apps 525 return launcherActivities; 526 } 527 if (mDpm.getDeviceOwnerComponentOnAnyUser() != null) { 528 // Device owner devices should not show hidden apps 529 return launcherActivities; 530 } 531 532 final ArrayList<LauncherActivityInfoInternal> result = new ArrayList<>( 533 launcherActivities.getList()); 534 if (packageName != null) { 535 // If this hidden app should not be shown, return the original list. 536 // Otherwise, inject hidden activity that forwards user to app details page. 537 if (result.size() > 0) { 538 return launcherActivities; 539 } 540 final ApplicationInfo appInfo = mPackageManagerInternal.getApplicationInfo( 541 packageName, /* flags= */ 0, callingUid, user.getIdentifier()); 542 if (shouldShowSyntheticActivity(user, appInfo)) { 543 LauncherActivityInfoInternal info = getHiddenAppActivityInfo(packageName, 544 callingUid, user); 545 if (info != null) { 546 result.add(info); 547 } 548 } 549 return new ParceledListSlice<>(result); 550 } 551 final HashSet<String> visiblePackages = new HashSet<>(); 552 for (LauncherActivityInfoInternal info : result) { 553 visiblePackages.add(info.getActivityInfo().packageName); 554 } 555 final List<ApplicationInfo> installedPackages = 556 mPackageManagerInternal.getInstalledApplications(/* flags= */ 0, 557 user.getIdentifier(), callingUid); 558 for (ApplicationInfo applicationInfo : installedPackages) { 559 if (!visiblePackages.contains(applicationInfo.packageName)) { 560 if (!shouldShowSyntheticActivity(user, applicationInfo)) { 561 continue; 562 } 563 LauncherActivityInfoInternal info = getHiddenAppActivityInfo( 564 applicationInfo.packageName, callingUid, user); 565 if (info != null) { 566 result.add(info); 567 } 568 } 569 } 570 return new ParceledListSlice<>(result); 571 } finally { 572 injectRestoreCallingIdentity(ident); 573 } 574 } 575 shouldShowSyntheticActivity(UserHandle user, ApplicationInfo appInfo)576 private boolean shouldShowSyntheticActivity(UserHandle user, ApplicationInfo appInfo) { 577 if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) { 578 return false; 579 } 580 if (isManagedProfileAdmin(user, appInfo.packageName)) { 581 return false; 582 } 583 final AndroidPackage pkg = mPackageManagerInternal.getPackage(appInfo.packageName); 584 if (pkg == null) { 585 // Should not happen, but we shouldn't be failing if it does 586 return false; 587 } 588 // If app does not have any default enabled launcher activity or any permissions, 589 // the app can legitimately have no icon so we do not show the synthetic activity. 590 return requestsPermissions(pkg) && hasDefaultEnableLauncherActivity( 591 appInfo.packageName); 592 } 593 requestsPermissions(@onNull AndroidPackage pkg)594 private boolean requestsPermissions(@NonNull AndroidPackage pkg) { 595 return !ArrayUtils.isEmpty(pkg.getRequestedPermissions()); 596 } 597 hasDefaultEnableLauncherActivity(@onNull String packageName)598 private boolean hasDefaultEnableLauncherActivity(@NonNull String packageName) { 599 final Intent matchIntent = new Intent(Intent.ACTION_MAIN); 600 matchIntent.addCategory(Intent.CATEGORY_LAUNCHER); 601 matchIntent.setPackage(packageName); 602 final List<ResolveInfo> infoList = mPackageManagerInternal.queryIntentActivities( 603 matchIntent, matchIntent.resolveTypeIfNeeded(mContext.getContentResolver()), 604 PackageManager.MATCH_DISABLED_COMPONENTS, Binder.getCallingUid(), 605 getCallingUserId()); 606 final int size = infoList.size(); 607 for (int i = 0; i < size; i++) { 608 if (infoList.get(i).activityInfo.enabled) { 609 return true; 610 } 611 } 612 return false; 613 } 614 isManagedProfileAdmin(UserHandle user, String packageName)615 private boolean isManagedProfileAdmin(UserHandle user, String packageName) { 616 final List<UserInfo> userInfoList = mUm.getProfiles(user.getIdentifier()); 617 for (int i = 0; i < userInfoList.size(); i++) { 618 UserInfo userInfo = userInfoList.get(i); 619 if (!userInfo.isManagedProfile()) { 620 continue; 621 } 622 ComponentName componentName = mDpm.getProfileOwnerAsUser(userInfo.getUserHandle()); 623 if (componentName == null) { 624 continue; 625 } 626 if (componentName.getPackageName().equals(packageName)) { 627 return true; 628 } 629 } 630 return false; 631 } 632 633 @Override resolveLauncherActivityInternal( String callingPackage, ComponentName component, UserHandle user)634 public LauncherActivityInfoInternal resolveLauncherActivityInternal( 635 String callingPackage, ComponentName component, UserHandle user) 636 throws RemoteException { 637 if (!canAccessProfile(user.getIdentifier(), "Cannot resolve activity")) { 638 return null; 639 } 640 641 final int callingUid = injectBinderCallingUid(); 642 final long ident = Binder.clearCallingIdentity(); 643 try { 644 final ActivityInfo activityInfo = mPackageManagerInternal.getActivityInfo(component, 645 PackageManager.MATCH_DIRECT_BOOT_AWARE 646 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 647 callingUid, user.getIdentifier()); 648 if (activityInfo == null) { 649 return null; 650 } 651 if (component == null || component.getPackageName() == null) { 652 // should not happen 653 return null; 654 } 655 final IncrementalStatesInfo incrementalStatesInfo = 656 mPackageManagerInternal.getIncrementalStatesInfo(component.getPackageName(), 657 callingUid, user.getIdentifier()); 658 if (incrementalStatesInfo == null) { 659 // package does not exist; should not happen 660 return null; 661 } 662 return new LauncherActivityInfoInternal(activityInfo, incrementalStatesInfo, user); 663 } finally { 664 Binder.restoreCallingIdentity(ident); 665 } 666 } 667 668 @Override getShortcutConfigActivities( String callingPackage, String packageName, UserHandle user)669 public ParceledListSlice getShortcutConfigActivities( 670 String callingPackage, String packageName, UserHandle user) 671 throws RemoteException { 672 return queryActivitiesForUser(callingPackage, 673 new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user); 674 } 675 queryActivitiesForUser( String callingPackage, Intent intent, UserHandle user)676 private ParceledListSlice<LauncherActivityInfoInternal> queryActivitiesForUser( 677 String callingPackage, Intent intent, UserHandle user) { 678 if (!canAccessProfile(user.getIdentifier(), "Cannot retrieve activities")) { 679 return null; 680 } 681 final int callingUid = injectBinderCallingUid(); 682 long ident = injectClearCallingIdentity(); 683 try { 684 return new ParceledListSlice<>(queryIntentLauncherActivities(intent, callingUid, 685 user)); 686 } finally { 687 injectRestoreCallingIdentity(ident); 688 } 689 } 690 queryIntentLauncherActivities( Intent intent, int callingUid, UserHandle user)691 private List<LauncherActivityInfoInternal> queryIntentLauncherActivities( 692 Intent intent, int callingUid, UserHandle user) { 693 final List<ResolveInfo> apps = mPackageManagerInternal.queryIntentActivities(intent, 694 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 695 PackageManager.MATCH_DIRECT_BOOT_AWARE 696 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 697 callingUid, user.getIdentifier()); 698 final int numResolveInfos = apps.size(); 699 List<LauncherActivityInfoInternal> results = new ArrayList<>(); 700 for (int i = 0; i < numResolveInfos; i++) { 701 final ResolveInfo ri = apps.get(i); 702 final String packageName = ri.activityInfo.packageName; 703 if (packageName == null) { 704 // should not happen 705 continue; 706 } 707 final IncrementalStatesInfo incrementalStatesInfo = 708 mPackageManagerInternal.getIncrementalStatesInfo(packageName, callingUid, 709 user.getIdentifier()); 710 if (incrementalStatesInfo == null) { 711 // package doesn't exist any more; should not happen 712 continue; 713 } 714 results.add(new LauncherActivityInfoInternal(ri.activityInfo, 715 incrementalStatesInfo, user)); 716 } 717 return results; 718 } 719 720 @Override getShortcutConfigActivityIntent(String callingPackage, ComponentName component, UserHandle user)721 public IntentSender getShortcutConfigActivityIntent(String callingPackage, 722 ComponentName component, UserHandle user) throws RemoteException { 723 ensureShortcutPermission(callingPackage); 724 if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { 725 return null; 726 } 727 Objects.requireNonNull(component); 728 729 // All right, create the sender. 730 final int callingUid = injectBinderCallingUid(); 731 final long identity = Binder.clearCallingIdentity(); 732 try { 733 Intent packageIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT) 734 .setPackage(component.getPackageName()); 735 List<ResolveInfo> apps = 736 mPackageManagerInternal.queryIntentActivities(packageIntent, 737 packageIntent.resolveTypeIfNeeded(mContext.getContentResolver()), 738 PackageManager.MATCH_DIRECT_BOOT_AWARE 739 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 740 callingUid, user.getIdentifier()); 741 // ensure that the component is present in the list 742 if (!apps.stream().anyMatch( 743 ri -> component.getClassName().equals(ri.activityInfo.name))) { 744 return null; 745 } 746 747 Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component); 748 final PendingIntent pi = PendingIntent.getActivityAsUser( 749 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT 750 | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT, 751 null, user); 752 return pi == null ? null : pi.getIntentSender(); 753 } finally { 754 Binder.restoreCallingIdentity(identity); 755 } 756 } 757 758 /** 759 * Returns the intents for a specific shortcut. 760 */ 761 @Nullable 762 @Override getShortcutIntent(@onNull final String callingPackage, @NonNull final String packageName, @NonNull final String shortcutId, @Nullable final Bundle opts, @NonNull final UserHandle user)763 public PendingIntent getShortcutIntent(@NonNull final String callingPackage, 764 @NonNull final String packageName, @NonNull final String shortcutId, 765 @Nullable final Bundle opts, @NonNull final UserHandle user) 766 throws RemoteException { 767 Objects.requireNonNull(callingPackage); 768 Objects.requireNonNull(packageName); 769 Objects.requireNonNull(shortcutId); 770 Objects.requireNonNull(user); 771 772 ensureShortcutPermission(callingPackage); 773 if (!canAccessProfile(user.getIdentifier(), "Cannot get shortcuts")) { 774 return null; 775 } 776 777 final AndroidFuture<Intent[]> ret = new AndroidFuture<>(); 778 Intent[] intents; 779 mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(), 780 callingPackage, packageName, shortcutId, user.getIdentifier(), 781 injectBinderCallingPid(), injectBinderCallingUid(), ret); 782 try { 783 intents = ret.get(); 784 } catch (InterruptedException | ExecutionException e) { 785 return null; 786 } 787 if (intents == null || intents.length == 0) { 788 return null; 789 } 790 final long ident = Binder.clearCallingIdentity(); 791 try { 792 return injectCreatePendingIntent(0 /* requestCode */, intents, 793 FLAG_IMMUTABLE | FLAG_UPDATE_CURRENT, opts, packageName, 794 mPackageManagerInternal.getPackageUid( 795 packageName, PackageManager.MATCH_DIRECT_BOOT_AUTO, 796 user.getIdentifier())); 797 } finally { 798 Binder.restoreCallingIdentity(ident); 799 } 800 } 801 802 @Override isPackageEnabled(String callingPackage, String packageName, UserHandle user)803 public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user) 804 throws RemoteException { 805 if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { 806 return false; 807 } 808 809 final int callingUid = injectBinderCallingUid(); 810 final long ident = Binder.clearCallingIdentity(); 811 try { 812 final PackageInfo info = mPackageManagerInternal.getPackageInfo(packageName, 813 PackageManager.MATCH_DIRECT_BOOT_AWARE 814 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 815 callingUid, user.getIdentifier()); 816 return info != null && info.applicationInfo.enabled; 817 } finally { 818 Binder.restoreCallingIdentity(ident); 819 } 820 } 821 822 @Override getSuspendedPackageLauncherExtras(String packageName, UserHandle user)823 public Bundle getSuspendedPackageLauncherExtras(String packageName, 824 UserHandle user) { 825 final int callingUid = injectBinderCallingUid(); 826 final int userId = user.getIdentifier(); 827 if (!canAccessProfile(userId, "Cannot get launcher extras")) { 828 return null; 829 } 830 if (mPackageManagerInternal.filterAppAccess(packageName, callingUid, userId)) { 831 return null; 832 } 833 return mPackageManagerInternal.getSuspendedPackageLauncherExtras(packageName, userId); 834 } 835 836 @Override getApplicationInfo( String callingPackage, String packageName, int flags, UserHandle user)837 public ApplicationInfo getApplicationInfo( 838 String callingPackage, String packageName, int flags, UserHandle user) 839 throws RemoteException { 840 if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { 841 return null; 842 } 843 844 final int callingUid = injectBinderCallingUid(); 845 final long ident = Binder.clearCallingIdentity(); 846 try { 847 final ApplicationInfo info = mPackageManagerInternal.getApplicationInfo(packageName, 848 flags, callingUid, user.getIdentifier()); 849 return info; 850 } finally { 851 Binder.restoreCallingIdentity(ident); 852 } 853 } 854 855 @Override getAppUsageLimit(String callingPackage, String packageName, UserHandle user)856 public LauncherApps.AppUsageLimit getAppUsageLimit(String callingPackage, 857 String packageName, UserHandle user) { 858 verifyCallingPackage(callingPackage); 859 if (!canAccessProfile(user.getIdentifier(), "Cannot access usage limit")) { 860 return null; 861 } 862 if (!mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid())) { 863 throw new SecurityException("Caller is not the recents app"); 864 } 865 866 final UsageStatsManagerInternal.AppUsageLimitData data = 867 mUsageStatsManagerInternal.getAppUsageLimit(packageName, user); 868 if (data == null) { 869 return null; 870 } 871 return new LauncherApps.AppUsageLimit( 872 data.getTotalUsageLimit(), data.getUsageRemaining()); 873 } 874 ensureShortcutPermission(@onNull String callingPackage)875 private void ensureShortcutPermission(@NonNull String callingPackage) { 876 ensureShortcutPermission(injectBinderCallingUid(), injectBinderCallingPid(), 877 callingPackage); 878 } 879 ensureShortcutPermission(int callerUid, int callerPid, @NonNull String callingPackage)880 private void ensureShortcutPermission(int callerUid, int callerPid, 881 @NonNull String callingPackage) { 882 verifyCallingPackage(callingPackage, callerUid); 883 if (!mShortcutServiceInternal.hasShortcutHostPermission(UserHandle.getUserId(callerUid), 884 callingPackage, callerPid, callerUid)) { 885 throw new SecurityException("Caller can't access shortcut information"); 886 } 887 } 888 ensureStrictAccessShortcutsPermission(@onNull String callingPackage)889 private void ensureStrictAccessShortcutsPermission(@NonNull String callingPackage) { 890 verifyCallingPackage(callingPackage); 891 if (!injectHasAccessShortcutsPermission(injectBinderCallingPid(), 892 injectBinderCallingUid())) { 893 throw new SecurityException("Caller can't access shortcut information"); 894 } 895 } 896 897 /** 898 * Returns true if the caller has the "ACCESS_SHORTCUTS" permission. 899 */ 900 @VisibleForTesting injectHasAccessShortcutsPermission(int callingPid, int callingUid)901 boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) { 902 return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS, 903 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; 904 } 905 906 /** 907 * Returns true if the caller has the "INTERACT_ACROSS_USERS_FULL" permission. 908 */ 909 @VisibleForTesting injectHasInteractAcrossUsersFullPermission(int callingPid, int callingUid)910 boolean injectHasInteractAcrossUsersFullPermission(int callingPid, int callingUid) { 911 return mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, 912 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; 913 } 914 915 @VisibleForTesting injectCreatePendingIntent(int requestCode, @NonNull Intent[] intents, int flags, Bundle options, String ownerPackage, int ownerUserId)916 PendingIntent injectCreatePendingIntent(int requestCode, @NonNull Intent[] intents, 917 int flags, Bundle options, String ownerPackage, int ownerUserId) { 918 return mActivityManagerInternal.getPendingIntentActivityAsApp(requestCode, intents, 919 flags, null /* options */, ownerPackage, ownerUserId); 920 } 921 922 @Override getShortcuts(@onNull final String callingPackage, @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser)923 public ParceledListSlice getShortcuts(@NonNull final String callingPackage, 924 @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser) { 925 ensureShortcutPermission(callingPackage); 926 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) { 927 return new ParceledListSlice<>(Collections.EMPTY_LIST); 928 } 929 930 final long changedSince = query.getChangedSince(); 931 final String packageName = query.getPackage(); 932 final List<String> shortcutIds = query.getShortcutIds(); 933 final List<LocusId> locusIds = query.getLocusIds(); 934 final ComponentName componentName = query.getActivity(); 935 final int flags = query.getQueryFlags(); 936 if (shortcutIds != null && packageName == null) { 937 throw new IllegalArgumentException( 938 "To query by shortcut ID, package name must also be set"); 939 } 940 if (locusIds != null && packageName == null) { 941 throw new IllegalArgumentException( 942 "To query by locus ID, package name must also be set"); 943 } 944 if ((query.getQueryFlags() & ShortcutQuery.FLAG_GET_PERSONS_DATA) != 0) { 945 ensureStrictAccessShortcutsPermission(callingPackage); 946 } 947 948 // TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below. 949 return new ParceledListSlice<>((List<ShortcutInfo>) 950 mShortcutServiceInternal.getShortcuts(getCallingUserId(), 951 callingPackage, changedSince, packageName, shortcutIds, locusIds, 952 componentName, flags, targetUser.getIdentifier(), 953 injectBinderCallingPid(), injectBinderCallingUid())); 954 } 955 956 @Override getShortcutsAsync(@onNull final String callingPackage, @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser, @NonNull final AndroidFuture<List<ShortcutInfo>> cb)957 public void getShortcutsAsync(@NonNull final String callingPackage, 958 @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser, 959 @NonNull final AndroidFuture<List<ShortcutInfo>> cb) { 960 ensureShortcutPermission(callingPackage); 961 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) { 962 cb.complete(Collections.EMPTY_LIST); 963 return; 964 } 965 966 final long changedSince = query.getChangedSince(); 967 final String packageName = query.getPackage(); 968 final List<String> shortcutIds = query.getShortcutIds(); 969 final List<LocusId> locusIds = query.getLocusIds(); 970 final ComponentName componentName = query.getActivity(); 971 final int flags = query.getQueryFlags(); 972 if (shortcutIds != null && packageName == null) { 973 throw new IllegalArgumentException( 974 "To query by shortcut ID, package name must also be set"); 975 } 976 if (locusIds != null && packageName == null) { 977 throw new IllegalArgumentException( 978 "To query by locus ID, package name must also be set"); 979 } 980 if ((query.getQueryFlags() & ShortcutQuery.FLAG_GET_PERSONS_DATA) != 0) { 981 ensureStrictAccessShortcutsPermission(callingPackage); 982 } 983 984 mShortcutServiceInternal.getShortcutsAsync(getCallingUserId(), 985 callingPackage, changedSince, packageName, shortcutIds, locusIds, 986 componentName, flags, targetUser.getIdentifier(), 987 injectBinderCallingPid(), injectBinderCallingUid(), cb); 988 } 989 990 @Override registerShortcutChangeCallback(@onNull final String callingPackage, @NonNull final ShortcutQueryWrapper query, @NonNull final IShortcutChangeCallback callback)991 public void registerShortcutChangeCallback(@NonNull final String callingPackage, 992 @NonNull final ShortcutQueryWrapper query, 993 @NonNull final IShortcutChangeCallback callback) { 994 995 ensureShortcutPermission(callingPackage); 996 997 if (query.getShortcutIds() != null && query.getPackage() == null) { 998 throw new IllegalArgumentException( 999 "To query by shortcut ID, package name must also be set"); 1000 } 1001 if (query.getLocusIds() != null && query.getPackage() == null) { 1002 throw new IllegalArgumentException( 1003 "To query by locus ID, package name must also be set"); 1004 } 1005 1006 UserHandle user = UserHandle.of(injectCallingUserId()); 1007 if (injectHasInteractAcrossUsersFullPermission(injectBinderCallingPid(), 1008 injectBinderCallingUid())) { 1009 user = null; 1010 } 1011 1012 mShortcutChangeHandler.addShortcutChangeCallback(callback, query, user); 1013 } 1014 1015 @Override unregisterShortcutChangeCallback(String callingPackage, IShortcutChangeCallback callback)1016 public void unregisterShortcutChangeCallback(String callingPackage, 1017 IShortcutChangeCallback callback) { 1018 ensureShortcutPermission(callingPackage); 1019 1020 mShortcutChangeHandler.removeShortcutChangeCallback(callback); 1021 } 1022 1023 @Override pinShortcuts(String callingPackage, String packageName, List<String> ids, UserHandle targetUser)1024 public void pinShortcuts(String callingPackage, String packageName, List<String> ids, 1025 UserHandle targetUser) { 1026 ensureShortcutPermission(callingPackage); 1027 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot pin shortcuts")) { 1028 return; 1029 } 1030 1031 mShortcutServiceInternal.pinShortcuts(getCallingUserId(), 1032 callingPackage, packageName, ids, targetUser.getIdentifier()); 1033 } 1034 1035 @Override cacheShortcuts(String callingPackage, String packageName, List<String> ids, UserHandle targetUser, int cacheFlags)1036 public void cacheShortcuts(String callingPackage, String packageName, List<String> ids, 1037 UserHandle targetUser, int cacheFlags) { 1038 ensureStrictAccessShortcutsPermission(callingPackage); 1039 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot cache shortcuts")) { 1040 return; 1041 } 1042 1043 mShortcutServiceInternal.cacheShortcuts( 1044 getCallingUserId(), callingPackage, packageName, ids, 1045 targetUser.getIdentifier(), toShortcutsCacheFlags(cacheFlags)); 1046 } 1047 1048 @Override uncacheShortcuts(String callingPackage, String packageName, List<String> ids, UserHandle targetUser, int cacheFlags)1049 public void uncacheShortcuts(String callingPackage, String packageName, List<String> ids, 1050 UserHandle targetUser, int cacheFlags) { 1051 ensureStrictAccessShortcutsPermission(callingPackage); 1052 if (!canAccessProfile(targetUser.getIdentifier(), "Cannot uncache shortcuts")) { 1053 return; 1054 } 1055 1056 mShortcutServiceInternal.uncacheShortcuts( 1057 getCallingUserId(), callingPackage, packageName, ids, 1058 targetUser.getIdentifier(), toShortcutsCacheFlags(cacheFlags)); 1059 } 1060 1061 @Override getShortcutIconResId(String callingPackage, String packageName, String id, int targetUserId)1062 public int getShortcutIconResId(String callingPackage, String packageName, String id, 1063 int targetUserId) { 1064 ensureShortcutPermission(callingPackage); 1065 if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) { 1066 return 0; 1067 } 1068 1069 return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(), 1070 callingPackage, packageName, id, targetUserId); 1071 } 1072 1073 @Override getShortcutIconFd(String callingPackage, String packageName, String id, int targetUserId)1074 public ParcelFileDescriptor getShortcutIconFd(String callingPackage, 1075 String packageName, String id, int targetUserId) { 1076 ensureShortcutPermission(callingPackage); 1077 if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) { 1078 return null; 1079 } 1080 1081 final AndroidFuture<ParcelFileDescriptor> ret = new AndroidFuture<>(); 1082 mShortcutServiceInternal.getShortcutIconFdAsync(getCallingUserId(), 1083 callingPackage, packageName, id, targetUserId, ret); 1084 try { 1085 return ret.get(); 1086 } catch (InterruptedException | ExecutionException e) { 1087 throw new RuntimeException(e); 1088 } 1089 } 1090 1091 @Override getShortcutIconUri(String callingPackage, String packageName, String shortcutId, int userId)1092 public String getShortcutIconUri(String callingPackage, String packageName, 1093 String shortcutId, int userId) { 1094 ensureShortcutPermission(callingPackage); 1095 if (!canAccessProfile(userId, "Cannot access shortcuts")) { 1096 return null; 1097 } 1098 1099 final AndroidFuture<String> ret = new AndroidFuture<>(); 1100 mShortcutServiceInternal.getShortcutIconUriAsync(getCallingUserId(), callingPackage, 1101 packageName, shortcutId, userId, ret); 1102 try { 1103 return ret.get(); 1104 } catch (InterruptedException | ExecutionException e) { 1105 throw new RuntimeException(e); 1106 } 1107 } 1108 1109 @Override hasShortcutHostPermission(String callingPackage)1110 public boolean hasShortcutHostPermission(String callingPackage) { 1111 verifyCallingPackage(callingPackage); 1112 return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), 1113 callingPackage, injectBinderCallingPid(), injectBinderCallingUid()); 1114 } 1115 1116 @Override 1117 @NonNull getActivityOverrides(String callingPackage, int userId)1118 public Map<String, LauncherActivityInfoInternal> getActivityOverrides(String callingPackage, 1119 int userId) { 1120 ensureShortcutPermission(callingPackage); 1121 int callingUid = Binder.getCallingUid(); 1122 final long callerIdentity = Binder.clearCallingIdentity(); 1123 try { 1124 Map<String, LauncherActivityInfoInternal> shortcutOverridesInfo = new ArrayMap<>(); 1125 UserHandle managedUserHandle = getManagedProfile(userId); 1126 if (managedUserHandle == null) { 1127 return shortcutOverridesInfo; 1128 } 1129 1130 Map<String, String> packagesToOverride = 1131 DevicePolicyCache.getInstance().getLauncherShortcutOverrides(); 1132 for (Map.Entry<String, String> packageNames : packagesToOverride.entrySet()) { 1133 Intent intent = new Intent(Intent.ACTION_MAIN) 1134 .addCategory(Intent.CATEGORY_LAUNCHER) 1135 .setPackage(packageNames.getValue()); 1136 1137 List<LauncherActivityInfoInternal> possibleShortcutOverrides = 1138 queryIntentLauncherActivities( 1139 intent, 1140 callingUid, 1141 managedUserHandle 1142 ); 1143 1144 if (!possibleShortcutOverrides.isEmpty()) { 1145 shortcutOverridesInfo.put(packageNames.getKey(), 1146 possibleShortcutOverrides.get(0)); 1147 } 1148 } 1149 return shortcutOverridesInfo; 1150 } finally { 1151 Binder.restoreCallingIdentity(callerIdentity); 1152 } 1153 } 1154 1155 1156 @Nullable getManagedProfile(int userId)1157 private UserHandle getManagedProfile(int userId) { 1158 for (UserInfo profile : mUm.getProfiles(userId)) { 1159 if (profile.isManagedProfile()) { 1160 return profile.getUserHandle(); 1161 } 1162 } 1163 return null; 1164 } 1165 1166 @Override startShortcut(String callingPackage, String packageName, String featureId, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int targetUserId)1167 public boolean startShortcut(String callingPackage, String packageName, String featureId, 1168 String shortcutId, Rect sourceBounds, Bundle startActivityOptions, 1169 int targetUserId) { 1170 return startShortcutInner(injectBinderCallingUid(), injectBinderCallingPid(), 1171 injectCallingUserId(), callingPackage, packageName, featureId, shortcutId, 1172 sourceBounds, startActivityOptions, targetUserId); 1173 } 1174 startShortcutInner(int callerUid, int callerPid, int callingUserId, String callingPackage, String packageName, String featureId, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int targetUserId)1175 private boolean startShortcutInner(int callerUid, int callerPid, int callingUserId, 1176 String callingPackage, String packageName, String featureId, String shortcutId, 1177 Rect sourceBounds, Bundle startActivityOptions, int targetUserId) { 1178 verifyCallingPackage(callingPackage, callerUid); 1179 if (!canAccessProfile(targetUserId, "Cannot start activity")) { 1180 return false; 1181 } 1182 1183 // Even without the permission, pinned shortcuts are always launchable. 1184 if (!mShortcutServiceInternal.isPinnedByCaller(callingUserId, 1185 callingPackage, packageName, shortcutId, targetUserId)) { 1186 ensureShortcutPermission(callerUid, callerPid, callingPackage); 1187 } 1188 1189 final AndroidFuture<Intent[]> ret = new AndroidFuture<>(); 1190 Intent[] intents; 1191 mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(), callingPackage, 1192 packageName, shortcutId, targetUserId, 1193 injectBinderCallingPid(), injectBinderCallingUid(), ret); 1194 try { 1195 intents = ret.get(); 1196 } catch (InterruptedException | ExecutionException e) { 1197 return false; 1198 } 1199 if (intents == null || intents.length == 0) { 1200 return false; 1201 } 1202 // Note the target activity doesn't have to be exported. 1203 1204 // Flag for bubble 1205 ActivityOptions options = ActivityOptions.fromBundle(startActivityOptions); 1206 if (options != null) { 1207 if (options.isApplyActivityFlagsForBubbles()) { 1208 // Flag for bubble to make behaviour match documentLaunchMode=always. 1209 intents[0].addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); 1210 intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); 1211 } 1212 if (options.isApplyMultipleTaskFlagForShortcut()) { 1213 intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); 1214 } 1215 if (options.isApplyNoUserActionFlagForShortcut()) { 1216 intents[0].addFlags(FLAG_ACTIVITY_NO_USER_ACTION); 1217 } 1218 } 1219 intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1220 intents[0].setSourceBounds(sourceBounds); 1221 1222 // Replace theme for splash screen 1223 final String splashScreenThemeResName = 1224 mShortcutServiceInternal.getShortcutStartingThemeResName(callingUserId, 1225 callingPackage, packageName, shortcutId, targetUserId); 1226 if (splashScreenThemeResName != null && !splashScreenThemeResName.isEmpty()) { 1227 if (startActivityOptions == null) { 1228 startActivityOptions = new Bundle(); 1229 } 1230 startActivityOptions.putString(KEY_SPLASH_SCREEN_THEME, splashScreenThemeResName); 1231 } 1232 return startShortcutIntentsAsPublisher( 1233 intents, packageName, featureId, startActivityOptions, targetUserId); 1234 } 1235 startShortcutIntentsAsPublisher(@onNull Intent[] intents, @NonNull String publisherPackage, @Nullable String publishedFeatureId, Bundle startActivityOptions, int userId)1236 private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, 1237 @NonNull String publisherPackage, @Nullable String publishedFeatureId, 1238 Bundle startActivityOptions, int userId) { 1239 final int code; 1240 try { 1241 code = mActivityTaskManagerInternal.startActivitiesAsPackage(publisherPackage, 1242 publishedFeatureId, userId, intents, 1243 getActivityOptionsForLauncher(startActivityOptions)); 1244 if (ActivityManager.isStartResultSuccessful(code)) { 1245 return true; // Success 1246 } else { 1247 Log.e(TAG, "Couldn't start activity, code=" + code); 1248 } 1249 return false; 1250 } catch (SecurityException e) { 1251 if (DEBUG) { 1252 Slog.d(TAG, "SecurityException while launching intent", e); 1253 } 1254 return false; 1255 } 1256 } 1257 getActivityOptionsForLauncher(Bundle startActivityOptions)1258 private Bundle getActivityOptionsForLauncher(Bundle startActivityOptions) { 1259 // starting a shortcut implies the user's consent, so grant the launchers/senders BAL 1260 // privileges (unless the caller explicitly defined the behavior) 1261 if (startActivityOptions == null) { 1262 return ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode( 1263 MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle(); 1264 } 1265 ActivityOptions activityOptions = ActivityOptions.fromBundle(startActivityOptions); 1266 if (activityOptions.getPendingIntentBackgroundActivityStartMode() 1267 == MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED) { 1268 // only override if the property was not explicitly set 1269 return activityOptions.setPendingIntentBackgroundActivityStartMode( 1270 MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle(); 1271 } 1272 return startActivityOptions; 1273 } 1274 1275 @Override isActivityEnabled( String callingPackage, ComponentName component, UserHandle user)1276 public boolean isActivityEnabled( 1277 String callingPackage, ComponentName component, UserHandle user) 1278 throws RemoteException { 1279 if (!canAccessProfile(user.getIdentifier(), "Cannot check component")) { 1280 return false; 1281 } 1282 1283 final int callingUid = injectBinderCallingUid(); 1284 final int state = mPackageManagerInternal.getComponentEnabledSetting(component, 1285 callingUid, user.getIdentifier()); 1286 switch (state) { 1287 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 1288 break; // Need to check the manifest's enabled state. 1289 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 1290 return true; 1291 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 1292 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 1293 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: 1294 return false; 1295 } 1296 1297 final long ident = Binder.clearCallingIdentity(); 1298 try { 1299 final ActivityInfo info = mPackageManagerInternal.getActivityInfo(component, 1300 PackageManager.MATCH_DIRECT_BOOT_AWARE 1301 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 1302 callingUid, user.getIdentifier()); 1303 // Note we don't check "exported" because if the caller has the same UID as the 1304 // callee's UID, it can still be launched. 1305 // (If an app doesn't export a front door activity and causes issues with the 1306 // launcher, that's just the app's bug.) 1307 return info != null && info.isEnabled(); 1308 } finally { 1309 Binder.restoreCallingIdentity(ident); 1310 } 1311 } 1312 1313 @Override startSessionDetailsActivityAsUser(IApplicationThread caller, String callingPackage, String callingFeatureId, SessionInfo sessionInfo, Rect sourceBounds, Bundle opts, UserHandle userHandle)1314 public void startSessionDetailsActivityAsUser(IApplicationThread caller, 1315 String callingPackage, String callingFeatureId, SessionInfo sessionInfo, 1316 Rect sourceBounds, Bundle opts, UserHandle userHandle) throws RemoteException { 1317 int userId = userHandle.getIdentifier(); 1318 if (!canAccessProfile(userId, "Cannot start details activity")) { 1319 return; 1320 } 1321 1322 Intent i = new Intent(Intent.ACTION_VIEW) 1323 .setData(new Uri.Builder() 1324 .scheme("market") 1325 .authority("details") 1326 .appendQueryParameter("id", sessionInfo.appPackageName) 1327 .build()) 1328 .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app") 1329 .authority(callingPackage).build()); 1330 i.setSourceBounds(sourceBounds); 1331 1332 mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, 1333 callingFeatureId, i, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK, 1334 getActivityOptionsForLauncher(opts), userId); 1335 } 1336 1337 @Override getActivityLaunchIntent(String callingPackage, ComponentName component, UserHandle user)1338 public PendingIntent getActivityLaunchIntent(String callingPackage, ComponentName component, 1339 UserHandle user) { 1340 if (mContext.checkPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS, 1341 injectBinderCallingPid(), injectBinderCallingUid()) 1342 != PackageManager.PERMISSION_GRANTED) { 1343 throw new SecurityException("Permission START_TASKS_FROM_RECENTS required"); 1344 } 1345 if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) { 1346 throw new ActivityNotFoundException("Activity could not be found"); 1347 } 1348 1349 final Intent launchIntent = getMainActivityLaunchIntent(component, user); 1350 if (launchIntent == null) { 1351 throw new SecurityException("Attempt to launch activity without " 1352 + " category Intent.CATEGORY_LAUNCHER " + component); 1353 } 1354 1355 final long ident = Binder.clearCallingIdentity(); 1356 try { 1357 // If we reach here, we've verified that the caller has access to the profile and 1358 // is launching an exported activity with CATEGORY_LAUNCHER so we can clear the 1359 // calling identity to mirror the startActivityAsUser() call which does not validate 1360 // the calling user 1361 return PendingIntent.getActivityAsUser(mContext, 0 /* requestCode */, launchIntent, 1362 FLAG_MUTABLE, null /* opts */, user); 1363 } finally { 1364 Binder.restoreCallingIdentity(ident); 1365 } 1366 } 1367 1368 @Override startActivityAsUser(IApplicationThread caller, String callingPackage, String callingFeatureId, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user)1369 public void startActivityAsUser(IApplicationThread caller, String callingPackage, 1370 String callingFeatureId, ComponentName component, Rect sourceBounds, 1371 Bundle opts, UserHandle user) throws RemoteException { 1372 if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) { 1373 return; 1374 } 1375 1376 Intent launchIntent = getMainActivityLaunchIntent(component, user); 1377 if (launchIntent == null) { 1378 throw new SecurityException("Attempt to launch activity without " 1379 + " category Intent.CATEGORY_LAUNCHER " + component); 1380 } 1381 launchIntent.setSourceBounds(sourceBounds); 1382 1383 mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, 1384 callingFeatureId, launchIntent, /* resultTo= */ null, 1385 Intent.FLAG_ACTIVITY_NEW_TASK, getActivityOptionsForLauncher(opts), 1386 user.getIdentifier()); 1387 } 1388 1389 /** 1390 * Returns the main activity launch intent for the given component package. 1391 */ getMainActivityLaunchIntent(ComponentName component, UserHandle user)1392 private Intent getMainActivityLaunchIntent(ComponentName component, UserHandle user) { 1393 Intent launchIntent = new Intent(Intent.ACTION_MAIN); 1394 launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); 1395 launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1396 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 1397 launchIntent.setPackage(component.getPackageName()); 1398 1399 boolean canLaunch = false; 1400 1401 final int callingUid = injectBinderCallingUid(); 1402 final long ident = Binder.clearCallingIdentity(); 1403 try { 1404 // Check that the component actually has Intent.CATEGORY_LAUCNCHER 1405 // as calling startActivityAsUser ignores the category and just 1406 // resolves based on the component if present. 1407 final List<ResolveInfo> apps = mPackageManagerInternal.queryIntentActivities( 1408 launchIntent, 1409 launchIntent.resolveTypeIfNeeded(mContext.getContentResolver()), 1410 PackageManager.MATCH_DIRECT_BOOT_AWARE 1411 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 1412 callingUid, user.getIdentifier()); 1413 final int size = apps.size(); 1414 for (int i = 0; i < size; ++i) { 1415 ActivityInfo activityInfo = apps.get(i).activityInfo; 1416 if (activityInfo.packageName.equals(component.getPackageName()) && 1417 activityInfo.name.equals(component.getClassName())) { 1418 if (!activityInfo.exported) { 1419 throw new SecurityException("Cannot launch non-exported components " 1420 + component); 1421 } 1422 1423 // Found an activity with category launcher that matches 1424 // this component so ok to launch. 1425 launchIntent.setPackage(null); 1426 launchIntent.setComponent(component); 1427 canLaunch = true; 1428 break; 1429 } 1430 } 1431 if (!canLaunch) { 1432 return null; 1433 } 1434 } finally { 1435 Binder.restoreCallingIdentity(ident); 1436 } 1437 return launchIntent; 1438 } 1439 1440 @Override showAppDetailsAsUser(IApplicationThread caller, String callingPackage, String callingFeatureId, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user)1441 public void showAppDetailsAsUser(IApplicationThread caller, 1442 String callingPackage, String callingFeatureId, ComponentName component, 1443 Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { 1444 if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) { 1445 return; 1446 } 1447 1448 final Intent intent; 1449 final long ident = Binder.clearCallingIdentity(); 1450 try { 1451 String packageName = component.getPackageName(); 1452 int uId = -1; 1453 try { 1454 uId = mContext.getPackageManager().getApplicationInfo( 1455 packageName, PackageManager.MATCH_ANY_USER).uid; 1456 } catch (PackageManager.NameNotFoundException e) { 1457 Log.d(TAG, "package not found: " + e); 1458 } 1459 intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, 1460 Uri.fromParts("package", packageName, null)); 1461 intent.putExtra("uId", uId); 1462 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 1463 intent.setSourceBounds(sourceBounds); 1464 } finally { 1465 Binder.restoreCallingIdentity(ident); 1466 } 1467 mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, 1468 callingFeatureId, intent, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK, 1469 getActivityOptionsForLauncher(opts), user.getIdentifier()); 1470 } 1471 1472 @Override onShellCommand(FileDescriptor in, @NonNull FileDescriptor out, @NonNull FileDescriptor err, @Nullable String[] args, ShellCallback cb, @Nullable ResultReceiver receiver)1473 public void onShellCommand(FileDescriptor in, @NonNull FileDescriptor out, 1474 @NonNull FileDescriptor err, @Nullable String[] args, ShellCallback cb, 1475 @Nullable ResultReceiver receiver) { 1476 final int callingUid = injectBinderCallingUid(); 1477 if (!(callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID)) { 1478 throw new SecurityException("Caller must be shell"); 1479 } 1480 1481 final long token = injectClearCallingIdentity(); 1482 try { 1483 int status = (new LauncherAppsShellCommand()) 1484 .exec(this, in, out, err, args, cb, receiver); 1485 if (receiver != null) { 1486 receiver.send(status, null); 1487 } 1488 } finally { 1489 injectRestoreCallingIdentity(token); 1490 } 1491 } 1492 1493 /** Handles Shell commands for LauncherAppsService */ 1494 private class LauncherAppsShellCommand extends ShellCommand { 1495 @Override onCommand(@ullable String cmd)1496 public int onCommand(@Nullable String cmd) { 1497 if ("dump-view-hierarchies".equals(cmd)) { 1498 dumpViewCaptureDataToShell(); 1499 return 0; 1500 } else { 1501 return handleDefaultCommands(cmd); 1502 } 1503 } 1504 dumpViewCaptureDataToShell()1505 private void dumpViewCaptureDataToShell() { 1506 try (ZipOutputStream zipOs = new ZipOutputStream(getRawOutputStream())) { 1507 forEachViewCaptureWindow((fileName, is) -> { 1508 try { 1509 zipOs.putNextEntry(new ZipEntry("FS" + fileName)); 1510 is.transferTo(zipOs); 1511 zipOs.closeEntry(); 1512 } catch (IOException e) { 1513 getErrPrintWriter().write("Failed to output " + fileName 1514 + " data to shell: " + e.getMessage()); 1515 } 1516 }); 1517 } catch (IOException e) { 1518 getErrPrintWriter().write("Failed to create or close zip output stream: " 1519 + e.getMessage()); 1520 } 1521 } 1522 1523 @Override onHelp()1524 public void onHelp() { 1525 final PrintWriter pw = getOutPrintWriter(); 1526 pw.println("Usage: cmd launcherapps COMMAND [options ...]"); 1527 pw.println(); 1528 pw.println("cmd launcherapps dump-view-hierarchies"); 1529 pw.println(" Output captured view hierarchies. Files will be generated in "); 1530 pw.println(" `" + WM_TRACE_DIR + "`. After pulling the data to your device,"); 1531 pw.println(" you can upload / visualize it at `go/winscope`."); 1532 pw.println(); 1533 } 1534 } 1535 1536 /** 1537 * Using a pipe, outputs view capture data to the wmtrace dir 1538 */ dump(@onNull FileDescriptor fd, @NonNull PrintWriter pw, @Nullable String[] args)1539 protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, 1540 @Nullable String[] args) { 1541 super.dump(fd, pw, args); 1542 1543 // Before the wmtrace directory is picked up by dumpstate service, some processes need 1544 // to write their data to that location. They can do that via these dumpCallbacks. 1545 forEachViewCaptureWindow(this::dumpViewCaptureDataToWmTrace); 1546 } 1547 dumpViewCaptureDataToWmTrace(@onNull String fileName, @NonNull InputStream is)1548 private void dumpViewCaptureDataToWmTrace(@NonNull String fileName, 1549 @NonNull InputStream is) { 1550 Path outPath = Paths.get(fileName); 1551 try { 1552 Files.copy(is, outPath, StandardCopyOption.REPLACE_EXISTING); 1553 Files.setPosixFilePermissions(outPath, WM_TRACE_FILE_PERMISSIONS); 1554 } catch (IOException e) { 1555 Log.d(TAG, "failed to write data to " + fileName + " in wmtrace dir", e); 1556 } 1557 } 1558 1559 /** 1560 * IDumpCallback.onDump alerts the in-process ViewCapture instance to start sending data 1561 * to LauncherAppsService via the pipe's input provided. This data (as well as an output 1562 * file name) is provided to the consumer via an InputStream to output where it wants (for 1563 * example, the winscope trace directory or the shell's stdout). 1564 */ forEachViewCaptureWindow( @onNull BiConsumer<String, InputStream> outputtingConsumer)1565 private void forEachViewCaptureWindow( 1566 @NonNull BiConsumer<String, InputStream> outputtingConsumer) { 1567 for (int i = mDumpCallbacks.beginBroadcast() - 1; i >= 0; i--) { 1568 String packageName = (String) mDumpCallbacks.getBroadcastCookie(i); 1569 String fileName = WM_TRACE_DIR + packageName + "_" + i + VC_FILE_SUFFIX; 1570 1571 try { 1572 // Order is important here. OnDump needs to be called before the BiConsumer 1573 // accepts & starts blocking on reading the input stream. 1574 ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); 1575 mDumpCallbacks.getBroadcastItem(i).onDump(pipe[1]); 1576 1577 InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0]); 1578 outputtingConsumer.accept(fileName, is); 1579 is.close(); 1580 } catch (Exception e) { 1581 Log.d(TAG, "failed to pipe view capture data", e); 1582 } 1583 } 1584 mDumpCallbacks.finishBroadcast(); 1585 } 1586 1587 @RequiresPermission(READ_FRAME_BUFFER) 1588 @Override registerDumpCallback(@onNull IDumpCallback cb)1589 public void registerDumpCallback(@NonNull IDumpCallback cb) { 1590 int status = checkCallingOrSelfPermissionForPreflight(mContext, READ_FRAME_BUFFER); 1591 if (PERMISSION_GRANTED == status) { 1592 String name = mContext.getPackageManager().getNameForUid(Binder.getCallingUid()); 1593 mDumpCallbacks.register(cb, name); 1594 } else { 1595 Log.w(TAG, "caller lacks permissions to registerDumpCallback"); 1596 } 1597 } 1598 1599 @RequiresPermission(READ_FRAME_BUFFER) 1600 @Override unRegisterDumpCallback(@onNull IDumpCallback cb)1601 public void unRegisterDumpCallback(@NonNull IDumpCallback cb) { 1602 int status = checkCallingOrSelfPermissionForPreflight(mContext, READ_FRAME_BUFFER); 1603 if (PERMISSION_GRANTED == status) { 1604 mDumpCallbacks.unregister(cb); 1605 } else { 1606 Log.w(TAG, "caller lacks permissions to unRegisterDumpCallback"); 1607 } 1608 } 1609 1610 /** Checks if user is a profile of or same as listeningUser. 1611 * and the user is enabled. */ isEnabledProfileOf(UserHandle listeningUser, UserHandle user, String debugMsg)1612 private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user, 1613 String debugMsg) { 1614 return mUserManagerInternal.isProfileAccessible(listeningUser.getIdentifier(), 1615 user.getIdentifier(), debugMsg, false); 1616 } 1617 1618 /** 1619 * Returns whether or not the result to the listener should be filtered. 1620 * 1621 * @param packageName The package to be accessed by the listener. 1622 * @param cookie The listener 1623 * @param user The user where the package resides. 1624 */ isPackageVisibleToListener(String packageName, BroadcastCookie cookie, UserHandle user)1625 private boolean isPackageVisibleToListener(String packageName, BroadcastCookie cookie, 1626 UserHandle user) { 1627 // Do not filter the uninstalled package access since it might break callbacks such as 1628 // shortcut changes and unavailable packages events. 1629 return !mPackageManagerInternal.filterAppAccess(packageName, cookie.callingUid, 1630 user.getIdentifier(), false /* filterUninstalled */); 1631 } 1632 1633 /** Returns whether or not the given appId is in allow list */ isCallingAppIdAllowed(int[] appIdAllowList, @AppIdInt int appId)1634 private static boolean isCallingAppIdAllowed(int[] appIdAllowList, @AppIdInt int appId) { 1635 if (appIdAllowList == null || appId < Process.FIRST_APPLICATION_UID) { 1636 return true; 1637 } 1638 return Arrays.binarySearch(appIdAllowList, appId) > -1; 1639 } 1640 getFilteredPackageNames(String[] packageNames, BroadcastCookie cookie, UserHandle user)1641 private String[] getFilteredPackageNames(String[] packageNames, BroadcastCookie cookie, 1642 UserHandle user) { 1643 final List<String> filteredPackageNames = new ArrayList<>(); 1644 for (String packageName : packageNames) { 1645 if (!isPackageVisibleToListener(packageName, cookie, user)) { 1646 continue; 1647 } 1648 filteredPackageNames.add(packageName); 1649 } 1650 return filteredPackageNames.toArray(new String[filteredPackageNames.size()]); 1651 } 1652 toShortcutsCacheFlags(int cacheFlags)1653 private int toShortcutsCacheFlags(int cacheFlags) { 1654 int ret = 0; 1655 if (cacheFlags == FLAG_CACHE_NOTIFICATION_SHORTCUTS) { 1656 ret = ShortcutInfo.FLAG_CACHED_NOTIFICATIONS; 1657 } else if (cacheFlags == FLAG_CACHE_BUBBLE_SHORTCUTS) { 1658 ret = ShortcutInfo.FLAG_CACHED_BUBBLES; 1659 } else if (cacheFlags == FLAG_CACHE_PEOPLE_TILE_SHORTCUTS) { 1660 ret = ShortcutInfo.FLAG_CACHED_PEOPLE_TILE; 1661 } 1662 Preconditions.checkArgumentPositive(ret, "Invalid cache owner"); 1663 1664 return ret; 1665 } 1666 1667 @VisibleForTesting postToPackageMonitorHandler(Runnable r)1668 void postToPackageMonitorHandler(Runnable r) { 1669 mCallbackHandler.post(r); 1670 } 1671 1672 /** 1673 * Check all installed apps and if a package is installed via Incremental and not fully 1674 * loaded, register loading progress listener. 1675 */ registerLoadingProgressForIncrementalApps()1676 void registerLoadingProgressForIncrementalApps() { 1677 final List<UserHandle> users = mUm.getUserProfiles(); 1678 if (users == null) { 1679 return; 1680 } 1681 for (UserHandle user : users) { 1682 mPackageManagerInternal.forEachInstalledPackage(pkg -> { 1683 final String packageName = pkg.getPackageName(); 1684 if (mPackageManagerInternal.getIncrementalStatesInfo(packageName, 1685 Process.myUid(), user.getIdentifier()).isLoading()) { 1686 mPackageManagerInternal.registerInstalledLoadingProgressCallback( 1687 packageName, new PackageLoadingProgressCallback(packageName, user), 1688 user.getIdentifier()); 1689 } 1690 }, user.getIdentifier()); 1691 } 1692 } 1693 1694 public static class ShortcutChangeHandler implements LauncherApps.ShortcutChangeCallback { 1695 private final UserManagerInternal mUserManagerInternal; 1696 ShortcutChangeHandler(UserManagerInternal userManager)1697 ShortcutChangeHandler(UserManagerInternal userManager) { 1698 mUserManagerInternal = userManager; 1699 } 1700 1701 private final RemoteCallbackList<IShortcutChangeCallback> mCallbacks = 1702 new RemoteCallbackList<>(); 1703 addShortcutChangeCallback(IShortcutChangeCallback callback, ShortcutQueryWrapper query, UserHandle user)1704 public synchronized void addShortcutChangeCallback(IShortcutChangeCallback callback, 1705 ShortcutQueryWrapper query, UserHandle user) { 1706 mCallbacks.unregister(callback); 1707 mCallbacks.register(callback, new Pair<>(query, user)); 1708 } 1709 removeShortcutChangeCallback( IShortcutChangeCallback callback)1710 public synchronized void removeShortcutChangeCallback( 1711 IShortcutChangeCallback callback) { 1712 mCallbacks.unregister(callback); 1713 } 1714 1715 @Override onShortcutsAddedOrUpdated(String packageName, List<ShortcutInfo> shortcuts, UserHandle user)1716 public void onShortcutsAddedOrUpdated(String packageName, List<ShortcutInfo> shortcuts, 1717 UserHandle user) { 1718 onShortcutEvent(packageName, shortcuts, user, false); 1719 } 1720 1721 @Override onShortcutsRemoved(String packageName, List<ShortcutInfo> shortcuts, UserHandle user)1722 public void onShortcutsRemoved(String packageName, List<ShortcutInfo> shortcuts, 1723 UserHandle user) { 1724 onShortcutEvent(packageName, shortcuts, user, true); 1725 } 1726 onShortcutEvent(String packageName, List<ShortcutInfo> shortcuts, UserHandle user, boolean shortcutsRemoved)1727 private void onShortcutEvent(String packageName, 1728 List<ShortcutInfo> shortcuts, UserHandle user, boolean shortcutsRemoved) { 1729 int count = mCallbacks.beginBroadcast(); 1730 1731 for (int i = 0; i < count; i++) { 1732 final IShortcutChangeCallback callback = mCallbacks.getBroadcastItem(i); 1733 final Pair<ShortcutQueryWrapper, UserHandle> cookie = 1734 (Pair<ShortcutQueryWrapper, UserHandle>) 1735 mCallbacks.getBroadcastCookie(i); 1736 1737 final UserHandle callbackUser = cookie.second; 1738 if (callbackUser != null && !hasUserAccess(callbackUser, user)) { 1739 // Callback owner does not have access to the shortcuts' user. 1740 continue; 1741 } 1742 1743 // Filter the list by query, if any matches exists, send via callback. 1744 List<ShortcutInfo> matchedList = filterShortcutsByQuery(packageName, shortcuts, 1745 cookie.first, shortcutsRemoved); 1746 if (!CollectionUtils.isEmpty(matchedList)) { 1747 try { 1748 if (shortcutsRemoved) { 1749 callback.onShortcutsRemoved(packageName, matchedList, user); 1750 } else { 1751 callback.onShortcutsAddedOrUpdated(packageName, matchedList, user); 1752 } 1753 } catch (RemoteException e) { 1754 // The RemoteCallbackList will take care of removing the dead object. 1755 } 1756 } 1757 } 1758 1759 mCallbacks.finishBroadcast(); 1760 } 1761 filterShortcutsByQuery(String packageName, List<ShortcutInfo> shortcuts, ShortcutQueryWrapper query, boolean shortcutsRemoved)1762 public static List<ShortcutInfo> filterShortcutsByQuery(String packageName, 1763 List<ShortcutInfo> shortcuts, ShortcutQueryWrapper query, 1764 boolean shortcutsRemoved) { 1765 final long changedSince = query.getChangedSince(); 1766 final String queryPackage = query.getPackage(); 1767 final List<String> shortcutIds = query.getShortcutIds(); 1768 final List<LocusId> locusIds = query.getLocusIds(); 1769 final ComponentName activity = query.getActivity(); 1770 final int flags = query.getQueryFlags(); 1771 1772 if (queryPackage != null && !queryPackage.equals(packageName)) { 1773 return null; 1774 } 1775 1776 List<ShortcutInfo> matches = new ArrayList<>(); 1777 1778 final boolean matchDynamic = (flags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0; 1779 final boolean matchPinned = (flags & ShortcutQuery.FLAG_MATCH_PINNED) != 0; 1780 final boolean matchManifest = (flags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0; 1781 final boolean matchCached = (flags & ShortcutQuery.FLAG_MATCH_CACHED) != 0; 1782 final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0) 1783 | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0) 1784 | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) 1785 | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); 1786 1787 for (int i = 0; i < shortcuts.size(); i++) { 1788 final ShortcutInfo si = shortcuts.get(i); 1789 1790 if (activity != null && !activity.equals(si.getActivity())) { 1791 continue; 1792 } 1793 if (changedSince != 0 && changedSince > si.getLastChangedTimestamp()) { 1794 continue; 1795 } 1796 if (shortcutIds != null && !shortcutIds.contains(si.getId())) { 1797 continue; 1798 } 1799 if (locusIds != null && !locusIds.contains(si.getLocusId())) { 1800 continue; 1801 } 1802 if (shortcutsRemoved || (shortcutFlags & si.getFlags()) != 0) { 1803 matches.add(si); 1804 } 1805 } 1806 1807 return matches; 1808 } 1809 hasUserAccess(UserHandle callbackUser, UserHandle shortcutUser)1810 private boolean hasUserAccess(UserHandle callbackUser, UserHandle shortcutUser) { 1811 final int callbackUserId = callbackUser.getIdentifier(); 1812 final int shortcutUserId = shortcutUser.getIdentifier(); 1813 1814 if (shortcutUser == callbackUser) return true; 1815 return mUserManagerInternal.isProfileAccessible(callbackUserId, shortcutUserId, 1816 null, false); 1817 } 1818 } 1819 1820 private class PackageRemovedListener extends BroadcastReceiver { 1821 1822 @Override onReceive(Context context, Intent intent)1823 public void onReceive(Context context, Intent intent) { 1824 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 1825 UserHandle.USER_NULL); 1826 if (userId == UserHandle.USER_NULL) { 1827 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent); 1828 return; 1829 } 1830 final String action = intent.getAction(); 1831 // Handle onPackageRemoved. 1832 if (Intent.ACTION_PACKAGE_REMOVED_INTERNAL.equals(action)) { 1833 final String packageName = getPackageName(intent); 1834 final int[] appIdAllowList = 1835 intent.getIntArrayExtra(Intent.EXTRA_VISIBILITY_ALLOW_LIST); 1836 // If {@link #EXTRA_REPLACING} is true, that will be onPackageChanged case. 1837 if (packageName != null && !intent.getBooleanExtra( 1838 Intent.EXTRA_REPLACING, /* defaultValue= */ false)) { 1839 final UserHandle user = new UserHandle(userId); 1840 final int n = mListeners.beginBroadcast(); 1841 try { 1842 for (int i = 0; i < n; i++) { 1843 final IOnAppsChangedListener listener = 1844 mListeners.getBroadcastItem(i); 1845 final BroadcastCookie cookie = 1846 (BroadcastCookie) mListeners.getBroadcastCookie(i); 1847 if (!isEnabledProfileOf(cookie.user, user, "onPackageRemoved")) { 1848 continue; 1849 } 1850 if (!isCallingAppIdAllowed(appIdAllowList, UserHandle.getAppId( 1851 cookie.callingUid))) { 1852 continue; 1853 } 1854 try { 1855 listener.onPackageRemoved(user, packageName); 1856 } catch (RemoteException re) { 1857 Slog.d(TAG, "Callback failed ", re); 1858 } 1859 } 1860 } finally { 1861 mListeners.finishBroadcast(); 1862 } 1863 } 1864 } 1865 } 1866 getPackageName(Intent intent)1867 private String getPackageName(Intent intent) { 1868 final Uri uri = intent.getData(); 1869 final String pkg = uri != null ? uri.getSchemeSpecificPart() : null; 1870 return pkg; 1871 } 1872 } 1873 1874 private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener { 1875 1876 // TODO Simplify with lambdas. 1877 1878 @Override onPackageAdded(String packageName, int uid)1879 public void onPackageAdded(String packageName, int uid) { 1880 UserHandle user = new UserHandle(getChangingUserId()); 1881 final int n = mListeners.beginBroadcast(); 1882 try { 1883 for (int i = 0; i < n; i++) { 1884 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1885 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1886 if (!isEnabledProfileOf(cookie.user, user, "onPackageAdded")) { 1887 continue; 1888 } 1889 if (!isPackageVisibleToListener(packageName, cookie, user)) { 1890 continue; 1891 } 1892 try { 1893 listener.onPackageAdded(user, packageName); 1894 } catch (RemoteException re) { 1895 Slog.d(TAG, "Callback failed ", re); 1896 } 1897 } 1898 } finally { 1899 mListeners.finishBroadcast(); 1900 } 1901 super.onPackageAdded(packageName, uid); 1902 mPackageManagerInternal.registerInstalledLoadingProgressCallback(packageName, 1903 new PackageLoadingProgressCallback(packageName, user), 1904 user.getIdentifier()); 1905 } 1906 1907 @Override onPackageModified(String packageName)1908 public void onPackageModified(String packageName) { 1909 onPackageChanged(packageName); 1910 super.onPackageModified(packageName); 1911 } 1912 onPackageChanged(String packageName)1913 private void onPackageChanged(String packageName) { 1914 UserHandle user = new UserHandle(getChangingUserId()); 1915 final int n = mListeners.beginBroadcast(); 1916 try { 1917 for (int i = 0; i < n; i++) { 1918 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1919 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1920 if (!isEnabledProfileOf(cookie.user, user, "onPackageModified")) { 1921 continue; 1922 } 1923 if (!isPackageVisibleToListener(packageName, cookie, user)) { 1924 continue; 1925 } 1926 try { 1927 listener.onPackageChanged(user, packageName); 1928 } catch (RemoteException re) { 1929 Slog.d(TAG, "Callback failed ", re); 1930 } 1931 } 1932 } finally { 1933 mListeners.finishBroadcast(); 1934 } 1935 } 1936 1937 @Override onPackagesAvailable(String[] packages)1938 public void onPackagesAvailable(String[] packages) { 1939 UserHandle user = new UserHandle(getChangingUserId()); 1940 final int n = mListeners.beginBroadcast(); 1941 try { 1942 for (int i = 0; i < n; i++) { 1943 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1944 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1945 if (!isEnabledProfileOf(cookie.user, user, "onPackagesAvailable")) { 1946 continue; 1947 } 1948 final String[] filteredPackages = 1949 getFilteredPackageNames(packages, cookie, user); 1950 // If all packages are filtered, skip notifying listener. 1951 if (ArrayUtils.isEmpty(filteredPackages)) { 1952 continue; 1953 } 1954 try { 1955 listener.onPackagesAvailable(user, filteredPackages, isReplacing()); 1956 } catch (RemoteException re) { 1957 Slog.d(TAG, "Callback failed ", re); 1958 } 1959 } 1960 } finally { 1961 mListeners.finishBroadcast(); 1962 } 1963 1964 super.onPackagesAvailable(packages); 1965 } 1966 1967 @Override onPackagesUnavailable(String[] packages)1968 public void onPackagesUnavailable(String[] packages) { 1969 UserHandle user = new UserHandle(getChangingUserId()); 1970 final int n = mListeners.beginBroadcast(); 1971 try { 1972 for (int i = 0; i < n; i++) { 1973 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 1974 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 1975 if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnavailable")) { 1976 continue; 1977 } 1978 final String[] filteredPackages = 1979 getFilteredPackageNames(packages, cookie, user); 1980 // If all packages are filtered, skip notifying listener. 1981 if (ArrayUtils.isEmpty(filteredPackages)) { 1982 continue; 1983 } 1984 try { 1985 listener.onPackagesUnavailable(user, filteredPackages, isReplacing()); 1986 } catch (RemoteException re) { 1987 Slog.d(TAG, "Callback failed ", re); 1988 } 1989 } 1990 } finally { 1991 mListeners.finishBroadcast(); 1992 } 1993 1994 super.onPackagesUnavailable(packages); 1995 } 1996 1997 @Override onPackagesSuspended(String[] packages)1998 public void onPackagesSuspended(String[] packages) { 1999 UserHandle user = new UserHandle(getChangingUserId()); 2000 final ArrayList<Pair<String, Bundle>> packagesWithExtras = new ArrayList<>(); 2001 final ArrayList<String> packagesWithoutExtras = new ArrayList<>(); 2002 for (String pkg : packages) { 2003 final Bundle launcherExtras = 2004 mPackageManagerInternal.getSuspendedPackageLauncherExtras(pkg, 2005 user.getIdentifier()); 2006 if (launcherExtras != null) { 2007 packagesWithExtras.add(new Pair<>(pkg, launcherExtras)); 2008 } else { 2009 packagesWithoutExtras.add(pkg); 2010 } 2011 } 2012 final String[] packagesNullExtras = packagesWithoutExtras.toArray( 2013 new String[packagesWithoutExtras.size()]); 2014 final int n = mListeners.beginBroadcast(); 2015 try { 2016 for (int i = 0; i < n; i++) { 2017 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 2018 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 2019 if (!isEnabledProfileOf(cookie.user, user, "onPackagesSuspended")) { 2020 continue; 2021 } 2022 final String[] filteredPackagesWithoutExtras = 2023 getFilteredPackageNames(packagesNullExtras, cookie, user); 2024 try { 2025 if (!ArrayUtils.isEmpty(filteredPackagesWithoutExtras)) { 2026 listener.onPackagesSuspended(user, filteredPackagesWithoutExtras, 2027 /* launcherExtras= */ null); 2028 } 2029 for (int idx = 0; idx < packagesWithExtras.size(); idx++) { 2030 Pair<String, Bundle> packageExtraPair = packagesWithExtras.get(idx); 2031 if (!isPackageVisibleToListener( 2032 packageExtraPair.first, cookie, user)) { 2033 continue; 2034 } 2035 listener.onPackagesSuspended(user, 2036 new String[]{packageExtraPair.first}, 2037 packageExtraPair.second); 2038 } 2039 } catch (RemoteException re) { 2040 Slog.d(TAG, "Callback failed ", re); 2041 } 2042 } 2043 } finally { 2044 mListeners.finishBroadcast(); 2045 } 2046 } 2047 2048 @Override onPackagesUnsuspended(String[] packages)2049 public void onPackagesUnsuspended(String[] packages) { 2050 UserHandle user = new UserHandle(getChangingUserId()); 2051 final int n = mListeners.beginBroadcast(); 2052 try { 2053 for (int i = 0; i < n; i++) { 2054 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 2055 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 2056 if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnsuspended")) { 2057 continue; 2058 } 2059 final String[] filteredPackages = 2060 getFilteredPackageNames(packages, cookie, user); 2061 // If all packages are filtered, skip notifying listener. 2062 if (ArrayUtils.isEmpty(filteredPackages)) { 2063 continue; 2064 } 2065 try { 2066 listener.onPackagesUnsuspended(user, filteredPackages); 2067 } catch (RemoteException re) { 2068 Slog.d(TAG, "Callback failed ", re); 2069 } 2070 } 2071 } finally { 2072 mListeners.finishBroadcast(); 2073 } 2074 2075 super.onPackagesUnsuspended(packages); 2076 } 2077 2078 @Override onShortcutChanged(@onNull String packageName, @UserIdInt int userId)2079 public void onShortcutChanged(@NonNull String packageName, 2080 @UserIdInt int userId) { 2081 postToPackageMonitorHandler(() -> onShortcutChangedInner(packageName, userId)); 2082 } 2083 onShortcutChangedInner(@onNull String packageName, @UserIdInt int userId)2084 private void onShortcutChangedInner(@NonNull String packageName, 2085 @UserIdInt int userId) { 2086 final int n = mListeners.beginBroadcast(); 2087 try { 2088 final UserHandle user = UserHandle.of(userId); 2089 2090 for (int i = 0; i < n; i++) { 2091 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 2092 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 2093 if (!isEnabledProfileOf(cookie.user, user, "onShortcutChanged")) { 2094 continue; 2095 } 2096 if (!isPackageVisibleToListener(packageName, cookie, user)) { 2097 continue; 2098 } 2099 final int launcherUserId = cookie.user.getIdentifier(); 2100 2101 // Make sure the caller has the permission. 2102 if (!mShortcutServiceInternal.hasShortcutHostPermission( 2103 launcherUserId, cookie.packageName, 2104 cookie.callingPid, cookie.callingUid)) { 2105 continue; 2106 } 2107 // Each launcher has a different set of pinned shortcuts, so we need to do a 2108 // query in here. 2109 // (As of now, only one launcher has the permission at a time, so it's a bit 2110 // moot, but we may change the permission model eventually.) 2111 final List<ShortcutInfo> list = 2112 mShortcutServiceInternal.getShortcuts(launcherUserId, 2113 cookie.packageName, 2114 /* changedSince= */ 0, packageName, /* shortcutIds=*/ null, 2115 /* locusIds=*/ null, /* component= */ null, 2116 ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY 2117 | ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED 2118 , userId, cookie.callingPid, cookie.callingUid); 2119 try { 2120 listener.onShortcutChanged(user, packageName, 2121 new ParceledListSlice<>(list)); 2122 } catch (RemoteException re) { 2123 Slog.d(TAG, "Callback failed ", re); 2124 } 2125 2126 } 2127 } catch (RuntimeException e) { 2128 // When the user is locked we get IllegalState, so just catch all. 2129 Log.w(TAG, e.getMessage(), e); 2130 } finally { 2131 mListeners.finishBroadcast(); 2132 } 2133 } 2134 2135 @Override onPackageStateChanged(String packageName, int uid)2136 public void onPackageStateChanged(String packageName, int uid) { 2137 onPackageChanged(packageName); 2138 super.onPackageStateChanged(packageName, uid); 2139 } 2140 } 2141 2142 class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> { 2143 @Override onCallbackDied(T callback, Object cookie)2144 public void onCallbackDied(T callback, Object cookie) { 2145 checkCallbackCount(); 2146 } 2147 } 2148 2149 class PackageLoadingProgressCallback extends 2150 PackageManagerInternal.InstalledLoadingProgressCallback { 2151 private String mPackageName; 2152 private UserHandle mUser; 2153 PackageLoadingProgressCallback(String packageName, UserHandle user)2154 PackageLoadingProgressCallback(String packageName, UserHandle user) { 2155 super(mCallbackHandler); 2156 mPackageName = packageName; 2157 mUser = user; 2158 } 2159 2160 @Override onLoadingProgressChanged(float progress)2161 public void onLoadingProgressChanged(float progress) { 2162 final int n = mListeners.beginBroadcast(); 2163 try { 2164 for (int i = 0; i < n; i++) { 2165 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 2166 BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); 2167 if (!isEnabledProfileOf(cookie.user, mUser, "onLoadingProgressChanged")) { 2168 continue; 2169 } 2170 if (!isPackageVisibleToListener(mPackageName, cookie, mUser)) { 2171 continue; 2172 } 2173 try { 2174 listener.onPackageLoadingProgressChanged(mUser, mPackageName, progress); 2175 } catch (RemoteException re) { 2176 Slog.d(TAG, "Callback failed ", re); 2177 } 2178 } 2179 } finally { 2180 mListeners.finishBroadcast(); 2181 } 2182 } 2183 } 2184 2185 final class LocalService extends LauncherAppsServiceInternal { 2186 @Override startShortcut(int callerUid, int callerPid, String callingPackage, String packageName, String featureId, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int targetUserId)2187 public boolean startShortcut(int callerUid, int callerPid, String callingPackage, 2188 String packageName, String featureId, String shortcutId, Rect sourceBounds, 2189 Bundle startActivityOptions, int targetUserId) { 2190 return LauncherAppsImpl.this.startShortcutInner(callerUid, callerPid, 2191 UserHandle.getUserId(callerUid), callingPackage, packageName, featureId, 2192 shortcutId, sourceBounds, startActivityOptions, targetUserId); 2193 } 2194 } 2195 } 2196 } 2197