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