LauncherAppsService.java revision 53fa4ec7f466e70fe3e33d15c4abfc9bb557eb10
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.app.AppGlobals;
20import android.content.BroadcastReceiver;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.pm.ActivityInfo;
26import android.content.pm.ILauncherApps;
27import android.content.pm.IOnAppsChangedListener;
28import android.content.pm.IPackageManager;
29import android.content.pm.PackageManager;
30import android.content.pm.PackageInfo;
31import android.content.pm.ResolveInfo;
32import android.content.pm.UserInfo;
33import android.graphics.Rect;
34import android.os.Binder;
35import android.os.Bundle;
36import android.os.IInterface;
37import android.os.RemoteCallbackList;
38import android.os.RemoteException;
39import android.os.UserHandle;
40import android.os.UserManager;
41import android.util.Slog;
42
43import com.android.internal.content.PackageMonitor;
44
45import java.util.ArrayList;
46import java.util.List;
47
48/**
49 * Service that manages requests and callbacks for launchers that support
50 * managed profiles.
51 */
52public class LauncherAppsService extends ILauncherApps.Stub {
53
54    private static final String TAG = "LauncherAppsService";
55    private final Context mContext;
56    private final PackageManager mPm;
57    private final UserManager mUm;
58    private final PackageCallbackList<IOnAppsChangedListener> mListeners
59            = new PackageCallbackList<IOnAppsChangedListener>();
60
61    private MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
62
63    public LauncherAppsService(Context context) {
64        mContext = context;
65        mPm = mContext.getPackageManager();
66        mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
67    }
68
69    /*
70     * @see android.content.pm.ILauncherApps#addOnAppsChangedListener(
71     *          android.content.pm.IOnAppsChangedListener)
72     */
73    @Override
74    public void addOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException {
75        synchronized (mListeners) {
76            if (mListeners.getRegisteredCallbackCount() == 0) {
77                startWatchingPackageBroadcasts();
78            }
79            mListeners.unregister(listener);
80            mListeners.register(listener);
81        }
82    }
83
84    /*
85     * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener(
86     *          android.content.pm.IOnAppsChangedListener)
87     */
88    @Override
89    public void removeOnAppsChangedListener(IOnAppsChangedListener listener)
90            throws RemoteException {
91        synchronized (mListeners) {
92            mListeners.unregister(listener);
93            if (mListeners.getRegisteredCallbackCount() == 0) {
94                stopWatchingPackageBroadcasts();
95            }
96        }
97    }
98
99    /**
100     * Register a receiver to watch for package broadcasts
101     */
102    private void startWatchingPackageBroadcasts() {
103        mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
104    }
105
106    /**
107     * Unregister package broadcast receiver
108     */
109    private void stopWatchingPackageBroadcasts() {
110        mPackageMonitor.unregister();
111    }
112
113    void checkCallbackCount() {
114        synchronized (LauncherAppsService.this) {
115            if (mListeners.getRegisteredCallbackCount() == 0) {
116                stopWatchingPackageBroadcasts();
117            }
118        }
119    }
120
121    /**
122     * Checks if the caller is in the same group as the userToCheck.
123     */
124    private void ensureInUserProfiles(UserHandle userToCheck, String message) {
125        final int callingUserId = UserHandle.getCallingUserId();
126        final int targetUserId = userToCheck.getIdentifier();
127
128        if (targetUserId == callingUserId) return;
129
130        long ident = Binder.clearCallingIdentity();
131        try {
132            UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
133            UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
134            if (targetUserInfo == null
135                    || targetUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
136                    || targetUserInfo.profileGroupId != callingUserInfo.profileGroupId) {
137                throw new SecurityException(message);
138            }
139        } finally {
140            Binder.restoreCallingIdentity(ident);
141        }
142    }
143
144    @Override
145    public List<ResolveInfo> getLauncherActivities(String packageName, UserHandle user)
146            throws RemoteException {
147        ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);
148
149        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
150        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
151        mainIntent.setPackage(packageName);
152        long ident = Binder.clearCallingIdentity();
153        try {
154            List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent, 0,
155                    user.getIdentifier());
156            return apps;
157        } finally {
158            Binder.restoreCallingIdentity(ident);
159        }
160    }
161
162    @Override
163    public ResolveInfo resolveActivity(Intent intent, UserHandle user)
164            throws RemoteException {
165        ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user);
166
167        long ident = Binder.clearCallingIdentity();
168        try {
169            ResolveInfo app = mPm.resolveActivityAsUser(intent, 0, user.getIdentifier());
170            return app;
171        } finally {
172            Binder.restoreCallingIdentity(ident);
173        }
174    }
175
176    @Override
177    public boolean isPackageEnabled(String packageName, UserHandle user)
178            throws RemoteException {
179        ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
180        long ident = Binder.clearCallingIdentity();
181        try {
182            IPackageManager pm = AppGlobals.getPackageManager();
183            PackageInfo info = pm.getPackageInfo(packageName, 0, user.getIdentifier());
184            return info != null && info.applicationInfo.enabled;
185        } finally {
186            Binder.restoreCallingIdentity(ident);
187        }
188    }
189
190    @Override
191    public boolean isActivityEnabled(ComponentName component, UserHandle user)
192            throws RemoteException {
193        ensureInUserProfiles(user, "Cannot check component for unrelated profile " + user);
194        long ident = Binder.clearCallingIdentity();
195        try {
196            IPackageManager pm = AppGlobals.getPackageManager();
197            ActivityInfo info = pm.getActivityInfo(component, 0, user.getIdentifier());
198            return info != null && info.isEnabled();
199        } finally {
200            Binder.restoreCallingIdentity(ident);
201        }
202    }
203
204    @Override
205    public void startActivityAsUser(ComponentName component, Rect sourceBounds,
206            Bundle opts, UserHandle user) throws RemoteException {
207        ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
208
209        Intent launchIntent = new Intent(Intent.ACTION_MAIN);
210        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
211        launchIntent.setComponent(component);
212        launchIntent.setSourceBounds(sourceBounds);
213        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
214
215        final int callingUserId = UserHandle.getCallingUserId();
216        long ident = Binder.clearCallingIdentity();
217        try {
218            mContext.startActivityAsUser(launchIntent, opts, user);
219        } finally {
220            Binder.restoreCallingIdentity(ident);
221        }
222    }
223
224    private class MyPackageMonitor extends PackageMonitor {
225
226        @Override
227        public void onPackageAdded(String packageName, int uid) {
228            UserHandle user = new UserHandle(getChangingUserId());
229            // TODO: if (!isProfile(user)) return;
230            final int n = mListeners.beginBroadcast();
231            for (int i = 0; i < n; i++) {
232                IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
233                try {
234                    listener.onPackageAdded(user, packageName);
235                } catch (RemoteException re) {
236                    Slog.d(TAG, "Callback failed ", re);
237                }
238            }
239            mListeners.finishBroadcast();
240
241            super.onPackageAdded(packageName, uid);
242        }
243
244        @Override
245        public void onPackageRemoved(String packageName, int uid) {
246            UserHandle user = new UserHandle(getChangingUserId());
247            // TODO: if (!isCurrentProfile(user)) return;
248            final int n = mListeners.beginBroadcast();
249            for (int i = 0; i < n; i++) {
250                IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
251                try {
252                    listener.onPackageRemoved(user, packageName);
253                } catch (RemoteException re) {
254                    Slog.d(TAG, "Callback failed ", re);
255                }
256            }
257            mListeners.finishBroadcast();
258
259            super.onPackageRemoved(packageName, uid);
260        }
261
262        @Override
263        public void onPackageModified(String packageName) {
264            UserHandle user = new UserHandle(getChangingUserId());
265            // TODO: if (!isProfile(user)) return;
266            final int n = mListeners.beginBroadcast();
267            for (int i = 0; i < n; i++) {
268                IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
269                try {
270                    listener.onPackageChanged(user, packageName);
271                } catch (RemoteException re) {
272                    Slog.d(TAG, "Callback failed ", re);
273                }
274            }
275            mListeners.finishBroadcast();
276
277            super.onPackageModified(packageName);
278        }
279
280        @Override
281        public void onPackagesAvailable(String[] packages) {
282            UserHandle user = new UserHandle(getChangingUserId());
283            // TODO: if (!isProfile(user)) return;
284            final int n = mListeners.beginBroadcast();
285            for (int i = 0; i < n; i++) {
286                IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
287                try {
288                    listener.onPackagesAvailable(user, packages, isReplacing());
289                } catch (RemoteException re) {
290                    Slog.d(TAG, "Callback failed ", re);
291                }
292            }
293            mListeners.finishBroadcast();
294
295            super.onPackagesAvailable(packages);
296        }
297
298        @Override
299        public void onPackagesUnavailable(String[] packages) {
300            UserHandle user = new UserHandle(getChangingUserId());
301            // TODO: if (!isProfile(user)) return;
302            final int n = mListeners.beginBroadcast();
303            for (int i = 0; i < n; i++) {
304                IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
305                try {
306                    listener.onPackagesUnavailable(user, packages, isReplacing());
307                } catch (RemoteException re) {
308                    Slog.d(TAG, "Callback failed ", re);
309                }
310            }
311            mListeners.finishBroadcast();
312
313            super.onPackagesUnavailable(packages);
314        }
315
316    }
317
318    class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> {
319
320        @Override
321        public void onCallbackDied(T callback, Object cookie) {
322            checkCallbackCount();
323        }
324    }
325}
326