summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorAmith Yamasani <yamasani@google.com>2014-02-19 14:31:52 -0800
committerAmith Yamasani <yamasani@google.com>2014-04-08 10:51:05 -0700
commit4f58263d02f296430a9653126d28501e95c7bb6c (patch)
treeee424e547166ddfc5da545654ac9ee2908803b02 /services
parent2d925545b6190153928658ce320d9b681baad882 (diff)
downloadframeworks_base-4f58263d02f296430a9653126d28501e95c7bb6c.zip
frameworks_base-4f58263d02f296430a9653126d28501e95c7bb6c.tar.gz
frameworks_base-4f58263d02f296430a9653126d28501e95c7bb6c.tar.bz2
Launcher APIs and broadcasts for managed profiles
UserManager - Corp badging - Querying list of managed profiles Launcher API - LauncherApps and Service to proxy changes in managed profile to the launcher in the primary profile - Querying and launching launchable apps across profiles Change-Id: Id8f7b4201afdfb5f414d04156d7b81300119289e
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java292
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java4
-rw-r--r--services/java/com/android/server/SystemServer.java9
3 files changed, 304 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
new file mode 100644
index 0000000..27c7b39
--- /dev/null
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ILauncherApps;
+import android.content.pm.IOnAppsChangedListener;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IInterface;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
+
+import com.android.internal.content.PackageMonitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Service that manages requests and callbacks for launchers that support
+ * managed profiles.
+ */
+public class LauncherAppsService extends ILauncherApps.Stub {
+
+ private static final String TAG = "LauncherAppsService";
+ private final Context mContext;
+ private final PackageManager mPm;
+ private final UserManager mUm;
+ private final PackageCallbackList<IOnAppsChangedListener> mListeners
+ = new PackageCallbackList<IOnAppsChangedListener>();
+
+ private MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
+
+ public LauncherAppsService(Context context) {
+ mContext = context;
+ mPm = mContext.getPackageManager();
+ mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ }
+
+ /*
+ * @see android.content.pm.ILauncherApps#addOnAppsChangedListener(
+ * android.content.pm.IOnAppsChangedListener)
+ */
+ @Override
+ public void addOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException {
+ synchronized (mListeners) {
+ if (mListeners.getRegisteredCallbackCount() == 0) {
+ startWatchingPackageBroadcasts();
+ }
+ mListeners.unregister(listener);
+ mListeners.register(listener);
+ }
+ }
+
+ /*
+ * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener(
+ * android.content.pm.IOnAppsChangedListener)
+ */
+ @Override
+ public void removeOnAppsChangedListener(IOnAppsChangedListener listener)
+ throws RemoteException {
+ synchronized (mListeners) {
+ mListeners.unregister(listener);
+ if (mListeners.getRegisteredCallbackCount() == 0) {
+ stopWatchingPackageBroadcasts();
+ }
+ }
+ }
+
+ /**
+ * Register a receiver to watch for package broadcasts
+ */
+ private void startWatchingPackageBroadcasts() {
+ mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
+ }
+
+ /**
+ * Unregister package broadcast receiver
+ */
+ private void stopWatchingPackageBroadcasts() {
+ mPackageMonitor.unregister();
+ }
+
+ void checkCallbackCount() {
+ synchronized (LauncherAppsService.this) {
+ if (mListeners.getRegisteredCallbackCount() == 0) {
+ stopWatchingPackageBroadcasts();
+ }
+ }
+ }
+
+ /**
+ * Checks if the caller is in the same group as the userToCheck.
+ */
+ private void ensureInUserProfiles(UserHandle userToCheck, String message) {
+ final int callingUserId = UserHandle.getCallingUserId();
+ final int targetUserId = userToCheck.getIdentifier();
+
+ if (targetUserId == callingUserId) return;
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
+ UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
+ if (targetUserInfo == null
+ || targetUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
+ || targetUserInfo.profileGroupId != callingUserInfo.profileGroupId) {
+ throw new SecurityException(message);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public List<ResolveInfo> getLauncherActivities(String packageName, UserHandle user)
+ throws RemoteException {
+ ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);
+
+ final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent, 0,
+ user.getIdentifier());
+ return apps;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public ResolveInfo resolveActivity(Intent intent, UserHandle user)
+ throws RemoteException {
+ ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user);
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ ResolveInfo app = mPm.resolveActivityAsUser(intent, 0, user.getIdentifier());
+ return app;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void startActivityAsUser(ComponentName component, Rect sourceBounds,
+ Bundle opts, UserHandle user) throws RemoteException {
+ ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
+
+ Intent launchIntent = new Intent(Intent.ACTION_MAIN);
+ launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ launchIntent.setComponent(component);
+ launchIntent.setSourceBounds(sourceBounds);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ final int callingUserId = UserHandle.getCallingUserId();
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.startActivityAsUser(launchIntent, opts, user);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private class MyPackageMonitor extends PackageMonitor {
+
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ UserHandle user = new UserHandle(getChangingUserId());
+ // TODO: if (!isProfile(user)) return;
+ final int n = mListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ try {
+ listener.onPackageAdded(user, packageName);
+ } catch (RemoteException re) {
+ Slog.d(TAG, "Callback failed ", re);
+ }
+ }
+ mListeners.finishBroadcast();
+
+ super.onPackageAdded(packageName, uid);
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ UserHandle user = new UserHandle(getChangingUserId());
+ // TODO: if (!isCurrentProfile(user)) return;
+ final int n = mListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ try {
+ listener.onPackageRemoved(user, packageName);
+ } catch (RemoteException re) {
+ Slog.d(TAG, "Callback failed ", re);
+ }
+ }
+ mListeners.finishBroadcast();
+
+ super.onPackageRemoved(packageName, uid);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ UserHandle user = new UserHandle(getChangingUserId());
+ // TODO: if (!isProfile(user)) return;
+ final int n = mListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ try {
+ listener.onPackageChanged(user, packageName);
+ } catch (RemoteException re) {
+ Slog.d(TAG, "Callback failed ", re);
+ }
+ }
+ mListeners.finishBroadcast();
+
+ super.onPackageModified(packageName);
+ }
+
+ @Override
+ public void onPackagesAvailable(String[] packages) {
+ UserHandle user = new UserHandle(getChangingUserId());
+ // TODO: if (!isProfile(user)) return;
+ final int n = mListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ try {
+ listener.onPackagesAvailable(user, packages, isReplacing());
+ } catch (RemoteException re) {
+ Slog.d(TAG, "Callback failed ", re);
+ }
+ }
+ mListeners.finishBroadcast();
+
+ super.onPackagesAvailable(packages);
+ }
+
+ @Override
+ public void onPackagesUnavailable(String[] packages) {
+ UserHandle user = new UserHandle(getChangingUserId());
+ // TODO: if (!isProfile(user)) return;
+ final int n = mListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ try {
+ listener.onPackagesUnavailable(user, packages, isReplacing());
+ } catch (RemoteException re) {
+ Slog.d(TAG, "Callback failed ", re);
+ }
+ }
+ mListeners.finishBroadcast();
+
+ super.onPackagesUnavailable(packages);
+ }
+
+ }
+
+ class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> {
+
+ @Override
+ public void onCallbackDied(T callback, Object cookie) {
+ checkCallbackCount();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a39e958..32515b5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -258,7 +258,9 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public List<UserInfo> getProfiles(int userId) {
- checkManageUsersPermission("query users");
+ if (userId != UserHandle.getCallingUserId()) {
+ checkManageUsersPermission("getting profiles related to user " + userId);
+ }
synchronized (mPackagesLock) {
UserInfo user = getUserInfoLocked(userId);
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8f2adc8..bc7f08e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -70,6 +70,7 @@ import com.android.server.net.NetworkStatsService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.pm.Installer;
+import com.android.server.pm.LauncherAppsService;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.UserManagerService;
import com.android.server.power.PowerManagerService;
@@ -922,6 +923,14 @@ public final class SystemServer {
Slog.e(TAG, "Failure starting TrustManagerService", e);
}
}
+
+ try {
+ Slog.i(TAG, "LauncherAppsService");
+ LauncherAppsService las = new LauncherAppsService(context);
+ ServiceManager.addService(Context.LAUNCHER_APPS_SERVICE, las);
+ } catch (Throwable t) {
+ reportWtf("starting LauncherAppsService", t);
+ }
}
// Before things start rolling, be sure we have decided whether