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