OSDN Git Service

Push DO/PO package names from DPMS to PM
authorMakoto Onuki <omakoto@google.com>
Tue, 7 Jun 2016 19:19:46 +0000 (12:19 -0700)
committerMakoto Onuki <omakoto@google.com>
Wed, 8 Jun 2016 18:52:13 +0000 (11:52 -0700)
Bug 29126573

Change-Id: I95ea1559f6acf5d2f0e1b0953568cdfc938e83b9

core/java/android/app/admin/DevicePolicyManagerInternal.java
core/java/android/content/pm/PackageManagerInternal.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/core/java/com/android/server/pm/ProtectedPackages.java [new file with mode: 0644]
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java

index 54a2f7a..e98bb7e 100644 (file)
@@ -17,7 +17,6 @@
 package android.app.admin;
 
 import android.content.Intent;
-import android.os.UserHandle;
 
 import java.util.List;
 
@@ -74,17 +73,6 @@ public abstract class DevicePolicyManagerInternal {
     public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
 
     /**
-     * Checks if a given package has a device or a profile owner for the given user.
-     * <p>
-     * <em>Note: does <b>not</b> support negative userIds like {@link UserHandle#USER_ALL}</em>
-     *
-     * @param packageName The package to check
-     * @param userId the userId to check for.
-     * @return true if package has a device or profile owner, false otherwise.
-     */
-    public abstract boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId);
-
-    /**
      * Creates an intent to show the admin support dialog to let the user know that the package is
      * suspended by the admin. This assumes that {@param packageName} is suspended by the
      * device/profile owner. The caller should check if the package is suspended or not.
index 13ebb82..14f7727 100644 (file)
@@ -18,6 +18,7 @@ package android.content.pm;
 
 import android.content.ComponentName;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.SparseArray;
 
 import java.util.List;
 
@@ -147,4 +148,16 @@ public abstract class PackageManagerInternal {
      */
     public abstract ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
             int userId);
+
+    /**
+     * Called by DeviceOwnerManagerService to set the package names of device owner and profile
+     * owners.
+     */
+    public abstract void setDeviceAndProfileOwnerPackages(
+            int deviceOwnerUserId, String deviceOwner, SparseArray<String> profileOwners);
+
+    /**
+     * Whether a package's data be cleared.
+     */
+    public abstract boolean canPackageBeWiped(int userId, String packageName);
 }
index 32aeea8..109a80c 100644 (file)
@@ -5374,17 +5374,18 @@ public final class ActivityManagerService extends ActivityManagerNative
         userId = mUserController.handleIncomingUser(pid, uid, userId, false,
                 ALLOW_FULL_ONLY, "clearApplicationUserData", null);
 
-        final DevicePolicyManagerInternal dpmi = LocalServices
-                .getService(DevicePolicyManagerInternal.class);
-        if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
-            throw new SecurityException("Cannot clear data for a device owner or a profile owner");
-        }
 
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
             int pkgUid = -1;
             synchronized(this) {
+                if (getPackageManagerInternalLocked().canPackageBeWiped(
+                        userId, packageName)) {
+                    throw new SecurityException(
+                            "Cannot clear data for a device owner or a profile owner");
+                }
+
                 try {
                     pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES, userId);
                 } catch (RemoteException e) {
index 27ca62a..e71758c 100644 (file)
@@ -102,11 +102,11 @@ import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCES
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.ResourcesManager;
-import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.SecurityLog;
 import android.app.backup.IBackupManager;
@@ -622,6 +622,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     @GuardedBy("mPackages")
     final ArraySet<String> mFrozenPackages = new ArraySet<>();
 
+    final ProtectedPackages mProtectedPackages = new ProtectedPackages();
+
     boolean mRestoredSettings;
 
     // System configuration read by SystemConfig.
@@ -16396,9 +16398,7 @@ public class PackageManagerService extends IPackageManager.Stub {
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */, "clear application data");
 
-        final DevicePolicyManagerInternal dpmi = LocalServices
-                .getService(DevicePolicyManagerInternal.class);
-        if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+        if (mProtectedPackages.canPackageBeWiped(userId, packageName)) {
             throw new SecurityException("Cannot clear data for a device owner or a profile owner");
         }
         // Queue up an async operation since the package deletion may take a little while.
@@ -17725,10 +17725,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
                         + Binder.getCallingPid()
                         + ", uid=" + uid + ", package uid=" + pkgSetting.appId);
             }
