LauncherAppsService.java revision 1a4e0b998030bb86196559947f417ee6fe117644
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.content.BroadcastReceiver; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.content.pm.ILauncherApps; 25import android.content.pm.IOnAppsChangedListener; 26import android.content.pm.PackageManager; 27import android.content.pm.ResolveInfo; 28import android.content.pm.UserInfo; 29import android.graphics.Rect; 30import android.os.Binder; 31import android.os.Bundle; 32import android.os.IInterface; 33import android.os.RemoteCallbackList; 34import android.os.RemoteException; 35import android.os.UserHandle; 36import android.os.UserManager; 37import android.util.Slog; 38 39import com.android.internal.content.PackageMonitor; 40 41import java.util.ArrayList; 42import java.util.List; 43 44/** 45 * Service that manages requests and callbacks for launchers that support 46 * managed profiles. 47 */ 48public class LauncherAppsService extends ILauncherApps.Stub { 49 50 private static final String TAG = "LauncherAppsService"; 51 private final Context mContext; 52 private final PackageManager mPm; 53 private final UserManager mUm; 54 private final PackageCallbackList<IOnAppsChangedListener> mListeners 55 = new PackageCallbackList<IOnAppsChangedListener>(); 56 57 private MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); 58 59 public LauncherAppsService(Context context) { 60 mContext = context; 61 mPm = mContext.getPackageManager(); 62 mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 63 } 64 65 /* 66 * @see android.content.pm.ILauncherApps#addOnAppsChangedListener( 67 * android.content.pm.IOnAppsChangedListener) 68 */ 69 @Override 70 public void addOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException { 71 synchronized (mListeners) { 72 if (mListeners.getRegisteredCallbackCount() == 0) { 73 startWatchingPackageBroadcasts(); 74 } 75 mListeners.unregister(listener); 76 mListeners.register(listener); 77 } 78 } 79 80 /* 81 * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener( 82 * android.content.pm.IOnAppsChangedListener) 83 */ 84 @Override 85 public void removeOnAppsChangedListener(IOnAppsChangedListener listener) 86 throws RemoteException { 87 synchronized (mListeners) { 88 mListeners.unregister(listener); 89 if (mListeners.getRegisteredCallbackCount() == 0) { 90 stopWatchingPackageBroadcasts(); 91 } 92 } 93 } 94 95 /** 96 * Register a receiver to watch for package broadcasts 97 */ 98 private void startWatchingPackageBroadcasts() { 99 mPackageMonitor.register(mContext, null, UserHandle.ALL, true); 100 } 101 102 /** 103 * Unregister package broadcast receiver 104 */ 105 private void stopWatchingPackageBroadcasts() { 106 mPackageMonitor.unregister(); 107 } 108 109 void checkCallbackCount() { 110 synchronized (LauncherAppsService.this) { 111 if (mListeners.getRegisteredCallbackCount() == 0) { 112 stopWatchingPackageBroadcasts(); 113 } 114 } 115 } 116 117 /** 118 * Checks if the caller is in the same group as the userToCheck. 119 */ 120 private void ensureInUserProfiles(UserHandle userToCheck, String message) { 121 final int callingUserId = UserHandle.getCallingUserId(); 122 final int targetUserId = userToCheck.getIdentifier(); 123 124 if (targetUserId == callingUserId) return; 125 126 long ident = Binder.clearCallingIdentity(); 127 try { 128 UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); 129 UserInfo targetUserInfo = mUm.getUserInfo(targetUserId); 130 if (targetUserInfo == null 131 || targetUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID 132 || targetUserInfo.profileGroupId != callingUserInfo.profileGroupId) { 133 throw new SecurityException(message); 134 } 135 } finally { 136 Binder.restoreCallingIdentity(ident); 137 } 138 } 139 140 @Override 141 public List<ResolveInfo> getLauncherActivities(String packageName, UserHandle user) 142 throws RemoteException { 143 ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user); 144 145 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 146 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 147 mainIntent.setPackage(packageName); 148 long ident = Binder.clearCallingIdentity(); 149 try { 150 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent, 0, 151 user.getIdentifier()); 152 return apps; 153 } finally { 154 Binder.restoreCallingIdentity(ident); 155 } 156 } 157 158 @Override 159 public ResolveInfo resolveActivity(Intent intent, UserHandle user) 160 throws RemoteException { 161 ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user); 162 163 long ident = Binder.clearCallingIdentity(); 164 try { 165 ResolveInfo app = mPm.resolveActivityAsUser(intent, 0, user.getIdentifier()); 166 return app; 167 } finally { 168 Binder.restoreCallingIdentity(ident); 169 } 170 } 171 172 @Override 173 public void startActivityAsUser(ComponentName component, Rect sourceBounds, 174 Bundle opts, UserHandle user) throws RemoteException { 175 ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user); 176 177 Intent launchIntent = new Intent(Intent.ACTION_MAIN); 178 launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); 179 launchIntent.setComponent(component); 180 launchIntent.setSourceBounds(sourceBounds); 181 launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 182 183 final int callingUserId = UserHandle.getCallingUserId(); 184 long ident = Binder.clearCallingIdentity(); 185 try { 186 mContext.startActivityAsUser(launchIntent, opts, user); 187 } finally { 188 Binder.restoreCallingIdentity(ident); 189 } 190 } 191 192 private class MyPackageMonitor extends PackageMonitor { 193 194 @Override 195 public void onPackageAdded(String packageName, int uid) { 196 UserHandle user = new UserHandle(getChangingUserId()); 197 // TODO: if (!isProfile(user)) return; 198 final int n = mListeners.beginBroadcast(); 199 for (int i = 0; i < n; i++) { 200 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 201 try { 202 listener.onPackageAdded(user, packageName); 203 } catch (RemoteException re) { 204 Slog.d(TAG, "Callback failed ", re); 205 } 206 } 207 mListeners.finishBroadcast(); 208 209 super.onPackageAdded(packageName, uid); 210 } 211 212 @Override 213 public void onPackageRemoved(String packageName, int uid) { 214 UserHandle user = new UserHandle(getChangingUserId()); 215 // TODO: if (!isCurrentProfile(user)) return; 216 final int n = mListeners.beginBroadcast(); 217 for (int i = 0; i < n; i++) { 218 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 219 try { 220 listener.onPackageRemoved(user, packageName); 221 } catch (RemoteException re) { 222 Slog.d(TAG, "Callback failed ", re); 223 } 224 } 225 mListeners.finishBroadcast(); 226 227 super.onPackageRemoved(packageName, uid); 228 } 229 230 @Override 231 public void onPackageModified(String packageName) { 232 UserHandle user = new UserHandle(getChangingUserId()); 233 // TODO: if (!isProfile(user)) return; 234 final int n = mListeners.beginBroadcast(); 235 for (int i = 0; i < n; i++) { 236 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 237 try { 238 listener.onPackageChanged(user, packageName); 239 } catch (RemoteException re) { 240 Slog.d(TAG, "Callback failed ", re); 241 } 242 } 243 mListeners.finishBroadcast(); 244 245 super.onPackageModified(packageName); 246 } 247 248 @Override 249 public void onPackagesAvailable(String[] packages) { 250 UserHandle user = new UserHandle(getChangingUserId()); 251 // TODO: if (!isProfile(user)) return; 252 final int n = mListeners.beginBroadcast(); 253 for (int i = 0; i < n; i++) { 254 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 255 try { 256 listener.onPackagesAvailable(user, packages, isReplacing()); 257 } catch (RemoteException re) { 258 Slog.d(TAG, "Callback failed ", re); 259 } 260 } 261 mListeners.finishBroadcast(); 262 263 super.onPackagesAvailable(packages); 264 } 265 266 @Override 267 public void onPackagesUnavailable(String[] packages) { 268 UserHandle user = new UserHandle(getChangingUserId()); 269 // TODO: if (!isProfile(user)) return; 270 final int n = mListeners.beginBroadcast(); 271 for (int i = 0; i < n; i++) { 272 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); 273 try { 274 listener.onPackagesUnavailable(user, packages, isReplacing()); 275 } catch (RemoteException re) { 276 Slog.d(TAG, "Callback failed ", re); 277 } 278 } 279 mListeners.finishBroadcast(); 280 281 super.onPackagesUnavailable(packages); 282 } 283 284 } 285 286 class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> { 287 288 @Override 289 public void onCallbackDied(T callback, Object cookie) { 290 checkCallbackCount(); 291 } 292 } 293} 294