Change lock-task DPM authorization to packages

Switch the DPM lock-task authorization to be controlled by a package
rather than a component.

Change-Id: Ife9bed068f31ff2449b4451ab69d3586a3f09d89
diff --git a/api/current.txt b/api/current.txt
index a09a853..e931331 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5229,7 +5229,7 @@
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationBlocked(android.content.ComponentName, java.lang.String);
     method public boolean isDeviceOwnerApp(java.lang.String);
-    method public boolean isLockTaskPermitted(android.content.ComponentName);
+    method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
     method public boolean isProfileOwnerApp(java.lang.String);
     method public void lockNow();
@@ -5243,7 +5243,7 @@
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
-    method public void setLockTaskComponents(android.content.ComponentName[]) throws java.lang.SecurityException;
+    method public void setLockTaskPackages(java.lang.String[]) throws java.lang.SecurityException;
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e80c761..ae1a4e7 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -2340,15 +2341,20 @@
     }
 
     /**
-     * Sets which components may enter lock task mode.
+     * Sets which packages may enter lock task mode.
+     *
+     * <p>Any packages that shares uid with an allowed package will also be allowed
+     * to activate lock task.
      *
      * This function can only be called by the device owner or the profile owner.
-     * @param components The list of components allowed to enter lock task mode
+     * @param packages The list of packages allowed to enter lock task mode
+     *
+     * @see Activity#startLockTask()
      */