-            // Don't allow changing profile and device owners. Calling into DPMS, so no locking.
-            final DevicePolicyManagerInternal dpmi = LocalServices
-                    .getService(DevicePolicyManagerInternal.class);
-            if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+            // Don't allow changing profile and device owners.
+            if (mProtectedPackages.canPackageStateBeChanged(userId, packageName)) {
                 throw new SecurityException("Cannot disable a device owner or a profile owner");
             }
         }
@@ -20825,6 +20823,20 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
                 int userId) {
             return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId);
         }
+
+        @Override
+        public void setDeviceAndProfileOwnerPackages(
+                int deviceOwnerUserId, String deviceOwnerPackage,
+                SparseArray<String> profileOwnerPackages) {
+            mProtectedPackages.setDeviceAndProfileOwnerPackages(
+                    deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
+        }
+
+        @Override
+        public boolean canPackageBeWiped(int userId, String packageName) {
+            return mProtectedPackages.canPackageBeWiped(userId,
+                    packageName);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java
new file mode 100644 (file)
index 0000000..7bdea18
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 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.annotation.UserIdInt;
+import android.os.UserHandle;
+import android.util.SparseArray;
+
+/**
+ * Manages package names that need special protection.
+ *
+ * TODO: This class should persist the information by itself, and also keeps track of device admin
+ * packages for all users.  Then PMS.isPackageDeviceAdmin() should use it instead of talking
+ * to DPMS.
+ */
+public class ProtectedPackages {
+    @UserIdInt
+    private int mDeviceOwnerUserId;
+
+    private String mDeviceOwnerPackage;
+
+    private SparseArray<String> mProfileOwnerPackages;
+
+    private final Object mLock = new Object();
+
+    /**
+     * Sets the device/profile owner information.
+     */
+    public void setDeviceAndProfileOwnerPackages(
+            int deviceOwnerUserId, String deviceOwnerPackage,
+            SparseArray<String> profileOwnerPackages) {
+        synchronized (mLock) {
+            mDeviceOwnerUserId = deviceOwnerUserId;
+            mDeviceOwnerPackage =
+                    (deviceOwnerUserId == UserHandle.USER_NULL) ? null : deviceOwnerPackage;
+            mProfileOwnerPackages = (profileOwnerPackages == null) ? null
+                    : profileOwnerPackages.clone();
+        }
+    }
+
+    private boolean hasDeviceOwnerOrProfileOwner(int userId, String packageName) {
+        if (packageName == null) {
+            return false;
+        }
+        synchronized (mLock) {
+            if (mDeviceOwnerPackage != null) {
+                if ((mDeviceOwnerUserId == userId)
+                        && (packageName.equals(mDeviceOwnerPackage))) {
+                    return true;
+                }
+            }
+            if (mProfileOwnerPackages != null) {
+                if (packageName.equals(mProfileOwnerPackages.get(userId))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Whether a package or the components in a package's enabled state can be changed
+     * by other callers than itself.
+     */
+    public boolean canPackageStateBeChanged(@UserIdInt int userId, String packageName) {
+        return hasDeviceOwnerOrProfileOwner(userId, packageName);
+    }
+
+    /**
+     * Whether a package's data be cleared.
+     */
+    public boolean canPackageBeWiped(@UserIdInt int userId, String packageName) {
+        return hasDeviceOwnerOrProfileOwner(userId, packageName);
+    }
+}
index 9a7e64b..4692a57 100644 (file)
@@ -1338,7 +1338,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
         }
 
         Owners newOwners() {
-            return new Owners(mContext, getUserManager(), getUserManagerInternal());
+            return new Owners(getUserManager(), getUserManagerInternal(),
+                    getPackageManagerInternal());
         }
 
         UserManager getUserManager() {
@@ -8134,26 +8135,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
         }
 
         @Override
-        public boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId) {
-            if (!mHasFeature || packageName == null) {
-                return false;
-            }
-            if (userId < 0) {
-                throw new UnsupportedOperationException("userId should be >= 0");
-            }
-            synchronized (DevicePolicyManagerService.this) {
-                if (packageName.equals(mOwners.getProfileOwnerPackage(userId))) {
-                    return true;
-                }
-                if (userId == mOwners.getDeviceOwnerUserId()
-                        && packageName.equals(mOwners.getDeviceOwnerPackageName())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @Override
         public Intent createPackageSuspendedDialogIntent(String packageName, int userId) {
             Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
             intent.putExtra(Intent.EXTRA_USER_ID, userId);
index b316cbd..cb39ebd 100644 (file)
@@ -19,6 +19,7 @@ package com.android.server.devicepolicy;
 import android.app.admin.SystemUpdatePolicy;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
 import android.os.Environment;
 import android.os.UserHandle;
@@ -28,6 +29,7 @@ import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.Xml;
 
 import com.android.internal.util.FastXmlSerializer;
@@ -86,6 +88,7 @@ class Owners {
 
     private final UserManager mUserManager;
     private final UserManagerInternal mUserManagerInternal;
+    private final PackageManagerInternal mPackageManagerInternal;
 
     // Internal state for the device owner package.
     private OwnerInfo mDeviceOwner;
@@ -98,10 +101,12 @@ class Owners {
     // Local system update policy controllable by device owner.
     private SystemUpdatePolicy mSystemUpdatePolicy;
 
-    public Owners(Context context, UserManager userManager,
-            UserManagerInternal userManagerInternal) {
+    public Owners(UserManager userManager,
+            UserManagerInternal userManagerInternal,
+            PackageManagerInternal packageManagerInternal) {
         mUserManager = userManager;
         mUserManagerInternal = userManagerInternal;
+        mPackageManagerInternal = packageManagerInternal;
     }
 
     /**
@@ -145,6 +150,17 @@ class Owners {
             Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
                     getDeviceOwnerUserId()));
         }
+        pushToPackageManager();
+    }
+
+    private void pushToPackageManager() {
+        final SparseArray<String> po = new SparseArray<>();
+        for (int i = mProfileOwners.size() - 1; i >= 0; i--) {
+            po.put(mProfileOwners.keyAt(i), mProfileOwners.valueAt(i).packageName);
+        }
+        mPackageManagerInternal.setDeviceAndProfileOwnerPackages(
+                mDeviceOwnerUserId, (mDeviceOwner != null ? mDeviceOwner.packageName : null),
+                po);
     }
 
     String getDeviceOwnerPackageName() {
@@ -190,6 +206,7 @@ class Owners {
         mDeviceOwnerUserId = userId;
 
         mUserManagerInternal.setDeviceManaged(true);
+        pushToPackageManager();
     }
 
     void clearDeviceOwner() {
@@ -197,6 +214,7 @@ class Owners {
         mDeviceOwnerUserId = UserHandle.USER_NULL;
 
         mUserManagerInternal.setDeviceManaged(false);
+        pushToPackageManager();
     }
 
     void setProfileOwner(ComponentName admin, String ownerName, int userId) {
@@ -205,11 +223,13 @@ class Owners {
                 /* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
                 /* remoteBugreportHash =*/ null));
         mUserManagerInternal.setUserManaged(userId, true);
+        pushToPackageManager();
     }
 
     void removeProfileOwner(int userId) {
         mProfileOwners.remove(userId);
         mUserManagerInternal.setUserManaged(userId, false);
+        pushToPackageManager();
     }
 
     ComponentName getProfileOwnerComponent(int userId) {
index 744443f..6cb4a82 100644 (file)
@@ -28,10 +28,8 @@ import android.os.PowerManagerInternal;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
-import android.os.storage.StorageManager;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
-import android.util.Log;
 import android.util.Pair;
 import android.view.IWindowManager;
 
@@ -57,7 +55,7 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
         private final File mProfileOwnerBase;
 
         public OwnersTestable(DpmMockContext context) {
-            super(context, context.userManager, context.userManagerInternal);
+            super(context.userManager, context.userManagerInternal, context.packageManagerInternal);
             mLegacyFile = new File(context.dataDir, LEGACY_FILE);
             mDeviceOwnerFile = new File(context.dataDir, DEVICE_OWNER_FILE);
             mProfileOwnerBase = new File(context.dataDir, PROFILE_OWNER_FILE_BASE);