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