-    public void setLockTaskComponents(ComponentName[] components) throws SecurityException {
+    public void setLockTaskPackages(String[] packages) throws SecurityException {
         if (mService != null) {
             try {
-                mService.setLockTaskComponents(components);
+                mService.setLockTaskPackages(packages);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2356,13 +2362,13 @@
     }
 
     /**
-     * This function returns the list of components allowed to start the lock task mode.
+     * This function returns the list of packages allowed to start the lock task mode.
      * @hide
      */
-    public ComponentName[] getLockTaskComponents() {
+    public String[] getLockTaskPackages() {
         if (mService != null) {
             try {
-                return mService.getLockTaskComponents();
+                return mService.getLockTaskPackages();
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2373,12 +2379,12 @@
     /**
      * This function lets the caller know whether the given component is allowed to start the
      * lock task mode.
-     * @param component The component to check
+     * @param pkg The package to check
      */
-    public boolean isLockTaskPermitted(ComponentName component) {
+    public boolean isLockTaskPermitted(String pkg) {
         if (mService != null) {
             try {
-                return mService.isLockTaskPermitted(component);
+                return mService.isLockTaskPermitted(pkg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a1caa21..8272c07 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -142,9 +142,9 @@
     void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
     String[] getAccountTypesWithManagementDisabled();
 
-    void setLockTaskComponents(in ComponentName[] components);
-    ComponentName[] getLockTaskComponents();
-    boolean isLockTaskPermitted(in ComponentName component);
+    void setLockTaskPackages(in String[] packages);
+    String[] getLockTaskPackages();
+    boolean isLockTaskPermitted(in String pkg);
 
     void setGlobalSetting(in ComponentName who, in String setting, in String value);
     void setSecureSetting(in ComponentName who, in String setting, in String value);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 697e1f2..1d9cf5b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7625,14 +7625,24 @@
         }
     }
 
-    private boolean isLockTaskAuthorized(ComponentName name) {
+    private boolean isLockTaskAuthorized(String pkg) {
         final DevicePolicyManager dpm = (DevicePolicyManager)
                 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        return dpm != null && dpm.isLockTaskPermitted(name);
+        try {
+            int uid = mContext.getPackageManager().getPackageUid(pkg,
+                    Binder.getCallingUserHandle().getIdentifier());
+            return (uid == Binder.getCallingUid()) && dpm != null && dpm.isLockTaskPermitted(pkg);
+        } catch (NameNotFoundException e) {
+            return false;
+        }
     }
 
     private void startLockTaskMode(TaskRecord task) {
-        if (!isLockTaskAuthorized(task.intent.getComponent())) {
+        final String pkg;
+        synchronized (this) {
+            pkg = task.intent.getComponent().getPackageName();
+        }
+        if (!isLockTaskAuthorized(pkg)) {
             return;
         }
         long ident = Binder.clearCallingIdentity();
@@ -7641,6 +7651,9 @@
                 // Since we lost lock on task, make sure it is still there.
                 task = mStackSupervisor.anyTaskForIdLocked(task.taskId);
                 if (task != null) {
+                    if ((mFocusedActivity == null) || (task != mFocusedActivity.task)) {
+                        throw new IllegalArgumentException("Invalid task, not in foreground");
+                    }
                     mStackSupervisor.setLockTaskModeLocked(task);
                 }
             }
@@ -7651,25 +7664,25 @@
 
     @Override
     public void startLockTaskMode(int taskId) {
+        final TaskRecord task;
         long ident = Binder.clearCallingIdentity();
         try {
-            final TaskRecord task;
             synchronized (this) {
                 task = mStackSupervisor.anyTaskForIdLocked(taskId);
             }
-            if (task != null) {
-                startLockTaskMode(task);
-            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
+        if (task != null) {
+            startLockTaskMode(task);
+        }
     }
 
     @Override
     public void startLockTaskMode(IBinder token) {
+        final TaskRecord task;
         long ident = Binder.clearCallingIdentity();
         try {
-            final TaskRecord task;
             synchronized (this) {
                 final ActivityRecord r = ActivityRecord.forToken(token);
                 if (r == null) {
@@ -7677,24 +7690,27 @@
                 }
                 task = r.task;
             }
-            if (task != null) {
-                startLockTaskMode(task);
-            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
+        if (task != null) {
+            startLockTaskMode(task);
+        }
     }
 
     @Override
     public void stopLockTaskMode() {
-        // Check if the calling task is eligible to use lock task
-        final int uid = Binder.getCallingUid();
+        // Verify that the user matches the package of the intent for the TaskRecord
+        // we are locked to.  This will ensure the same caller for startLockTaskMode and
+        // stopLockTaskMode.
         try {
-            final String name = AppGlobals.getPackageManager().getNameForUid(uid);
-            if (!isLockTaskAuthorized(new ComponentName(name, name))) {
-                return;
+            String pkg = mStackSupervisor.mLockTaskModeTask.intent.getPackage();
+            int uid = mContext.getPackageManager().getPackageUid(pkg,
+                    Binder.getCallingUserHandle().getIdentifier());
+            if (uid != Binder.getCallingUid()) {
+                throw new SecurityException("Invalid uid, expected " + uid);
             }
-        } catch (RemoteException e) {
+        } catch (NameNotFoundException e) {
             Log.d(TAG, "stopLockTaskMode " + e);
             return;
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 66e9eb3..278fa3e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -251,7 +251,7 @@
 
     /** If non-null then the task specified remains in front and no other tasks may be started
      * until the task exits or #stopLockTaskMode() is called. */
-    private TaskRecord mLockTaskModeTask;
+    TaskRecord mLockTaskModeTask;
 
     public ActivityStackSupervisor(ActivityManagerService service) {
         mService = service;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4574caf..765a33d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -195,7 +195,7 @@
                 = new ArrayList<ActiveAdmin>();
 
         // This is the list of component allowed to start lock task mode.
-        final List<ComponentName> mLockTaskComponents = new ArrayList<ComponentName>();
+        final List<String> mLockTaskPackages = new ArrayList<String>();
 
         ComponentName mRestrictionsProvider;
 
@@ -1014,10 +1014,10 @@
                 out.endTag(null, "active-password");
             }
 
-            for (int i=0; i<policy.mLockTaskComponents.size(); i++) {
-                ComponentName component = policy.mLockTaskComponents.get(i);
+            for (int i=0; i<policy.mLockTaskPackages.size(); i++) {
+                String component = policy.mLockTaskPackages.get(i);
                 out.startTag(null, LOCK_TASK_COMPONENTS_XML);
-                out.attribute(null, "name", component.flattenToString());
+                out.attribute(null, "name", component);
                 out.endTag(null, LOCK_TASK_COMPONENTS_XML);
             }
 
@@ -1077,7 +1077,7 @@
 
             type = parser.next();
             int outerDepth = parser.getDepth();
-            policy.mLockTaskComponents.clear();
+            policy.mLockTaskPackages.clear();
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -1131,9 +1131,7 @@
                             parser.getAttributeValue(null, "nonletter"));
                     XmlUtils.skipCurrentTag(parser);
                 } else if (LOCK_TASK_COMPONENTS_XML.equals(tag)) {
-                    policy.mLockTaskComponents.add
-                        (ComponentName.unflattenFromString
-                         (parser.getAttributeValue(null, "name")));
+                    policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
                     XmlUtils.skipCurrentTag(parser);
                 } else {
                     Slog.w(LOG_TAG, "Unknown tag: " + tag);
@@ -3723,38 +3721,40 @@
     }
 
     /**
-     * Sets which componets may enter lock task mode.
+     * Sets which packages may enter lock task mode.
      *
      * This function can only be called by the device owner or the profile owner.
      * @param components The list of components allowed to enter lock task mode.
      */
-    public void setLockTaskComponents(ComponentName[] components) throws SecurityException {
+    public void setLockTaskPackages(String[] packages) throws SecurityException {
         // Get the package names of the caller.
         int uid = Binder.getCallingUid();
         String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
 
-        // Check whether any of the package name is the device owner or the profile owner.
-        for (int i=0; i<packageNames.length; i++) {
-            String packageName = packageNames[i];
-            int userHandle = UserHandle.getUserId(uid);
-            String profileOwnerPackage = getProfileOwner(userHandle);
-            if (isDeviceOwner(packageName) ||
-                (profileOwnerPackage != null && profileOwnerPackage.equals(packageName))) {
+        synchronized (this) {
+            // Check whether any of the package name is the device owner or the profile owner.
+            for (int i=0; i<packageNames.length; i++) {
+                String packageName = packageNames[i];
+                int userHandle = UserHandle.getUserId(uid);
+                String profileOwnerPackage = getProfileOwner(userHandle);
+                if (isDeviceOwner(packageName) ||
+                    (profileOwnerPackage != null && profileOwnerPackage.equals(packageName))) {
 
-                // If a package name is the device owner or the profile owner,
-                // we update the component list.
-                DevicePolicyData policy = getUserData(userHandle);
-                policy.mLockTaskComponents.clear();
-                if (components != null) {
-                    for (int j=0; j<components.length; j++) {
-                        ComponentName component = components[j];
-                        policy.mLockTaskComponents.add(component);
+                    // If a package name is the device owner or the profile owner,
+                    // we update the component list.
+                    DevicePolicyData policy = getUserData(userHandle);
+                    policy.mLockTaskPackages.clear();
+                    if (packages != null) {
+                        for (int j = 0; j < packages.length; j++) {
+                            String pkg = packages[j];
+                            policy.mLockTaskPackages.add(pkg);
+                        }
                     }
-                }
 
-                // Store the settings persistently.
-                saveSettingsLocked(userHandle);
-                return;
+                    // Store the settings persistently.
+                    saveSettingsLocked(userHandle);
+                    return;
+                }
             }
         }
         throw new SecurityException();
@@ -3763,30 +3763,33 @@
     /**
      * This function returns the list of components allowed to start the task lock mode.
      */
-    public ComponentName[] getLockTaskComponents() {
-        int userHandle = UserHandle.USER_OWNER;
-        DevicePolicyData policy = getUserData(userHandle);
-        ComponentName[] tempArray = policy.mLockTaskComponents.toArray(new ComponentName[0]);
-        return tempArray;
+    public String[] getLockTaskPackages() {
+        synchronized (this) {
+            int userHandle = UserHandle.USER_OWNER;
+            DevicePolicyData policy = getUserData(userHandle);
+            return policy.mLockTaskPackages.toArray(new String[0]);
+        }
     }
 
     /**
-     * This function lets the caller know whether the given component is allowed to start the
+     * This function lets the caller know whether the given package is allowed to start the
      * lock task mode.
-     * @param component The component to check
+     * @param pkg The package to check
      */
-    public boolean isLockTaskPermitted(ComponentName component) {
+    public boolean isLockTaskPermitted(String pkg) {
         // Get current user's devicepolicy
         int uid = Binder.getCallingUid();
         int userHandle = UserHandle.getUserId(uid);
         DevicePolicyData policy = getUserData(userHandle);
-        for (int i=0; i<policy.mLockTaskComponents.size(); i++) {
-            ComponentName lockTaskComponent = policy.mLockTaskComponents.get(i);
+        synchronized (this) {
+            for (int i = 0; i < policy.mLockTaskPackages.size(); i++) {
+                String lockTaskPackage = policy.mLockTaskPackages.get(i);
 
-            // If the given component equals one of the component stored our device-owner-set
-            // list, we allow this component to start the lock task mode.
-            if (lockTaskComponent.getPackageName().equals(component.getPackageName())) {
-                return true;
+                // If the given package equals one of the packages stored our list,
+                // we allow this package to start lock task mode.
+                if (lockTaskPackage.equals(pkg)) {
+                    return true;
+                }
             }
         }
         return false;