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