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
17package com.android.server.pm;
18
19import android.annotation.NonNull;
20import android.annotation.UserIdInt;
21import android.app.ActivityManager;
22import android.app.ActivityManagerInternal;
23import android.app.AppGlobals;
24import android.app.IApplicationThread;
25import android.app.PendingIntent;
26import android.content.ComponentName;
27import android.content.Context;
28import android.content.Intent;
29import android.content.IntentSender;
30import android.content.pm.ActivityInfo;
31import android.content.pm.ApplicationInfo;
32import android.content.pm.ILauncherApps;
33import android.content.pm.IOnAppsChangedListener;
34import android.content.pm.LauncherApps.ShortcutQuery;
35import android.content.pm.PackageInfo;
36import android.content.pm.PackageManager;
37import android.content.pm.PackageManagerInternal;
38import android.content.pm.ParceledListSlice;
39import android.content.pm.ResolveInfo;
40import android.content.pm.ShortcutInfo;
41import android.content.pm.ShortcutServiceInternal;
42import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
43import android.content.pm.UserInfo;
44import android.graphics.Rect;
45import android.net.Uri;
46import android.os.Binder;
47import android.os.Bundle;
48import android.os.Handler;
49import android.os.IInterface;
50import android.os.ParcelFileDescriptor;
51import android.os.RemoteCallbackList;
52import android.os.RemoteException;
53import android.os.UserHandle;
54import android.os.UserManager;
55import android.os.UserManagerInternal;
56import android.provider.Settings;
57import android.util.Log;
58import android.util.Slog;
59
60import com.android.internal.annotations.VisibleForTesting;
61import com.android.internal.content.PackageMonitor;
62import com.android.internal.os.BackgroundThread;
63import com.android.internal.util.Preconditions;
64import com.android.server.LocalServices;
65import com.android.server.SystemService;
66
67import java.util.Collections;
68import java.util.List;
69
70/**
71 * Service that manages requests and callbacks for launchers that support
72 * managed profiles.
73 */
74public class LauncherAppsService extends SystemService {
75
76    private final LauncherAppsImpl mLauncherAppsImpl;
77
78    public LauncherAppsService(Context context) {
79        super(context);
80        mLauncherAppsImpl = new LauncherAppsImpl(context);
81    }
82
83    @Override
84    public void onStart() {
85        publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl);
86    }
87
88    static class BroadcastCookie {
89        public final UserHandle user;
90        public final String packageName;
91        public final int callingUid;
92        public final int callingPid;
93
94        BroadcastCookie(UserHandle userHandle, String packageName, int callingPid, int callingUid) {
95            this.user = userHandle;
96            this.packageName = packageName;
97            this.callingUid = callingUid;
98            this.callingPid = callingPid;
99        }
100    }
101
102    @VisibleForTesting
103    static class LauncherAppsImpl extends ILauncherApps.Stub {
104        private static final boolean DEBUG = false;
105        private static final String TAG = "LauncherAppsService";
106        private final Context mContext;
107        private final UserManager mUm;
108        private final UserManagerInternal mUserManagerInternal;
109        private final ActivityManagerInternal mActivityManagerInternal;
110        private final ShortcutServiceInternal mShortcutServiceInternal;
111        private final PackageCallbackList<IOnAppsChangedListener> mListeners
112                = new PackageCallbackList<IOnAppsChangedListener>();
113
114        private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
115
116        private final Handler mCallbackHandler;
117
118        public LauncherAppsImpl(Context context) {
119            mContext = context;
120            mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
121            mUserManagerInternal = Preconditions.checkNotNull(
122                    LocalServices.getService(UserManagerInternal.class));
123            mActivityManagerInternal = Preconditions.checkNotNull(
124                    LocalServices.getService(ActivityManagerInternal.class));
125            mShortcutServiceInternal = Preconditions.checkNotNull(
126                    LocalServices.getService(ShortcutServiceInternal.class));
127            mShortcutServiceInternal.addListener(mPackageMonitor);
128            mCallbackHandler = BackgroundThread.getHandler();
129        }
130
131        @VisibleForTesting
132        int injectBinderCallingUid() {
133            return getCallingUid();
134        }
135
136        @VisibleForTesting
137        int injectBinderCallingPid() {
138            return getCallingPid();
139        }
140
141        final int injectCallingUserId() {
142            return UserHandle.getUserId(injectBinderCallingUid());
143        }
144
145        @VisibleForTesting
146        long injectClearCallingIdentity() {
147            return Binder.clearCallingIdentity();
148        }
149
150        // Injection point.
151        @VisibleForTesting
152        void injectRestoreCallingIdentity(long token) {
153            Binder.restoreCallingIdentity(token);
154        }
155
156        private int getCallingUserId() {
157            return UserHandle.getUserId(injectBinderCallingUid());
158        }
159
160        /*
161         * @see android.content.pm.ILauncherApps#addOnAppsChangedListener(
162         *          android.content.pm.IOnAppsChangedListener)
163         */
164        @Override
165        public void addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener)
166                throws RemoteException {
167            verifyCallingPackage(callingPackage);
168            synchronized (mListeners) {
169                if (DEBUG) {
170                    Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle());
171                }
172                if (mListeners.getRegisteredCallbackCount() == 0) {
173                    if (DEBUG) {
174                        Log.d(TAG, "Starting package monitoring");
175                    }
176                    startWatchingPackageBroadcasts();
177                }
178                mListeners.unregister(listener);
179                mListeners.register(listener, new BroadcastCookie(UserHandle.of(getCallingUserId()),
180                        callingPackage, injectBinderCallingPid(), injectBinderCallingUid()));
181            }
182        }
183
184        /*
185         * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener(
186         *          android.content.pm.IOnAppsChangedListener)
187         */
188        @Override
189        public void removeOnAppsChangedListener(IOnAppsChangedListener listener)
190                throws RemoteException {
191            synchronized (mListeners) {
192                if (DEBUG) {
193                    Log.d(TAG, "Removing listener from " + Binder.getCallingUserHandle());
194                }
195                mListeners.unregister(listener);
196                if (mListeners.getRegisteredCallbackCount() == 0) {
197                    stopWatchingPackageBroadcasts();
198                }
199            }
200        }
201
202        /**
203         * Register a receiver to watch for package broadcasts
204         */
205        private void startWatchingPackageBroadcasts() {
206            mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
207        }
208
209        /**
210         * Unregister package broadcast receiver
211         */
212        private void stopWatchingPackageBroadcasts() {
213            if (DEBUG) {
214                Log.d(TAG, "Stopped watching for packages");
215            }
216            mPackageMonitor.unregister();
217        }
218
219        void checkCallbackCount() {
220            synchronized (mListeners) {
221                if (DEBUG) {
222                    Log.d(TAG, "Callback count = " + mListeners.getRegisteredCallbackCount());
223                }
224                if (mListeners.getRegisteredCallbackCount() == 0) {
225                    stopWatchingPackageBroadcasts();
226                }
227            }
228        }
229
230        /**
231         * Checks if the calling user is in the same group as {@code targetUser}, and allowed
232         * to access it.
233         *
234         * @return TRUE if the calling user can access {@code targetUserId}.  FALSE if not *but
235         * they're still in the same profile group*.
236         *
237         * @throws SecurityException if the calling user and {@code targetUser} are not in the same
238         * group.
239         */
240        private boolean canAccessProfile(int targetUserId, String message) {
241            final int callingUserId = injectCallingUserId();
242
243            if (targetUserId == callingUserId) return true;
244
245            long ident = injectClearCallingIdentity();
246            try {
247                final UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
248                if (callingUserInfo != null && callingUserInfo.isManagedProfile()) {
249                    Slog.w(TAG, message + " for another profile "
250                            + targetUserId + " from " + callingUserId + " not allowed");
251                    return false;
252                }
253            } finally {
254                injectRestoreCallingIdentity(ident);
255            }
256
257            return mUserManagerInternal.isProfileAccessible(injectCallingUserId(), targetUserId,
258                    message, true);
259        }
260
261        @VisibleForTesting // We override it in unit tests
262        void verifyCallingPackage(String callingPackage) {
263            int packageUid = -1;
264            try {
265                packageUid = AppGlobals.getPackageManager().getPackageUid(callingPackage,
266                        PackageManager.MATCH_DIRECT_BOOT_AWARE
267                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
268                                | PackageManager.MATCH_UNINSTALLED_PACKAGES,
269                        UserHandle.getUserId(getCallingUid()));
270            } catch (RemoteException ignore) {
271            }
272            if (packageUid < 0) {
273                Log.e(TAG, "Package not found: " + callingPackage);
274            }
275            if (packageUid != injectBinderCallingUid()) {
276                throw new SecurityException("Calling package name mismatch");
277            }
278        }
279
280        @Override
281        public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
282                String packageName, UserHandle user)
283                throws RemoteException {
284            return queryActivitiesForUser(callingPackage,
285                    new Intent(Intent.ACTION_MAIN)
286                            .addCategory(Intent.CATEGORY_LAUNCHER)
287                            .setPackage(packageName),
288                    user);
289        }
290
291        @Override
292        public ActivityInfo resolveActivity(
293                String callingPackage, ComponentName component, UserHandle user)
294                throws RemoteException {
295            if (!canAccessProfile(user.getIdentifier(), "Cannot resolve activity")) {
296                return null;
297            }
298
299            final int callingUid = injectBinderCallingUid();
300            long ident = Binder.clearCallingIdentity();
301            try {
302                final PackageManagerInternal pmInt =
303                        LocalServices.getService(PackageManagerInternal.class);
304                return pmInt.getActivityInfo(component,
305                        PackageManager.MATCH_DIRECT_BOOT_AWARE
306                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
307                        callingUid, user.getIdentifier());
308            } finally {
309                Binder.restoreCallingIdentity(ident);
310            }
311        }
312
313        @Override
314        public ParceledListSlice getShortcutConfigActivities(
315                String callingPackage, String packageName, UserHandle user)
316                throws RemoteException {
317            return queryActivitiesForUser(callingPackage,
318                    new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user);
319        }
320
321        private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage,
322                Intent intent, UserHandle user) {
323            if (!canAccessProfile(user.getIdentifier(), "Cannot retrieve activities")) {
324                return null;
325            }
326
327            final int callingUid = injectBinderCallingUid();
328            long ident = injectClearCallingIdentity();
329            try {
330                final PackageManagerInternal pmInt =
331                        LocalServices.getService(PackageManagerInternal.class);
332                List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
333                        PackageManager.MATCH_DIRECT_BOOT_AWARE
334                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
335                        callingUid, user.getIdentifier());
336                return new ParceledListSlice<>(apps);
337            } finally {
338                injectRestoreCallingIdentity(ident);
339            }
340        }
341
342        @Override
343        public IntentSender getShortcutConfigActivityIntent(String callingPackage,
344                ComponentName component, UserHandle user) throws RemoteException {
345            ensureShortcutPermission(callingPackage);
346            if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) {
347                return null;
348            }
349            Preconditions.checkNotNull(component);
350
351            // All right, create the sender.
352            Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component);
353            final long identity = Binder.clearCallingIdentity();
354            try {
355                final PendingIntent pi = PendingIntent.getActivityAsUser(
356                        mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
357                                | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
358                        null, user);
359                return pi == null ? null : pi.getIntentSender();
360            } finally {
361                Binder.restoreCallingIdentity(identity);
362            }
363        }
364
365        @Override
366        public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user)
367                throws RemoteException {
368            if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) {
369                return false;
370            }
371
372            final int callingUid = injectBinderCallingUid();
373            long ident = Binder.clearCallingIdentity();
374            try {
375                final PackageManagerInternal pmInt =
376                        LocalServices.getService(PackageManagerInternal.class);
377                PackageInfo info = pmInt.getPackageInfo(packageName,
378                        PackageManager.MATCH_DIRECT_BOOT_AWARE
379                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
380                        callingUid, user.getIdentifier());
381                return info != null && info.applicationInfo.enabled;
382            } finally {
383                Binder.restoreCallingIdentity(ident);
384            }
385        }
386
387        @Override
388        public Bundle getSuspendedPackageLauncherExtras(String packageName,
389                UserHandle user) {
390            if (!canAccessProfile(user.getIdentifier(), "Cannot get launcher extras")) {
391                return null;
392            }
393            final PackageManagerInternal pmi =
394                    LocalServices.getService(PackageManagerInternal.class);
395            return pmi.getSuspendedPackageLauncherExtras(packageName, user.getIdentifier());
396        }
397
398        @Override
399        public ApplicationInfo getApplicationInfo(
400                String callingPackage, String packageName, int flags, UserHandle user)
401                throws RemoteException {
402            if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) {
403                return null;
404            }
405
406            final int callingUid = injectBinderCallingUid();
407            long ident = Binder.clearCallingIdentity();
408            try {
409                final PackageManagerInternal pmInt =
410                        LocalServices.getService(PackageManagerInternal.class);
411                ApplicationInfo info = pmInt.getApplicationInfo(packageName, flags,
412                        callingUid, user.getIdentifier());
413                return info;
414            } finally {
415                Binder.restoreCallingIdentity(ident);
416            }
417        }
418
419        private void ensureShortcutPermission(@NonNull String callingPackage) {
420            verifyCallingPackage(callingPackage);
421            if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
422                    callingPackage, injectBinderCallingPid(), injectBinderCallingUid())) {
423                throw new SecurityException("Caller can't access shortcut information");
424            }
425        }
426
427        @Override
428        public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
429                String packageName, List shortcutIds, ComponentName componentName, int flags,
430                UserHandle targetUser) {
431            ensureShortcutPermission(callingPackage);
432            if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) {
433                return new ParceledListSlice<>(Collections.EMPTY_LIST);
434            }
435            if (shortcutIds != null && packageName == null) {
436                throw new IllegalArgumentException(
437                        "To query by shortcut ID, package name must also be set");
438            }
439
440            // TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below.
441            return new ParceledListSlice<>((List<ShortcutInfo>)
442                    mShortcutServiceInternal.getShortcuts(getCallingUserId(),
443                            callingPackage, changedSince, packageName, shortcutIds,
444                            componentName, flags, targetUser.getIdentifier(),
445                            injectBinderCallingPid(), injectBinderCallingUid()));
446        }
447
448        @Override
449        public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
450                UserHandle targetUser) {
451            ensureShortcutPermission(callingPackage);
452            if (!canAccessProfile(targetUser.getIdentifier(), "Cannot pin shortcuts")) {
453                return;
454            }
455
456            mShortcutServiceInternal.pinShortcuts(getCallingUserId(),
457                    callingPackage, packageName, ids, targetUser.getIdentifier());
458        }
459
460        @Override
461        public int getShortcutIconResId(String callingPackage, String packageName, String id,
462                int targetUserId) {
463            ensureShortcutPermission(callingPackage);
464            if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) {
465                return 0;
466            }
467
468            return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(),
469                    callingPackage, packageName, id, targetUserId);
470        }
471
472        @Override
473        public ParcelFileDescriptor getShortcutIconFd(String callingPackage,
474                String packageName, String id, int targetUserId) {
475            ensureShortcutPermission(callingPackage);
476            if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) {
477                return null;
478            }
479
480            return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(),
481                    callingPackage, packageName, id, targetUserId);
482        }
483
484        @Override
485        public boolean hasShortcutHostPermission(String callingPackage) {
486            verifyCallingPackage(callingPackage);
487            return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
488                    callingPackage, injectBinderCallingPid(), injectBinderCallingUid());
489        }
490
491        @Override
492        public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
493                Rect sourceBounds, Bundle startActivityOptions, int targetUserId) {
494            verifyCallingPackage(callingPackage);
495            if (!canAccessProfile(targetUserId, "Cannot start activity")) {
496                return false;
497            }
498
499            // Even without the permission, pinned shortcuts are always launchable.
500            if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(),
501                    callingPackage, packageName, shortcutId, targetUserId)) {
502                ensureShortcutPermission(callingPackage);
503            }
504
505            final Intent[] intents = mShortcutServiceInternal.createShortcutIntents(
506                    getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId,
507                    injectBinderCallingPid(), injectBinderCallingUid());
508            if (intents == null || intents.length == 0) {
509                return false;
510            }
511            // Note the target activity doesn't have to be exported.
512
513            intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
514            intents[0].setSourceBounds(sourceBounds);
515
516            return startShortcutIntentsAsPublisher(
517                    intents, packageName, startActivityOptions, targetUserId);
518        }
519
520        private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents,
521                @NonNull String publisherPackage, Bundle startActivityOptions, int userId) {
522            final int code;
523            try {
524                code = mActivityManagerInternal.startActivitiesAsPackage(publisherPackage,
525                        userId, intents, startActivityOptions);
526                if (ActivityManager.isStartResultSuccessful(code)) {
527                    return true; // Success
528                } else {
529                    Log.e(TAG, "Couldn't start activity, code=" + code);
530                }
531                return false;
532            } catch (SecurityException e) {
533                if (DEBUG) {
534                    Slog.d(TAG, "SecurityException while launching intent", e);
535                }
536                return false;
537            }
538        }
539
540        @Override
541        public boolean isActivityEnabled(
542                String callingPackage, ComponentName component, UserHandle user)
543                throws RemoteException {
544            if (!canAccessProfile(user.getIdentifier(), "Cannot check component")) {
545                return false;
546            }
547
548            final int callingUid = injectBinderCallingUid();
549            long ident = Binder.clearCallingIdentity();
550            try {
551                final PackageManagerInternal pmInt =
552                        LocalServices.getService(PackageManagerInternal.class);
553                ActivityInfo info = pmInt.getActivityInfo(component,
554                        PackageManager.MATCH_DIRECT_BOOT_AWARE
555                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
556                        callingUid, user.getIdentifier());
557                return info != null;
558            } finally {
559                Binder.restoreCallingIdentity(ident);
560            }
561        }
562
563        @Override
564        public void startActivityAsUser(IApplicationThread caller, String callingPackage,
565                ComponentName component, Rect sourceBounds,
566                Bundle opts, UserHandle user) throws RemoteException {
567            if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
568                return;
569            }
570
571            Intent launchIntent = new Intent(Intent.ACTION_MAIN);
572            launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
573            launchIntent.setSourceBounds(sourceBounds);
574            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
575                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
576            launchIntent.setPackage(component.getPackageName());
577
578            boolean canLaunch = false;
579
580            final int callingUid = injectBinderCallingUid();
581            long ident = Binder.clearCallingIdentity();
582            try {
583                final PackageManagerInternal pmInt =
584                        LocalServices.getService(PackageManagerInternal.class);
585                ActivityInfo info = pmInt.getActivityInfo(component,
586                        PackageManager.MATCH_DIRECT_BOOT_AWARE
587                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
588                        callingUid, user.getIdentifier());
589                if (!info.exported) {
590                    throw new SecurityException("Cannot launch non-exported components "
591                            + component);
592                }
593
594                // Check that the component actually has Intent.CATEGORY_LAUCNCHER
595                // as calling startActivityAsUser ignores the category and just
596                // resolves based on the component if present.
597                List<ResolveInfo> apps = pmInt.queryIntentActivities(launchIntent,
598                        PackageManager.MATCH_DIRECT_BOOT_AWARE
599                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
600                        callingUid, user.getIdentifier());
601                final int size = apps.size();
602                for (int i = 0; i < size; ++i) {
603                    ActivityInfo activityInfo = apps.get(i).activityInfo;
604                    if (activityInfo.packageName.equals(component.getPackageName()) &&
605                            activityInfo.name.equals(component.getClassName())) {
606                        // Found an activity with category launcher that matches
607                        // this component so ok to launch.
608                        launchIntent.setPackage(null);
609                        launchIntent.setComponent(component);
610                        canLaunch = true;
611                        break;
612                    }
613                }
614                if (!canLaunch) {
615                    throw new SecurityException("Attempt to launch activity without "
616                            + " category Intent.CATEGORY_LAUNCHER " + component);
617                }
618            } finally {
619                Binder.restoreCallingIdentity(ident);
620            }
621            mActivityManagerInternal.startActivityAsUser(caller, callingPackage,
622                    launchIntent, opts, user.getIdentifier());
623        }
624
625        @Override
626        public void showAppDetailsAsUser(IApplicationThread caller,
627                String callingPackage, ComponentName component,
628                Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException {
629            if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) {
630                return;
631            }
632
633            final Intent intent;
634            long ident = Binder.clearCallingIdentity();
635            try {
636                String packageName = component.getPackageName();
637                intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
638                        Uri.fromParts("package", packageName, null));
639                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
640                intent.setSourceBounds(sourceBounds);
641            } finally {
642                Binder.restoreCallingIdentity(ident);
643            }
644            mActivityManagerInternal.startActivityAsUser(caller, callingPackage,
645                    intent, opts, user.getIdentifier());
646        }
647
648        /** Checks if user is a profile of or same as listeningUser.
649         * and the user is enabled. */
650        private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user,
651                String debugMsg) {
652            return mUserManagerInternal.isProfileAccessible(listeningUser.getIdentifier(),
653                    user.getIdentifier(), debugMsg, false);
654        }
655
656        @VisibleForTesting
657        void postToPackageMonitorHandler(Runnable r) {
658            mCallbackHandler.post(r);
659        }
660
661        private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
662
663            // TODO Simplify with lambdas.
664
665            @Override
666            public void onPackageAdded(String packageName, int uid) {
667                UserHandle user = new UserHandle(getChangingUserId());
668                final int n = mListeners.beginBroadcast();
669                try {
670                    for (int i = 0; i < n; i++) {
671                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
672                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
673                        if (!isEnabledProfileOf(cookie.user, user, "onPackageAdded")) continue;
674                        try {
675                            listener.onPackageAdded(user, packageName);
676                        } catch (RemoteException re) {
677                            Slog.d(TAG, "Callback failed ", re);
678                        }
679                    }
680                } finally {
681                    mListeners.finishBroadcast();
682                }
683
684                super.onPackageAdded(packageName, uid);
685            }
686
687            @Override
688            public void onPackageRemoved(String packageName, int uid) {
689                UserHandle user = new UserHandle(getChangingUserId());
690                final int n = mListeners.beginBroadcast();
691                try {
692                    for (int i = 0; i < n; i++) {
693                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
694                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
695                        if (!isEnabledProfileOf(cookie.user, user, "onPackageRemoved")) continue;
696                        try {
697                            listener.onPackageRemoved(user, packageName);
698                        } catch (RemoteException re) {
699                            Slog.d(TAG, "Callback failed ", re);
700                        }
701                    }
702                } finally {
703                    mListeners.finishBroadcast();
704                }
705
706                super.onPackageRemoved(packageName, uid);
707            }
708
709            @Override
710            public void onPackageModified(String packageName) {
711                UserHandle user = new UserHandle(getChangingUserId());
712                final int n = mListeners.beginBroadcast();
713                try {
714                    for (int i = 0; i < n; i++) {
715                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
716                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
717                        if (!isEnabledProfileOf(cookie.user, user, "onPackageModified")) continue;
718                        try {
719                            listener.onPackageChanged(user, packageName);
720                        } catch (RemoteException re) {
721                            Slog.d(TAG, "Callback failed ", re);
722                        }
723                    }
724                } finally {
725                    mListeners.finishBroadcast();
726                }
727
728                super.onPackageModified(packageName);
729            }
730
731            @Override
732            public void onPackagesAvailable(String[] packages) {
733                UserHandle user = new UserHandle(getChangingUserId());
734                final int n = mListeners.beginBroadcast();
735                try {
736                    for (int i = 0; i < n; i++) {
737                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
738                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
739                        if (!isEnabledProfileOf(cookie.user, user, "onPackagesAvailable")) continue;
740                        try {
741                            listener.onPackagesAvailable(user, packages, isReplacing());
742                        } catch (RemoteException re) {
743                            Slog.d(TAG, "Callback failed ", re);
744                        }
745                    }
746                } finally {
747                    mListeners.finishBroadcast();
748                }
749
750                super.onPackagesAvailable(packages);
751            }
752
753            @Override
754            public void onPackagesUnavailable(String[] packages) {
755                UserHandle user = new UserHandle(getChangingUserId());
756                final int n = mListeners.beginBroadcast();
757                try {
758                    for (int i = 0; i < n; i++) {
759                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
760                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
761                        if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnavailable")) continue;
762                        try {
763                            listener.onPackagesUnavailable(user, packages, isReplacing());
764                        } catch (RemoteException re) {
765                            Slog.d(TAG, "Callback failed ", re);
766                        }
767                    }
768                } finally {
769                    mListeners.finishBroadcast();
770                }
771
772                super.onPackagesUnavailable(packages);
773            }
774
775            @Override
776            public void onPackagesSuspended(String[] packages, Bundle launcherExtras) {
777                UserHandle user = new UserHandle(getChangingUserId());
778                final int n = mListeners.beginBroadcast();
779                try {
780                    for (int i = 0; i < n; i++) {
781                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
782                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
783                        if (!isEnabledProfileOf(cookie.user, user, "onPackagesSuspended")) continue;
784                        try {
785                            listener.onPackagesSuspended(user, packages, launcherExtras);
786                        } catch (RemoteException re) {
787                            Slog.d(TAG, "Callback failed ", re);
788                        }
789                    }
790                } finally {
791                    mListeners.finishBroadcast();
792                }
793
794                super.onPackagesSuspended(packages, launcherExtras);
795            }
796
797            @Override
798            public void onPackagesUnsuspended(String[] packages) {
799                UserHandle user = new UserHandle(getChangingUserId());
800                final int n = mListeners.beginBroadcast();
801                try {
802                    for (int i = 0; i < n; i++) {
803                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
804                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
805                        if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnsuspended")) continue;
806                        try {
807                            listener.onPackagesUnsuspended(user, packages);
808                        } catch (RemoteException re) {
809                            Slog.d(TAG, "Callback failed ", re);
810                        }
811                    }
812                } finally {
813                    mListeners.finishBroadcast();
814                }
815
816                super.onPackagesUnsuspended(packages);
817            }
818
819            @Override
820            public void onShortcutChanged(@NonNull String packageName,
821                    @UserIdInt int userId) {
822                postToPackageMonitorHandler(() -> onShortcutChangedInner(packageName, userId));
823            }
824
825            private void onShortcutChangedInner(@NonNull String packageName,
826                    @UserIdInt int userId) {
827                final int n = mListeners.beginBroadcast();
828                try {
829                    final UserHandle user = UserHandle.of(userId);
830
831                    for (int i = 0; i < n; i++) {
832                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
833                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
834                        if (!isEnabledProfileOf(cookie.user, user, "onShortcutChanged")) continue;
835
836                        final int launcherUserId = cookie.user.getIdentifier();
837
838                        // Make sure the caller has the permission.
839                        if (!mShortcutServiceInternal.hasShortcutHostPermission(
840                                launcherUserId, cookie.packageName,
841                                cookie.callingPid, cookie.callingUid)) {
842                            continue;
843                        }
844                        // Each launcher has a different set of pinned shortcuts, so we need to do a
845                        // query in here.
846                        // (As of now, only one launcher has the permission at a time, so it's bit
847                        // moot, but we may change the permission model eventually.)
848                        final List<ShortcutInfo> list =
849                                mShortcutServiceInternal.getShortcuts(launcherUserId,
850                                        cookie.packageName,
851                                        /* changedSince= */ 0, packageName, /* shortcutIds=*/ null,
852                                        /* component= */ null,
853                                        ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
854                                        | ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED
855                                        , userId, cookie.callingPid, cookie.callingUid);
856                        try {
857                            listener.onShortcutChanged(user, packageName,
858                                    new ParceledListSlice<>(list));
859                        } catch (RemoteException re) {
860                            Slog.d(TAG, "Callback failed ", re);
861                        }
862                    }
863                } catch (RuntimeException e) {
864                    // When the user is locked we get IllegalState, so just catch all.
865                    Log.w(TAG, e.getMessage(), e);
866                } finally {
867                    mListeners.finishBroadcast();
868                }
869            }
870        }
871
872        class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> {
873            @Override
874            public void onCallbackDied(T callback, Object cookie) {
875                checkCallbackCount();
876            }
877        }
878    }
879}
880