• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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