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