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