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