LauncherAppsService.java revision 2871654830e94445842d6a67d775d7c317a7f2c0
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 * and the user is enabled. */ 244 private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, 245 String debugMsg) { 246 if (user.getIdentifier() == listeningUser.getIdentifier()) { 247 if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg); 248 return true; 249 } 250 long ident = Binder.clearCallingIdentity(); 251 try { 252 UserInfo userInfo = mUm.getUserInfo(user.getIdentifier()); 253 UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier()); 254 if (userInfo == null || listeningUserInfo == null 255 || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID 256 || userInfo.profileGroupId != listeningUserInfo.profileGroupId 257 || !userInfo.isEnabled()) { 258 if (DEBUG) { 259 Log.d(TAG, "Not delivering msg from " + user + " to " + listeningUser + ":" 260 + debugMsg); 261 } 262 return false; 263 } else { 264 if (DEBUG) { 265 Log.d(TAG, "Delivering msg from " + user + " to " + listeningUser + ":" 266 + debugMsg); 267 } 268 return true; 269 } 270 } finally { 271 Binder.restoreCallingIdentity(ident); 272 } 273 } 274 275 @Override 276 public void onPackageAdded(String packageName, int uid) { 277 UserHandle user = new UserHandle(getChangingUserId()); 278 final int n = mListeners.beginBroadcast(); 279 for (int i = 0; i < n; i++) { 280 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 281 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 282 if (!isEnabledProfileOf(user, listeningUser, "onPackageAdded")) continue; 283 try { 284 listener.onPackageAdded(user, packageName); 285 } catch (RemoteException re) { 286 Slog.d(TAG, "Callback failed ", re); 287 } 288 } 289 mListeners.finishBroadcast(); 290 291 super.onPackageAdded(packageName, uid); 292 } 293 294 @Override 295 public void onPackageRemoved(String packageName, int uid) { 296 UserHandle user = new UserHandle(getChangingUserId()); 297 final int n = mListeners.beginBroadcast(); 298 for (int i = 0; i < n; i++) { 299 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 300 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 301 if (!isEnabledProfileOf(user, listeningUser, "onPackageRemoved")) continue; 302 try { 303 listener.onPackageRemoved(user, packageName); 304 } catch (RemoteException re) { 305 Slog.d(TAG, "Callback failed ", re); 306 } 307 } 308 mListeners.finishBroadcast(); 309 310 super.onPackageRemoved(packageName, uid); 311 } 312 313 @Override 314 public void onPackageModified(String packageName) { 315 UserHandle user = new UserHandle(getChangingUserId()); 316 final int n = mListeners.beginBroadcast(); 317 for (int i = 0; i < n; i++) { 318 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 319 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 320 if (!isEnabledProfileOf(user, listeningUser, "onPackageModified")) continue; 321 try { 322 listener.onPackageChanged(user, packageName); 323 } catch (RemoteException re) { 324 Slog.d(TAG, "Callback failed ", re); 325 } 326 } 327 mListeners.finishBroadcast(); 328 329 super.onPackageModified(packageName); 330 } 331 332 @Override 333 public void onPackagesAvailable(String[] packages) { 334 UserHandle user = new UserHandle(getChangingUserId()); 335 final int n = mListeners.beginBroadcast(); 336 for (int i = 0; i < n; i++) { 337 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 338 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 339 if (!isEnabledProfileOf(user, listeningUser, "onPackagesAvailable")) continue; 340 try { 341 listener.onPackagesAvailable(user, packages, isReplacing()); 342 } catch (RemoteException re) { 343 Slog.d(TAG, "Callback failed ", re); 344 } 345 } 346 mListeners.finishBroadcast(); 347 348 super.onPackagesAvailable(packages); 349 } 350 351 @Override 352 public void onPackagesUnavailable(String[] packages) { 353 UserHandle user = new UserHandle(getChangingUserId()); 354 final int n = mListeners.beginBroadcast(); 355 for (int i = 0; i < n; i++) { 356 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 357 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); 358 if (!isEnabledProfileOf(user, listeningUser, "onPackagesUnavailable")) continue; 359 try { 360 listener.onPackagesUnavailable(user, packages, isReplacing()); 361 } catch (RemoteException re) { 362 Slog.d(TAG, "Callback failed ", re); 363 } 364 } 365 mListeners.finishBroadcast(); 366 367 super.onPackagesUnavailable(packages); 368 } 369 370 } 371 372 class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> { 373 @Override 374 public void onCallbackDied(T callback, Object cookie) { 375 checkCallbackCount(); 376 } 377 } 378} 379