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