LauncherAppsService.java revision 369aad0e23a1ca1417018c540730915760fe2ed3
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.ApplicationInfo; 25import android.content.pm.ILauncherApps; 26import android.content.pm.IOnAppsChangedListener; 27import android.content.pm.IPackageManager; 28import android.content.pm.PackageInfo; 29import android.content.pm.PackageManager; 30import android.content.pm.ParceledListSlice; 31import android.content.pm.ResolveInfo; 32import android.content.pm.UserInfo; 33import android.graphics.Rect; 34import android.net.Uri; 35import android.os.Binder; 36import android.os.Bundle; 37import android.os.IInterface; 38import android.os.RemoteCallbackList; 39import android.os.RemoteException; 40import android.os.UserHandle; 41import android.os.UserManager; 42import android.provider.Settings; 43import android.util.Log; 44import android.util.Slog; 45 46import com.android.internal.content.PackageMonitor; 47import com.android.server.SystemService; 48 49import java.util.List; 50 51/** 52 * Service that manages requests and callbacks for launchers that support 53 * managed profiles. 54 */ 55 56public class LauncherAppsService extends SystemService { 57 58 private final LauncherAppsImpl mLauncherAppsImpl; 59 60 public LauncherAppsService(Context context) { 61 super(context); 62 mLauncherAppsImpl = new LauncherAppsImpl(context); 63 } 64 65 @Override 66 public void onStart() { 67 publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl); 68 } 69 70 class LauncherAppsImpl extends ILauncherApps.Stub { 71 private static final boolean DEBUG = false; 72 private static final String TAG = "LauncherAppsService"; 73 private final Context mContext; 74 private final PackageManager mPm; 75 private final UserManager mUm; 76 private final PackageCallbackList<IOnAppsChangedListener> mListeners 77 = new PackageCallbackList<IOnAppsChangedListener>(); 78 79 private MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); 80 81 public LauncherAppsImpl(Context context) { 82 mContext = context; 83 mPm = mContext.getPackageManager(); 84 mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 85 } 86 87 /* 88 * @see android.content.pm.ILauncherApps#addOnAppsChangedListener( 89 * android.content.pm.IOnAppsChangedListener) 90 */ 91 @Override 92 public void addOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException { 93 synchronized (mListeners) { 94 if (DEBUG) { 95 Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle()); 96 } 97 if (mListeners.getRegisteredCallbackCount() == 0) { 98 if (DEBUG) { 99 Log.d(TAG, "Starting package monitoring"); 100 } 101 startWatchingPackageBroadcasts(); 102 } 103 mListeners.unregister(listener); 104 mListeners.register(listener, Binder.getCallingUserHandle()); 105 } 106 } 107 108 /* 109 * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener( 110 * android.content.pm.IOnAppsChangedListener) 111 */ 112 @Override 113 public void removeOnAppsChangedListener(IOnAppsChangedListener listener) 114 throws RemoteException { 115 synchronized (mListeners) { 116 if (DEBUG) { 117 Log.d(TAG, "Removing listener from " + Binder.getCallingUserHandle()); 118 } 119 mListeners.unregister(listener); 120 if (mListeners.getRegisteredCallbackCount() == 0) { 121 stopWatchingPackageBroadcasts(); 122 } 123 } 124 } 125 126 /** 127 * Register a receiver to watch for package broadcasts 128 */ 129 private void startWatchingPackageBroadcasts() { 130 mPackageMonitor.register(mContext, null, UserHandle.ALL, true); 131 } 132 133 /** 134 * Unregister package broadcast receiver 135 */ 136 private void stopWatchingPackageBroadcasts() { 137 if (DEBUG) { 138 Log.d(TAG, "Stopped watching for packages"); 139 } 140 mPackageMonitor.unregister(); 141 } 142 143 void checkCallbackCount() { 144 synchronized (mListeners) { 145 if (DEBUG) { 146 Log.d(TAG, "Callback count = " + mListeners.getRegisteredCallbackCount()); 147 } 148 if (mListeners.getRegisteredCallbackCount() == 0) { 149 stopWatchingPackageBroadcasts(); 150 } 151 } 152 } 153 154 /** 155 * Checks if the caller is in the same group as the userToCheck. 156 */ 157 private void ensureInUserProfiles(UserHandle userToCheck, String message) { 158 final int callingUserId = UserHandle.getCallingUserId(); 159 final int targetUserId = userToCheck.getIdentifier(); 160 161 if (targetUserId == callingUserId) return; 162 163 long ident = Binder.clearCallingIdentity(); 164 try { 165 UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); 166 UserInfo targetUserInfo = mUm.getUserInfo(targetUserId); 167 if (targetUserInfo == null 168 || targetUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID 169 || targetUserInfo.profileGroupId != callingUserInfo.profileGroupId) { 170 throw new SecurityException(message); 171 } 172 } finally { 173 Binder.restoreCallingIdentity(ident); 174 } 175 } 176 177 /** 178 * Checks if the user is enabled. 179 */ 180 private boolean isUserEnabled(UserHandle user) { 181 long ident = Binder.clearCallingIdentity(); 182 try { 183 UserInfo targetUserInfo = mUm.getUserInfo(user.getIdentifier()); 184 return targetUserInfo != null && targetUserInfo.isEnabled(); 185 } finally { 186 Binder.restoreCallingIdentity(ident); 187 } 188 } 189 190 @Override 191 public ParceledListSlice<ResolveInfo> getLauncherActivities(String packageName, UserHandle user) 192 throws RemoteException { 193 ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user); 194 if (!isUserEnabled(user)) { 195 return null; 196 } 197 198 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 199 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 200 mainIntent.setPackage(packageName); 201 long ident = Binder.clearCallingIdentity(); 202 try { 203 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent, 204 PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier()); 205 return new ParceledListSlice<>(apps); 206 } finally { 207 Binder.restoreCallingIdentity(ident); 208 } 209 } 210 211 @Override 212 public ResolveInfo resolveActivity(Intent intent, UserHandle user) 213 throws RemoteException { 214 ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user); 215 if (!isUserEnabled(user)) { 216 return null; 217 } 218 219 long ident = Binder.clearCallingIdentity(); 220 try { 221 ResolveInfo app = mPm.resolveActivityAsUser(intent, 222 PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier()); 223 return app; 224 } finally { 225 Binder.restoreCallingIdentity(ident); 226 } 227 } 228 229 @Override 230 public boolean isPackageEnabled(String packageName, UserHandle user) 231 throws RemoteException { 232 ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user); 233 if (!isUserEnabled(user)) { 234 return false; 235 } 236 237 long ident = Binder.clearCallingIdentity(); 238 try { 239 IPackageManager pm = AppGlobals.getPackageManager(); 240 PackageInfo info = pm.getPackageInfo(packageName, 241 PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier()); 242 return info != null && info.applicationInfo.enabled; 243 } finally { 244 Binder.restoreCallingIdentity(ident); 245 } 246 } 247 248 @Override 249 public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) 250 throws RemoteException { 251 ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user); 252 if (!isUserEnabled(user)) { 253 return null; 254 } 255 256 long ident = Binder.clearCallingIdentity(); 257 try { 258 IPackageManager pm = AppGlobals.getPackageManager(); 259 ApplicationInfo info = pm.getApplicationInfo(packageName, flags, 260 user.getIdentifier()); 261 return info; 262 } finally { 263 Binder.restoreCallingIdentity(ident); 264 } 265 } 266 267 @Override 268 public boolean isActivityEnabled(ComponentName component, UserHandle user) 269 throws RemoteException { 270 ensureInUserProfiles(user, "Cannot check component for unrelated profile " + user); 271 if (!isUserEnabled(user)) { 272 return false; 273 } 274 275 long ident = Binder.clearCallingIdentity(); 276 try { 277 IPackageManager pm = AppGlobals.getPackageManager(); 278 ActivityInfo info = pm.getActivityInfo(component, 279 PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier()); 280 return info != null; 281 } finally { 282 Binder.restoreCallingIdentity(ident); 283 } 284 } 285 286 @Override 287 public void startActivityAsUser(ComponentName component, Rect sourceBounds, 288 Bundle opts, UserHandle user) throws RemoteException { 289 ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user); 290 if (!isUserEnabled(user)) { 291 throw new IllegalStateException("Cannot start activity for disabled profile " + user); 292 } 293 294 Intent launchIntent = new Intent(Intent.ACTION_MAIN); 295 launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); 296 launchIntent.setSourceBounds(sourceBounds); 297 launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 298 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 299 launchIntent.setPackage(component.getPackageName()); 300 301 long ident = Binder.clearCallingIdentity(); 302 try { 303 IPackageManager pm = AppGlobals.getPackageManager(); 304 ActivityInfo info = pm.getActivityInfo(component, 305 PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier()); 306 if (!info.exported) { 307 throw new SecurityException("Cannot launch non-exported components " 308 + component); 309 } 310 311 // Check that the component actually has Intent.CATEGORY_LAUCNCHER 312 // as calling startActivityAsUser ignores the category and just 313 // resolves based on the component if present. 314 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(launchIntent, 315 PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier()); 316 final int size = apps.size(); 317 for (int i = 0; i < size; ++i) { 318 ActivityInfo activityInfo = apps.get(i).activityInfo; 319 if (activityInfo.packageName.equals(component.getPackageName()) && 320 activityInfo.name.equals(component.getClassName())) { 321 // Found an activity with category launcher that matches 322 // this component so ok to launch. 323 launchIntent.setComponent(component); 324 mContext.startActivityAsUser(launchIntent, opts, user); 325 return; 326 } 327 } 328 throw new SecurityException("Attempt to launch activity without " 329 + " category Intent.CATEGORY_LAUNCHER " + component); 330 } finally { 331 Binder.restoreCallingIdentity(ident); 332 } 333 } 334 335 @Override 336 public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds, 337 Bundle opts, UserHandle user) throws RemoteException { 338 ensureInUserProfiles(user, "Cannot show app details for unrelated profile " + user); 339 if (!isUserEnabled(user)) { 340 throw new IllegalStateException("Cannot show app details for disabled profile " 341 + user); 342 } 343 344 long ident = Binder.clearCallingIdentity(); 345 try { 346 String packageName = component.getPackageName(); 347 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, 348 Uri.fromParts("package", packageName, null)); 349 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 350 intent.setSourceBounds(sourceBounds); 351 mContext.startActivityAsUser(intent, opts, user); 352 } finally { 353 Binder.restoreCallingIdentity(ident); 354 } 355 } 356 357 358 private class MyPackageMonitor extends PackageMonitor { 359 360 /** Checks if user is a profile of or same as listeningUser. 361 * and the user is enabled. */ 362 private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, 363 String debugMsg) { 364 if (user.getIdentifier() == listeningUser.getIdentifier()) { 365 if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg); 366 return true; 367 } 368 long ident = Binder.clearCallingIdentity(); 369 try { 370 UserInfo userInfo = mUm.getUserInfo(user.getIdentifier()); 371 UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier()); 372 if (userInfo == null || listeningUserInfo == null 373 || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID 374 || userInfo.profileGroupId != listeningUserInfo.profileGroupId 375 || !userInfo.isEnabled()) { 376 if (DEBUG) { 377 Log.d(TAG, "Not delivering msg from " + user + " to " + listeningUser + ":" 378 + debugMsg); 379 } 380 return false; 381 } else { 382 if (DEBUG) { 383 Log.d(TAG, "Delivering msg from " + user + " to " + listeningUser + ":" 384 + debugMsg); 385 } 386 return true; 387 } 388 } finally { 389 Binder.restoreCallingIdentity(ident); 390 } 391 } 392 393 @Override 394 public void onPackageAdded(String packageName, int uid) { 395 UserHandle user = new UserHandle(getChangingUserId()); 396 final int n = mListeners.beginBroadcast(); 397 for (int i = 0; i < n; i++) { 398 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 399 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 400 if (!isEnabledProfileOf(user, listeningUser, "onPackageAdded")) continue; 401 try { 402 listener.onPackageAdded(user, packageName); 403 } catch (RemoteException re) { 404 Slog.d(TAG, "Callback failed ", re); 405 } 406 } 407 mListeners.finishBroadcast(); 408 409 super.onPackageAdded(packageName, uid); 410 } 411 412 @Override 413 public void onPackageRemoved(String packageName, int uid) { 414 UserHandle user = new UserHandle(getChangingUserId()); 415 final int n = mListeners.beginBroadcast(); 416 for (int i = 0; i < n; i++) { 417 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 418 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 419 if (!isEnabledProfileOf(user, listeningUser, "onPackageRemoved")) continue; 420 try { 421 listener.onPackageRemoved(user, packageName); 422 } catch (RemoteException re) { 423 Slog.d(TAG, "Callback failed ", re); 424 } 425 } 426 mListeners.finishBroadcast(); 427 428 super.onPackageRemoved(packageName, uid); 429 } 430 431 @Override 432 public void onPackageModified(String packageName) { 433 UserHandle user = new UserHandle(getChangingUserId()); 434 final int n = mListeners.beginBroadcast(); 435 for (int i = 0; i < n; i++) { 436 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 437 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 438 if (!isEnabledProfileOf(user, listeningUser, "onPackageModified")) continue; 439 try { 440 listener.onPackageChanged(user, packageName); 441 } catch (RemoteException re) { 442 Slog.d(TAG, "Callback failed ", re); 443 } 444 } 445 mListeners.finishBroadcast(); 446 447 super.onPackageModified(packageName); 448 } 449 450 @Override 451 public void onPackagesAvailable(String[] packages) { 452 UserHandle user = new UserHandle(getChangingUserId()); 453 final int n = mListeners.beginBroadcast(); 454 for (int i = 0; i < n; i++) { 455 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 456 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 457 if (!isEnabledProfileOf(user, listeningUser, "onPackagesAvailable")) continue; 458 try { 459 listener.onPackagesAvailable(user, packages, isReplacing()); 460 } catch (RemoteException re) { 461 Slog.d(TAG, "Callback failed ", re); 462 } 463 } 464 mListeners.finishBroadcast(); 465 466 super.onPackagesAvailable(packages); 467 } 468 469 @Override 470 public void onPackagesUnavailable(String[] packages) { 471 UserHandle user = new UserHandle(getChangingUserId()); 472 final int n = mListeners.beginBroadcast(); 473 for (int i = 0; i < n; i++) { 474 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 475 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 476 if (!isEnabledProfileOf(user, listeningUser, "onPackagesUnavailable")) continue; 477 try { 478 listener.onPackagesUnavailable(user, packages, isReplacing()); 479 } catch (RemoteException re) { 480 Slog.d(TAG, "Callback failed ", re); 481 } 482 } 483 mListeners.finishBroadcast(); 484 485 super.onPackagesUnavailable(packages); 486 } 487 488 @Override 489 public void onPackagesSuspended(String[] packages) { 490 UserHandle user = new UserHandle(getChangingUserId()); 491 final int n = mListeners.beginBroadcast(); 492 for (int i = 0; i < n; i++) { 493 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 494 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 495 if (!isEnabledProfileOf(user, listeningUser, "onPackagesSuspended")) continue; 496 try { 497 listener.onPackagesSuspended(user, packages); 498 } catch (RemoteException re) { 499 Slog.d(TAG, "Callback failed ", re); 500 } 501 } 502 mListeners.finishBroadcast(); 503 504 super.onPackagesSuspended(packages); 505 } 506 507 @Override 508 public void onPackagesUnsuspended(String[] packages) { 509 UserHandle user = new UserHandle(getChangingUserId()); 510 final int n = mListeners.beginBroadcast(); 511 for (int i = 0; i < n; i++) { 512 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 513 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 514 if (!isEnabledProfileOf(user, listeningUser, "onPackagesUnsuspended")) continue; 515 try { 516 listener.onPackagesUnsuspended(user, packages); 517 } catch (RemoteException re) { 518 Slog.d(TAG, "Callback failed ", re); 519 } 520 } 521 mListeners.finishBroadcast(); 522 523 super.onPackagesUnsuspended(packages); 524 } 525 526 } 527 528 class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> { 529 @Override 530 public void onCallbackDied(T callback, Object cookie) { 531 checkCallbackCount(); 532 } 533 } 534 } 535} 536