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