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