From 6b0d330da013ab84f01449a51b402db7a8a69e89 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Mon, 4 Apr 2022 12:22:45 +0100 Subject: [PATCH 1/2] Extract OwnersData from Owners. This change is intended to allow processing owners data during policy version upgrade. Owners currently has a lot of side effects like calls to other services, which doesn't allow it to be used as is. This change extracts "pure" data object from Onwers, which just holds the values and knows how to serialize/deserialize itself, which can be used for upgrade. Bug: 218639412 Test: atest com.android.server.devicepolicy Change-Id: I7a79cafee4ff4437c55bb21d65adeb6815da2d0b --- .../android/server/devicepolicy/Owners.java | 802 ++++-------------- .../server/devicepolicy/OwnersData.java | 583 +++++++++++++ .../DevicePolicyManagerServiceTestable.java | 2 +- 3 files changed, 741 insertions(+), 646 deletions(-) create mode 100644 services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java index 859183c801917..09d5c4a60c820 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java @@ -27,43 +27,31 @@ import android.app.admin.SystemUpdatePolicy; import android.content.ComponentName; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.UserInfo; import android.os.Binder; -import android.os.Environment; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.AtomicFile; import android.util.IndentingPrintWriter; -import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; -import android.util.TypedXmlPullParser; -import android.util.TypedXmlSerializer; -import android.util.Xml; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; +import com.android.server.devicepolicy.OwnersData.Injector; +import com.android.server.devicepolicy.OwnersData.OwnerInfo; import com.android.server.pm.UserManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; -import libcore.io.IoUtils; - -import org.xmlpull.v1.XmlPullParserException; - import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; import java.time.LocalDate; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; @@ -79,81 +67,24 @@ class Owners { private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE - // XML storing device owner info, system update policy and pending OTA update information. - private static final String DEVICE_OWNER_XML = "device_owner_2.xml"; - - private static final String PROFILE_OWNER_XML = "profile_owner.xml"; - - private static final String TAG_ROOT = "root"; - - private static final String TAG_DEVICE_OWNER = "device-owner"; - private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy"; - private static final String TAG_FREEZE_PERIOD_RECORD = "freeze-record"; - private static final String TAG_PENDING_OTA_INFO = "pending-ota-info"; - private static final String TAG_PROFILE_OWNER = "profile-owner"; - // Holds "context" for device-owner, this must not be show up before device-owner. - private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context"; - private static final String TAG_DEVICE_OWNER_TYPE = "device-owner-type"; - private static final String TAG_DEVICE_OWNER_PROTECTED_PACKAGES = - "device-owner-protected-packages"; - - private static final String ATTR_NAME = "name"; - private static final String ATTR_PACKAGE = "package"; - private static final String ATTR_COMPONENT_NAME = "component"; - private static final String ATTR_SIZE = "size"; - private static final String ATTR_REMOTE_BUGREPORT_URI = "remoteBugreportUri"; - private static final String ATTR_REMOTE_BUGREPORT_HASH = "remoteBugreportHash"; - private static final String ATTR_USERID = "userId"; - private static final String ATTR_FREEZE_RECORD_START = "start"; - private static final String ATTR_FREEZE_RECORD_END = "end"; - // Legacy attribute, its presence would mean the profile owner associated with it is - // managing a profile on an organization-owned device. - private static final String ATTR_CAN_ACCESS_DEVICE_IDS = "canAccessDeviceIds"; - // New attribute for profile owner of organization-owned device. - private static final String ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE = - "isPoOrganizationOwnedDevice"; - private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value"; - private final UserManager mUserManager; private final UserManagerInternal mUserManagerInternal; private final PackageManagerInternal mPackageManagerInternal; private final ActivityTaskManagerInternal mActivityTaskManagerInternal; private final ActivityManagerInternal mActivityManagerInternal; + @GuardedBy("mData") + private final OwnersData mData; + private boolean mSystemReady; - // Internal state for the device owner package. - private OwnerInfo mDeviceOwner; - - // Device owner type for a managed device. - private final ArrayMap mDeviceOwnerTypes = new ArrayMap<>(); - - private final ArrayMap> mDeviceOwnerProtectedPackages = new ArrayMap<>(); - - private int mDeviceOwnerUserId = UserHandle.USER_NULL; - - // Internal state for the profile owner packages. - private final ArrayMap mProfileOwners = new ArrayMap<>(); - - // Local system update policy controllable by device owner. - private SystemUpdatePolicy mSystemUpdatePolicy; - private LocalDate mSystemUpdateFreezeStart; - private LocalDate mSystemUpdateFreezeEnd; - - // Pending OTA info if there is one. - @Nullable - private SystemUpdateInfo mSystemUpdateInfo; - - private final Object mLock = new Object(); - private final Injector mInjector; - public Owners(UserManager userManager, UserManagerInternal userManagerInternal, PackageManagerInternal packageManagerInternal, ActivityTaskManagerInternal activityTaskManagerInternal, - ActivityManagerInternal activitykManagerInternal) { + ActivityManagerInternal activityManagerInternal) { this(userManager, userManagerInternal, packageManagerInternal, - activityTaskManagerInternal, activitykManagerInternal, new Injector()); + activityTaskManagerInternal, activityManagerInternal, new Injector()); } @VisibleForTesting @@ -168,36 +99,28 @@ class Owners { mPackageManagerInternal = packageManagerInternal; mActivityTaskManagerInternal = activityTaskManagerInternal; mActivityManagerInternal = activityManagerInternal; - mInjector = injector; + mData = new OwnersData(injector); } /** * Load configuration from the disk. */ void load() { - synchronized (mLock) { - final List users = mUserManager.getAliveUsers(); - - new DeviceOwnerReadWriter().readFromFileLocked(); - - for (UserInfo ui : users) { - new ProfileOwnerReadWriter(ui.id).readFromFileLocked(); - } + synchronized (mData) { + int[] usersIds = + mUserManager.getAliveUsers().stream().mapToInt(u -> u.id).toArray(); + mData.load(usersIds); mUserManagerInternal.setDeviceManaged(hasDeviceOwner()); - for (UserInfo ui : users) { - mUserManagerInternal.setUserManaged(ui.id, hasProfileOwner(ui.id)); - } - if (hasDeviceOwner() && hasProfileOwner(getDeviceOwnerUserId())) { - Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported", - getDeviceOwnerUserId())); + for (int userId : usersIds) { + mUserManagerInternal.setUserManaged(userId, hasProfileOwner(userId)); } notifyChangeLocked(); pushToActivityTaskManagerLocked(); for (ArrayMap.Entry> entry : - mDeviceOwnerProtectedPackages.entrySet()) { + mData.mDeviceOwnerProtectedPackages.entrySet()) { mPackageManagerInternal.setDeviceOwnerProtectedPackages( entry.getKey(), entry.getValue()); } @@ -206,6 +129,7 @@ class Owners { // Notify interested parties that things have changed. This does not notify the // ActivityTaskManager. + @GuardedBy("mData") private void notifyChangeLocked() { pushToDevicePolicyManager(); pushToPackageManagerLocked(); @@ -219,28 +143,31 @@ class Owners { DevicePolicyManagerService.invalidateBinderCaches(); } + @GuardedBy("mData") private void pushToPackageManagerLocked() { final SparseArray po = new SparseArray<>(); - for (int i = mProfileOwners.size() - 1; i >= 0; i--) { - po.put(mProfileOwners.keyAt(i), mProfileOwners.valueAt(i).packageName); + for (int i = mData.mProfileOwners.size() - 1; i >= 0; i--) { + po.put(mData.mProfileOwners.keyAt(i), mData.mProfileOwners.valueAt(i).packageName); } + final String doPackage = mData.mDeviceOwner != null ? mData.mDeviceOwner.packageName : null; mPackageManagerInternal.setDeviceAndProfileOwnerPackages( - mDeviceOwnerUserId, (mDeviceOwner != null ? mDeviceOwner.packageName : null), - po); + mData.mDeviceOwnerUserId, doPackage, po); } + @GuardedBy("mData") private void pushToActivityTaskManagerLocked() { mActivityTaskManagerInternal.setDeviceOwnerUid(getDeviceOwnerUidLocked()); } + @GuardedBy("mData") private void pushToActivityManagerLocked() { mActivityManagerInternal.setDeviceOwnerUid(getDeviceOwnerUidLocked()); final ArraySet profileOwners = new ArraySet<>(); - for (int poi = mProfileOwners.size() - 1; poi >= 0; poi--) { - final int userId = mProfileOwners.keyAt(poi); + for (int poi = mData.mProfileOwners.size() - 1; poi >= 0; poi--) { + final int userId = mData.mProfileOwners.keyAt(poi); final int profileOwnerUid = mPackageManagerInternal.getPackageUid( - mProfileOwners.valueAt(poi).packageName, + mData.mProfileOwners.valueAt(poi).packageName, PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES, userId); if (profileOwnerUid >= 0) { @@ -250,60 +177,61 @@ class Owners { mActivityManagerInternal.setProfileOwnerUid(profileOwners); } + @GuardedBy("mData") int getDeviceOwnerUidLocked() { - if (mDeviceOwner != null) { - return mPackageManagerInternal.getPackageUid(mDeviceOwner.packageName, + if (mData.mDeviceOwner != null) { + return mPackageManagerInternal.getPackageUid(mData.mDeviceOwner.packageName, PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES, - mDeviceOwnerUserId); + mData.mDeviceOwnerUserId); } else { return Process.INVALID_UID; } } String getDeviceOwnerPackageName() { - synchronized (mLock) { - return mDeviceOwner != null ? mDeviceOwner.packageName : null; + synchronized (mData) { + return mData.mDeviceOwner != null ? mData.mDeviceOwner.packageName : null; } } int getDeviceOwnerUserId() { - synchronized (mLock) { - return mDeviceOwnerUserId; + synchronized (mData) { + return mData.mDeviceOwnerUserId; } } @Nullable Pair getDeviceOwnerUserIdAndComponent() { - synchronized (mLock) { - if (mDeviceOwner == null) { + synchronized (mData) { + if (mData.mDeviceOwner == null) { return null; } else { - return Pair.create(mDeviceOwnerUserId, mDeviceOwner.admin); + return Pair.create(mData.mDeviceOwnerUserId, mData.mDeviceOwner.admin); } } } String getDeviceOwnerName() { - synchronized (mLock) { - return mDeviceOwner != null ? mDeviceOwner.name : null; + synchronized (mData) { + return mData.mDeviceOwner != null ? mData.mDeviceOwner.name : null; } } ComponentName getDeviceOwnerComponent() { - synchronized (mLock) { - return mDeviceOwner != null ? mDeviceOwner.admin : null; + synchronized (mData) { + return mData.mDeviceOwner != null ? mData.mDeviceOwner.admin : null; } } String getDeviceOwnerRemoteBugreportUri() { - synchronized (mLock) { - return mDeviceOwner != null ? mDeviceOwner.remoteBugreportUri : null; + synchronized (mData) { + return mData.mDeviceOwner != null ? mData.mDeviceOwner.remoteBugreportUri : null; } } String getDeviceOwnerRemoteBugreportHash() { - synchronized (mLock) { - return mDeviceOwner != null ? mDeviceOwner.remoteBugreportHash : null; + synchronized (mData) { + return mData.mDeviceOwner != null ? mData.mDeviceOwner.remoteBugreportHash : null; } } @@ -312,13 +240,13 @@ class Owners { Slog.e(TAG, "Invalid user id for device owner user: " + userId); return; } - synchronized (mLock) { + synchronized (mData) { // A device owner is allowed to access device identifiers. Even though this flag // is not currently checked for device owner, it is set to true here so that it is // semantically compatible with the meaning of this flag. - mDeviceOwner = new OwnerInfo(ownerName, admin, /* remoteBugreportUri =*/ null, + mData.mDeviceOwner = new OwnerInfo(ownerName, admin, /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null, /* isOrganizationOwnedDevice =*/ true); - mDeviceOwnerUserId = userId; + mData.mDeviceOwnerUserId = userId; mUserManagerInternal.setDeviceManaged(true); notifyChangeLocked(); @@ -327,16 +255,16 @@ class Owners { } void clearDeviceOwner() { - synchronized (mLock) { - mDeviceOwnerTypes.remove(mDeviceOwner.packageName); + synchronized (mData) { + mData.mDeviceOwnerTypes.remove(mData.mDeviceOwner.packageName); List protectedPackages = - mDeviceOwnerProtectedPackages.remove(mDeviceOwner.packageName); + mData.mDeviceOwnerProtectedPackages.remove(mData.mDeviceOwner.packageName); if (protectedPackages != null) { mPackageManagerInternal.setDeviceOwnerProtectedPackages( - mDeviceOwner.packageName, new ArrayList<>()); + mData.mDeviceOwner.packageName, new ArrayList<>()); } - mDeviceOwner = null; - mDeviceOwnerUserId = UserHandle.USER_NULL; + mData.mDeviceOwner = null; + mData.mDeviceOwnerUserId = UserHandle.USER_NULL; mUserManagerInternal.setDeviceManaged(false); notifyChangeLocked(); @@ -345,9 +273,9 @@ class Owners { } void setProfileOwner(ComponentName admin, String ownerName, int userId) { - synchronized (mLock) { + synchronized (mData) { // For a newly set PO, there's no need for migration. - mProfileOwners.put(userId, new OwnerInfo(ownerName, admin, + mData.mProfileOwners.put(userId, new OwnerInfo(ownerName, admin, /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null, /* isOrganizationOwnedDevice =*/ false)); mUserManagerInternal.setUserManaged(userId, true); @@ -356,43 +284,48 @@ class Owners { } void removeProfileOwner(int userId) { - synchronized (mLock) { - mProfileOwners.remove(userId); + synchronized (mData) { + mData.mProfileOwners.remove(userId); mUserManagerInternal.setUserManaged(userId, false); notifyChangeLocked(); } } void transferProfileOwner(ComponentName target, int userId) { - synchronized (mLock) { - final OwnerInfo ownerInfo = mProfileOwners.get(userId); + synchronized (mData) { + final OwnerInfo ownerInfo = mData.mProfileOwners.get(userId); final OwnerInfo newOwnerInfo = new OwnerInfo(target.getPackageName(), target, ownerInfo.remoteBugreportUri, ownerInfo.remoteBugreportHash, ownerInfo.isOrganizationOwnedDevice); - mProfileOwners.put(userId, newOwnerInfo); + mData.mProfileOwners.put(userId, newOwnerInfo); notifyChangeLocked(); } } void transferDeviceOwnership(ComponentName target) { - synchronized (mLock) { - Integer previousDeviceOwnerType = mDeviceOwnerTypes.remove(mDeviceOwner.packageName); + synchronized (mData) { + Integer previousDeviceOwnerType = mData.mDeviceOwnerTypes.remove( + mData.mDeviceOwner.packageName); List previousProtectedPackages = - mDeviceOwnerProtectedPackages.remove(mDeviceOwner.packageName); + mData.mDeviceOwnerProtectedPackages.remove(mData.mDeviceOwner.packageName); if (previousProtectedPackages != null) { mPackageManagerInternal.setDeviceOwnerProtectedPackages( - mDeviceOwner.packageName, new ArrayList<>()); + mData.mDeviceOwner.packageName, new ArrayList<>()); } // We don't set a name because it's not used anyway. // See DevicePolicyManagerService#getDeviceOwnerName - mDeviceOwner = new OwnerInfo(null, target, mDeviceOwner.remoteBugreportUri, - mDeviceOwner.remoteBugreportHash, mDeviceOwner.isOrganizationOwnedDevice); + mData.mDeviceOwner = new OwnerInfo(null, target, + mData.mDeviceOwner.remoteBugreportUri, + mData.mDeviceOwner.remoteBugreportHash, + mData.mDeviceOwner.isOrganizationOwnedDevice); + if (previousDeviceOwnerType != null) { - mDeviceOwnerTypes.put(mDeviceOwner.packageName, previousDeviceOwnerType); + mData.mDeviceOwnerTypes.put( + mData.mDeviceOwner.packageName, previousDeviceOwnerType); } if (previousProtectedPackages != null) { - mDeviceOwnerProtectedPackages.put( - mDeviceOwner.packageName, previousProtectedPackages); + mData.mDeviceOwnerProtectedPackages.put( + mData.mDeviceOwner.packageName, previousProtectedPackages); } notifyChangeLocked(); pushToActivityTaskManagerLocked(); @@ -400,22 +333,22 @@ class Owners { } ComponentName getProfileOwnerComponent(int userId) { - synchronized (mLock) { - OwnerInfo profileOwner = mProfileOwners.get(userId); + synchronized (mData) { + OwnerInfo profileOwner = mData.mProfileOwners.get(userId); return profileOwner != null ? profileOwner.admin : null; } } String getProfileOwnerName(int userId) { - synchronized (mLock) { - OwnerInfo profileOwner = mProfileOwners.get(userId); + synchronized (mData) { + OwnerInfo profileOwner = mData.mProfileOwners.get(userId); return profileOwner != null ? profileOwner.name : null; } } String getProfileOwnerPackage(int userId) { - synchronized (mLock) { - OwnerInfo profileOwner = mProfileOwners.get(userId); + synchronized (mData) { + OwnerInfo profileOwner = mData.mProfileOwners.get(userId); return profileOwner != null ? profileOwner.packageName : null; } } @@ -425,27 +358,28 @@ class Owners { * organization-owned device, as indicated by the provisioning flow. */ boolean isProfileOwnerOfOrganizationOwnedDevice(int userId) { - synchronized (mLock) { - OwnerInfo profileOwner = mProfileOwners.get(userId); + synchronized (mData) { + OwnerInfo profileOwner = mData.mProfileOwners.get(userId); return profileOwner != null ? profileOwner.isOrganizationOwnedDevice : false; } } Set getProfileOwnerKeys() { - synchronized (mLock) { - return mProfileOwners.keySet(); + synchronized (mData) { + return mData.mProfileOwners.keySet(); } } List listAllOwners() { List owners = new ArrayList<>(); - synchronized (mLock) { - if (mDeviceOwner != null) { - owners.add(OwnerShellData.forDeviceOwner(mDeviceOwnerUserId, mDeviceOwner.admin)); + synchronized (mData) { + if (mData.mDeviceOwner != null) { + owners.add(OwnerShellData.forDeviceOwner(mData.mDeviceOwnerUserId, + mData.mDeviceOwner.admin)); } - for (int i = 0; i < mProfileOwners.size(); i++) { - int userId = mProfileOwners.keyAt(i); - OwnerInfo info = mProfileOwners.valueAt(i); + for (int i = 0; i < mData.mProfileOwners.size(); i++) { + int userId = mData.mProfileOwners.keyAt(i); + OwnerInfo info = mData.mProfileOwners.valueAt(i); owners.add(OwnerShellData.forUserProfileOwner(userId, info.admin)); } } @@ -454,44 +388,34 @@ class Owners { SystemUpdatePolicy getSystemUpdatePolicy() { - synchronized (mLock) { - return mSystemUpdatePolicy; + synchronized (mData) { + return mData.mSystemUpdatePolicy; } } void setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy) { - synchronized (mLock) { - mSystemUpdatePolicy = systemUpdatePolicy; + synchronized (mData) { + mData.mSystemUpdatePolicy = systemUpdatePolicy; } } void clearSystemUpdatePolicy() { - synchronized (mLock) { - mSystemUpdatePolicy = null; + synchronized (mData) { + mData.mSystemUpdatePolicy = null; } } Pair getSystemUpdateFreezePeriodRecord() { - synchronized (mLock) { - return new Pair<>(mSystemUpdateFreezeStart, mSystemUpdateFreezeEnd); + synchronized (mData) { + return new Pair<>(mData.mSystemUpdateFreezeStart, + mData.mSystemUpdateFreezeEnd); } } String getSystemUpdateFreezePeriodRecordAsString() { - StringBuilder freezePeriodRecord = new StringBuilder(); - freezePeriodRecord.append("start: "); - if (mSystemUpdateFreezeStart != null) { - freezePeriodRecord.append(mSystemUpdateFreezeStart.toString()); - } else { - freezePeriodRecord.append("null"); + synchronized (mData) { + return mData.getSystemUpdateFreezePeriodRecordAsString(); } - freezePeriodRecord.append("; end: "); - if (mSystemUpdateFreezeEnd != null) { - freezePeriodRecord.append(mSystemUpdateFreezeEnd.toString()); - } else { - freezePeriodRecord.append("null"); - } - return freezePeriodRecord.toString(); } /** @@ -499,13 +423,13 @@ class Owners { */ boolean setSystemUpdateFreezePeriodRecord(LocalDate start, LocalDate end) { boolean changed = false; - synchronized (mLock) { - if (!Objects.equals(mSystemUpdateFreezeStart, start)) { - mSystemUpdateFreezeStart = start; + synchronized (mData) { + if (!Objects.equals(mData.mSystemUpdateFreezeStart, start)) { + mData.mSystemUpdateFreezeStart = start; changed = true; } - if (!Objects.equals(mSystemUpdateFreezeEnd, end)) { - mSystemUpdateFreezeEnd = end; + if (!Objects.equals(mData.mSystemUpdateFreezeEnd, end)) { + mData.mSystemUpdateFreezeEnd = end; changed = true; } } @@ -513,19 +437,19 @@ class Owners { } boolean hasDeviceOwner() { - synchronized (mLock) { - return mDeviceOwner != null; + synchronized (mData) { + return mData.mDeviceOwner != null; } } boolean isDeviceOwnerUserId(int userId) { - synchronized (mLock) { - return mDeviceOwner != null && mDeviceOwnerUserId == userId; + synchronized (mData) { + return mData.mDeviceOwner != null && mData.mDeviceOwnerUserId == userId; } } boolean hasProfileOwner(int userId) { - synchronized (mLock) { + synchronized (mData) { return getProfileOwnerComponent(userId) != null; } } @@ -533,10 +457,10 @@ class Owners { /** Sets the remote bugreport uri and hash, and also writes to the file. */ void setDeviceOwnerRemoteBugreportUriAndHash(String remoteBugreportUri, String remoteBugreportHash) { - synchronized (mLock) { - if (mDeviceOwner != null) { - mDeviceOwner.remoteBugreportUri = remoteBugreportUri; - mDeviceOwner.remoteBugreportHash = remoteBugreportHash; + synchronized (mData) { + if (mData.mDeviceOwner != null) { + mData.mDeviceOwner.remoteBugreportUri = remoteBugreportUri; + mData.mDeviceOwner.remoteBugreportHash = remoteBugreportHash; } writeDeviceOwner(); } @@ -544,8 +468,8 @@ class Owners { /** Set whether the profile owner manages an organization-owned device, then write to file. */ void setProfileOwnerOfOrganizationOwnedDevice(int userId, boolean isOrganizationOwnedDevice) { - synchronized (mLock) { - OwnerInfo profileOwner = mProfileOwners.get(userId); + synchronized (mData) { + OwnerInfo profileOwner = mData.mProfileOwners.get(userId); if (profileOwner != null) { profileOwner.isOrganizationOwnedDevice = isOrganizationOwnedDevice; } else { @@ -558,7 +482,7 @@ class Owners { void setDeviceOwnerType(String packageName, @DeviceOwnerType int deviceOwnerType, boolean isAdminTestOnly) { - synchronized (mLock) { + synchronized (mData) { if (!hasDeviceOwner()) { Slog.e(TAG, "Attempting to set a device owner type when there is no device owner"); return; @@ -568,71 +492,67 @@ class Owners { return; } - mDeviceOwnerTypes.put(packageName, deviceOwnerType); + mData.mDeviceOwnerTypes.put(packageName, deviceOwnerType); writeDeviceOwner(); } } @DeviceOwnerType int getDeviceOwnerType(String packageName) { - synchronized (mLock) { + synchronized (mData) { if (isDeviceOwnerTypeSetForDeviceOwner(packageName)) { - return mDeviceOwnerTypes.get(packageName); + return mData.mDeviceOwnerTypes.get(packageName); } return DEVICE_OWNER_TYPE_DEFAULT; } } boolean isDeviceOwnerTypeSetForDeviceOwner(String packageName) { - synchronized (mLock) { - return !mDeviceOwnerTypes.isEmpty() && mDeviceOwnerTypes.containsKey(packageName); + synchronized (mData) { + return !mData.mDeviceOwnerTypes.isEmpty() + && mData.mDeviceOwnerTypes.containsKey(packageName); } } void setDeviceOwnerProtectedPackages(String packageName, List protectedPackages) { - synchronized (mLock) { + synchronized (mData) { if (!hasDeviceOwner()) { Slog.e(TAG, "Attempting to set device owner protected packages when there is no " + "device owner"); return; - } else if (!mDeviceOwner.packageName.equals(packageName)) { + } else if (!mData.mDeviceOwner.packageName.equals(packageName)) { Slog.e(TAG, "Attempting to set device owner protected packages when the provided " + "package name " + packageName + " does not match the device owner package name"); return; } - mDeviceOwnerProtectedPackages.put(packageName, protectedPackages); + mData.mDeviceOwnerProtectedPackages.put(packageName, protectedPackages); mPackageManagerInternal.setDeviceOwnerProtectedPackages(packageName, protectedPackages); writeDeviceOwner(); } } List getDeviceOwnerProtectedPackages(String packageName) { - synchronized (mLock) { - return mDeviceOwnerProtectedPackages.containsKey(packageName) - ? mDeviceOwnerProtectedPackages.get(packageName) : Collections.emptyList(); + synchronized (mData) { + return mData.mDeviceOwnerProtectedPackages.containsKey(packageName) + ? mData.mDeviceOwnerProtectedPackages.get(packageName) + : Collections.emptyList(); } } void writeDeviceOwner() { - synchronized (mLock) { - if (DEBUG) { - Log.d(TAG, "Writing to device owner file"); - } + synchronized (mData) { pushToDevicePolicyManager(); - new DeviceOwnerReadWriter().writeToFileLocked(); + mData.writeDeviceOwner(); } } void writeProfileOwner(int userId) { - synchronized (mLock) { - if (DEBUG) { - Log.d(TAG, "Writing to profile owner file for user " + userId); - } + synchronized (mData) { pushToDevicePolicyManager(); - new ProfileOwnerReadWriter(userId).writeToFileLocked(); + mData.writeProfileOwner(userId); } } @@ -643,25 +563,26 @@ class Owners { * @return Whether the saved system update information has changed. */ boolean saveSystemUpdateInfo(@Nullable SystemUpdateInfo newInfo) { - synchronized (mLock) { + synchronized (mData) { // Check if we already have the same update information. - if (Objects.equals(newInfo, mSystemUpdateInfo)) { + if (Objects.equals(newInfo, mData.mSystemUpdateInfo)) { return false; } - mSystemUpdateInfo = newInfo; - new DeviceOwnerReadWriter().writeToFileLocked(); + mData.mSystemUpdateInfo = newInfo; + mData.writeDeviceOwner(); return true; } } @Nullable public SystemUpdateInfo getSystemUpdateInfo() { - synchronized (mLock) { - return mSystemUpdateInfo; + synchronized (mData) { + return mData.mSystemUpdateInfo; } } + @GuardedBy("mData") void pushToAppOpsLocked() { if (!mSystemReady) { return; @@ -669,20 +590,20 @@ class Owners { final long ident = Binder.clearCallingIdentity(); try { final SparseIntArray owners = new SparseIntArray(); - if (mDeviceOwner != null) { + if (mData.mDeviceOwner != null) { final int uid = getDeviceOwnerUidLocked(); if (uid >= 0) { - owners.put(mDeviceOwnerUserId, uid); + owners.put(mData.mDeviceOwnerUserId, uid); } } - if (mProfileOwners != null) { - for (int poi = mProfileOwners.size() - 1; poi >= 0; poi--) { + if (mData.mProfileOwners != null) { + for (int poi = mData.mProfileOwners.size() - 1; poi >= 0; poi--) { final int uid = mPackageManagerInternal.getPackageUid( - mProfileOwners.valueAt(poi).packageName, + mData.mProfileOwners.valueAt(poi).packageName, PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES, - mProfileOwners.keyAt(poi)); + mData.mProfileOwners.keyAt(poi)); if (uid >= 0) { - owners.put(mProfileOwners.keyAt(poi), uid); + owners.put(mData.mProfileOwners.keyAt(poi), uid); } } } @@ -696,435 +617,26 @@ class Owners { } public void systemReady() { - synchronized (mLock) { + synchronized (mData) { mSystemReady = true; pushToActivityManagerLocked(); pushToAppOpsLocked(); } } - private abstract static class FileReadWriter { - private final File mFile; - - protected FileReadWriter(File file) { - mFile = file; - } - - abstract boolean shouldWrite(); - - void writeToFileLocked() { - if (!shouldWrite()) { - if (DEBUG) { - Log.d(TAG, "No need to write to " + mFile); - } - // No contents, remove the file. - if (mFile.exists()) { - if (DEBUG) { - Log.d(TAG, "Deleting existing " + mFile); - } - if (!mFile.delete()) { - Slog.e(TAG, "Failed to remove " + mFile.getPath()); - } - } - return; - } - if (DEBUG) { - Log.d(TAG, "Writing to " + mFile); - } - - final AtomicFile f = new AtomicFile(mFile); - FileOutputStream outputStream = null; - try { - outputStream = f.startWrite(); - final TypedXmlSerializer out = Xml.resolveSerializer(outputStream); - - // Root tag - out.startDocument(null, true); - out.startTag(null, TAG_ROOT); - - // Actual content - writeInner(out); - - // Close root - out.endTag(null, TAG_ROOT); - out.endDocument(); - out.flush(); - - // Commit the content. - f.finishWrite(outputStream); - outputStream = null; - - } catch (IOException e) { - Slog.e(TAG, "Exception when writing", e); - if (outputStream != null) { - f.failWrite(outputStream); - } - } - } - - void readFromFileLocked() { - if (!mFile.exists()) { - if (DEBUG) { - Log.d(TAG, "" + mFile + " doesn't exist"); - } - return; - } - if (DEBUG) { - Log.d(TAG, "Reading from " + mFile); - } - final AtomicFile f = new AtomicFile(mFile); - InputStream input = null; - try { - input = f.openRead(); - final TypedXmlPullParser parser = Xml.resolvePullParser(input); - - int type; - int depth = 0; - while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) { - switch (type) { - case TypedXmlPullParser.START_TAG: - depth++; - break; - case TypedXmlPullParser.END_TAG: - depth--; - // fallthrough - default: - continue; - } - // Check the root tag - final String tag = parser.getName(); - if (depth == 1) { - if (!TAG_ROOT.equals(tag)) { - Slog.e(TAG, "Invalid root tag: " + tag); - return; - } - continue; - } - // readInner() will only see START_TAG at depth >= 2. - if (!readInner(parser, depth, tag)) { - return; // Error - } - } - } catch (XmlPullParserException | IOException e) { - Slog.e(TAG, "Error parsing owners information file", e); - } finally { - IoUtils.closeQuietly(input); - } - } - - abstract void writeInner(TypedXmlSerializer out) throws IOException; - - abstract boolean readInner(TypedXmlPullParser parser, int depth, String tag); - } - - private class DeviceOwnerReadWriter extends FileReadWriter { - - protected DeviceOwnerReadWriter() { - super(getDeviceOwnerFile()); - } - - @Override - boolean shouldWrite() { - return (mDeviceOwner != null) || (mSystemUpdatePolicy != null) - || (mSystemUpdateInfo != null); - } - - @Override - void writeInner(TypedXmlSerializer out) throws IOException { - if (mDeviceOwner != null) { - mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER); - out.startTag(null, TAG_DEVICE_OWNER_CONTEXT); - out.attributeInt(null, ATTR_USERID, mDeviceOwnerUserId); - out.endTag(null, TAG_DEVICE_OWNER_CONTEXT); - - } - - if (!mDeviceOwnerTypes.isEmpty()) { - for (ArrayMap.Entry entry : mDeviceOwnerTypes.entrySet()) { - out.startTag(null, TAG_DEVICE_OWNER_TYPE); - out.attribute(null, ATTR_PACKAGE, entry.getKey()); - out.attributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE, entry.getValue()); - out.endTag(null, TAG_DEVICE_OWNER_TYPE); - } - } - - if (!mDeviceOwnerProtectedPackages.isEmpty()) { - for (ArrayMap.Entry> entry : - mDeviceOwnerProtectedPackages.entrySet()) { - List protectedPackages = entry.getValue(); - - out.startTag(null, TAG_DEVICE_OWNER_PROTECTED_PACKAGES); - out.attribute(null, ATTR_PACKAGE, entry.getKey()); - out.attributeInt(null, ATTR_SIZE, protectedPackages.size()); - for (int i = 0, size = protectedPackages.size(); i < size; i++) { - out.attribute(null, ATTR_NAME + i, protectedPackages.get(i)); - } - out.endTag(null, TAG_DEVICE_OWNER_PROTECTED_PACKAGES); - } - } - - if (mSystemUpdatePolicy != null) { - out.startTag(null, TAG_SYSTEM_UPDATE_POLICY); - mSystemUpdatePolicy.saveToXml(out); - out.endTag(null, TAG_SYSTEM_UPDATE_POLICY); - } - - if (mSystemUpdateInfo != null) { - mSystemUpdateInfo.writeToXml(out, TAG_PENDING_OTA_INFO); - } - - if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) { - out.startTag(null, TAG_FREEZE_PERIOD_RECORD); - if (mSystemUpdateFreezeStart != null) { - out.attribute(null, ATTR_FREEZE_RECORD_START, - mSystemUpdateFreezeStart.toString()); - } - if (mSystemUpdateFreezeEnd != null) { - out.attribute(null, ATTR_FREEZE_RECORD_END, mSystemUpdateFreezeEnd.toString()); - } - out.endTag(null, TAG_FREEZE_PERIOD_RECORD); - } - } - - @Override - boolean readInner(TypedXmlPullParser parser, int depth, String tag) { - if (depth > 2) { - return true; // Ignore - } - switch (tag) { - case TAG_DEVICE_OWNER: - mDeviceOwner = OwnerInfo.readFromXml(parser); - mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default - break; - case TAG_DEVICE_OWNER_CONTEXT: { - mDeviceOwnerUserId = parser.getAttributeInt(null, ATTR_USERID, - mDeviceOwnerUserId); - break; - } - case TAG_SYSTEM_UPDATE_POLICY: - mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser); - break; - case TAG_PENDING_OTA_INFO: - mSystemUpdateInfo = SystemUpdateInfo.readFromXml(parser); - break; - case TAG_FREEZE_PERIOD_RECORD: - String startDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_START); - String endDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_END); - if (startDate != null && endDate != null) { - mSystemUpdateFreezeStart = LocalDate.parse(startDate); - mSystemUpdateFreezeEnd = LocalDate.parse(endDate); - if (mSystemUpdateFreezeStart.isAfter(mSystemUpdateFreezeEnd)) { - Slog.e(TAG, "Invalid system update freeze record loaded"); - mSystemUpdateFreezeStart = null; - mSystemUpdateFreezeEnd = null; - } - } - break; - case TAG_DEVICE_OWNER_TYPE: - String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); - int deviceOwnerType = parser.getAttributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE, - DEVICE_OWNER_TYPE_DEFAULT); - mDeviceOwnerTypes.put(packageName, deviceOwnerType); - break; - case TAG_DEVICE_OWNER_PROTECTED_PACKAGES: - packageName = parser.getAttributeValue(null, ATTR_PACKAGE); - int protectedPackagesSize = parser.getAttributeInt(null, ATTR_SIZE, 0); - List protectedPackages = new ArrayList<>(); - for (int i = 0; i < protectedPackagesSize; i++) { - protectedPackages.add(parser.getAttributeValue(null, ATTR_NAME + i)); - } - mDeviceOwnerProtectedPackages.put(packageName, protectedPackages); - break; - default: - Slog.e(TAG, "Unexpected tag: " + tag); - return false; - } - return true; - } - } - - private class ProfileOwnerReadWriter extends FileReadWriter { - private final int mUserId; - - ProfileOwnerReadWriter(int userId) { - super(getProfileOwnerFile(userId)); - mUserId = userId; - } - - @Override - boolean shouldWrite() { - return mProfileOwners.get(mUserId) != null; - } - - @Override - void writeInner(TypedXmlSerializer out) throws IOException { - final OwnerInfo profileOwner = mProfileOwners.get(mUserId); - if (profileOwner != null) { - profileOwner.writeToXml(out, TAG_PROFILE_OWNER); - } - } - - @Override - boolean readInner(TypedXmlPullParser parser, int depth, String tag) { - if (depth > 2) { - return true; // Ignore - } - switch (tag) { - case TAG_PROFILE_OWNER: - mProfileOwners.put(mUserId, OwnerInfo.readFromXml(parser)); - break; - default: - Slog.e(TAG, "Unexpected tag: " + tag); - return false; - - } - return true; - } - } - - static class OwnerInfo { - public final String name; - public final String packageName; - public final ComponentName admin; - public String remoteBugreportUri; - public String remoteBugreportHash; - public boolean isOrganizationOwnedDevice; - - OwnerInfo(String name, ComponentName admin, - String remoteBugreportUri, String remoteBugreportHash, - boolean isOrganizationOwnedDevice) { - this.name = name; - this.admin = admin; - this.packageName = admin.getPackageName(); - this.remoteBugreportUri = remoteBugreportUri; - this.remoteBugreportHash = remoteBugreportHash; - this.isOrganizationOwnedDevice = isOrganizationOwnedDevice; - } - - public void writeToXml(TypedXmlSerializer out, String tag) throws IOException { - out.startTag(null, tag); - if (name != null) { - out.attribute(null, ATTR_NAME, name); - } - if (admin != null) { - out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString()); - } - if (remoteBugreportUri != null) { - out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri); - } - if (remoteBugreportHash != null) { - out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash); - } - if (isOrganizationOwnedDevice) { - out.attributeBoolean(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE, - isOrganizationOwnedDevice); - } - out.endTag(null, tag); - } - - public static OwnerInfo readFromXml(TypedXmlPullParser parser) { - final String name = parser.getAttributeValue(null, ATTR_NAME); - final String componentName = - parser.getAttributeValue(null, ATTR_COMPONENT_NAME); - final String remoteBugreportUri = parser.getAttributeValue(null, - ATTR_REMOTE_BUGREPORT_URI); - final String remoteBugreportHash = parser.getAttributeValue(null, - ATTR_REMOTE_BUGREPORT_HASH); - final String canAccessDeviceIdsStr = - parser.getAttributeValue(null, ATTR_CAN_ACCESS_DEVICE_IDS); - final boolean canAccessDeviceIds = - ("true".equals(canAccessDeviceIdsStr)); - final String isOrgOwnedDeviceStr = - parser.getAttributeValue(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE); - final boolean isOrgOwnedDevice = - ("true".equals(isOrgOwnedDeviceStr)) | canAccessDeviceIds; - - if (componentName == null) { - Slog.e(TAG, "Owner component not found"); - return null; - } - final ComponentName admin = ComponentName.unflattenFromString(componentName); - if (admin == null) { - Slog.e(TAG, "Owner component not parsable: " + componentName); - return null; - } - - return new OwnerInfo( - name, admin, remoteBugreportUri, remoteBugreportHash, isOrgOwnedDevice); - } - - public void dump(IndentingPrintWriter pw) { - pw.println("admin=" + admin); - pw.println("name=" + name); - pw.println("package=" + packageName); - pw.println("isOrganizationOwnedDevice=" + isOrganizationOwnedDevice); - } - } - public void dump(IndentingPrintWriter pw) { - boolean needBlank = false; - if (mDeviceOwner != null) { - pw.println("Device Owner: "); - pw.increaseIndent(); - mDeviceOwner.dump(pw); - pw.println("User ID: " + mDeviceOwnerUserId); - pw.decreaseIndent(); - needBlank = true; - } - if (mSystemUpdatePolicy != null) { - if (needBlank) { - pw.println(); - } - pw.println("System Update Policy: " + mSystemUpdatePolicy); - needBlank = true; - } - if (mProfileOwners != null) { - for (Map.Entry entry : mProfileOwners.entrySet()) { - if (needBlank) { - pw.println(); - } - pw.println("Profile Owner (User " + entry.getKey() + "): "); - pw.increaseIndent(); - entry.getValue().dump(pw); - pw.decreaseIndent(); - needBlank = true; - } - } - if (mSystemUpdateInfo != null) { - if (needBlank) { - pw.println(); - } - pw.println("Pending System Update: " + mSystemUpdateInfo); - needBlank = true; - } - if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) { - if (needBlank) { - pw.println(); - } - pw.println("System update freeze record: " - + getSystemUpdateFreezePeriodRecordAsString()); - needBlank = true; + synchronized (mData) { + mData.dump(pw); } } @VisibleForTesting File getDeviceOwnerFile() { - return new File(mInjector.environmentGetDataSystemDirectory(), DEVICE_OWNER_XML); + return mData.getDeviceOwnerFile(); } @VisibleForTesting File getProfileOwnerFile(int userId) { - return new File(mInjector.environmentGetUserSystemDirectory(userId), PROFILE_OWNER_XML); - } - - @VisibleForTesting - public static class Injector { - File environmentGetDataSystemDirectory() { - return Environment.getDataSystemDirectory(); - } - - File environmentGetUserSystemDirectory(int userId) { - return Environment.getUserSystemDirectory(userId); - } + return mData.getProfileOwnerFile(userId); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java new file mode 100644 index 0000000000000..06a5b9ea2d171 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2022 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.devicepolicy; + +import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT; + +import android.annotation.Nullable; +import android.app.admin.SystemUpdateInfo; +import android.app.admin.SystemUpdatePolicy; +import android.content.ComponentName; +import android.os.Environment; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.AtomicFile; +import android.util.IndentingPrintWriter; +import android.util.Log; +import android.util.Slog; +import android.util.TypedXmlPullParser; +import android.util.TypedXmlSerializer; +import android.util.Xml; + +import com.android.internal.annotations.VisibleForTesting; + +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +class OwnersData { + private static final String TAG = "DevicePolicyManagerService"; + + private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE + + // XML storing device owner info, system update policy and pending OTA update information. + private static final String DEVICE_OWNER_XML = "device_owner_2.xml"; + private static final String PROFILE_OWNER_XML = "profile_owner.xml"; + + private static final String TAG_ROOT = "root"; + private static final String TAG_DEVICE_OWNER = "device-owner"; + private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy"; + private static final String TAG_FREEZE_PERIOD_RECORD = "freeze-record"; + private static final String TAG_PENDING_OTA_INFO = "pending-ota-info"; + private static final String TAG_PROFILE_OWNER = "profile-owner"; + // Holds "context" for device-owner, this must not be show up before device-owner. + private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context"; + private static final String TAG_DEVICE_OWNER_TYPE = "device-owner-type"; + private static final String TAG_DEVICE_OWNER_PROTECTED_PACKAGES = + "device-owner-protected-packages"; + + private static final String ATTR_NAME = "name"; + private static final String ATTR_PACKAGE = "package"; + private static final String ATTR_COMPONENT_NAME = "component"; + private static final String ATTR_SIZE = "size"; + private static final String ATTR_REMOTE_BUGREPORT_URI = "remoteBugreportUri"; + private static final String ATTR_REMOTE_BUGREPORT_HASH = "remoteBugreportHash"; + private static final String ATTR_USERID = "userId"; + private static final String ATTR_FREEZE_RECORD_START = "start"; + private static final String ATTR_FREEZE_RECORD_END = "end"; + // Legacy attribute, its presence would mean the profile owner associated with it is + // managing a profile on an organization-owned device. + private static final String ATTR_CAN_ACCESS_DEVICE_IDS = "canAccessDeviceIds"; + // New attribute for profile owner of organization-owned device. + private static final String ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE = + "isPoOrganizationOwnedDevice"; + private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value"; + + // Internal state for the device owner package. + OwnerInfo mDeviceOwner; + int mDeviceOwnerUserId = UserHandle.USER_NULL; + + // Device owner type for a managed device. + final ArrayMap mDeviceOwnerTypes = new ArrayMap<>(); + + final ArrayMap> mDeviceOwnerProtectedPackages = new ArrayMap<>(); + + + // Internal state for the profile owner packages. + final ArrayMap mProfileOwners = new ArrayMap<>(); + + // Local system update policy controllable by device owner. + SystemUpdatePolicy mSystemUpdatePolicy; + LocalDate mSystemUpdateFreezeStart; + LocalDate mSystemUpdateFreezeEnd; + + // Pending OTA info if there is one. + @Nullable + SystemUpdateInfo mSystemUpdateInfo; + private final Injector mInjector; + + OwnersData(Injector injector) { + mInjector = injector; + } + + void load(int[] allUsers) { + new DeviceOwnerReadWriter().readFromFileLocked(); + + for (int userId : allUsers) { + new ProfileOwnerReadWriter(userId).readFromFileLocked(); + } + + OwnerInfo profileOwner = mProfileOwners.get(mDeviceOwnerUserId); + ComponentName admin = profileOwner != null ? profileOwner.admin : null; + if (mDeviceOwner != null && admin != null) { + Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported", + mDeviceOwnerUserId)); + } + } + + void writeDeviceOwner() { + if (DEBUG) { + Log.d(TAG, "Writing to device owner file"); + } + new DeviceOwnerReadWriter().writeToFileLocked(); + } + + void writeProfileOwner(int userId) { + if (DEBUG) { + Log.d(TAG, "Writing to profile owner file for user " + userId); + } + new ProfileOwnerReadWriter(userId).writeToFileLocked(); + } + + void dump(IndentingPrintWriter pw) { + boolean needBlank = false; + if (mDeviceOwner != null) { + pw.println("Device Owner: "); + pw.increaseIndent(); + mDeviceOwner.dump(pw); + pw.println("User ID: " + mDeviceOwnerUserId); + pw.decreaseIndent(); + needBlank = true; + } + if (mSystemUpdatePolicy != null) { + if (needBlank) { + pw.println(); + } + pw.println("System Update Policy: " + mSystemUpdatePolicy); + needBlank = true; + } + if (mProfileOwners != null) { + for (Map.Entry entry : mProfileOwners.entrySet()) { + if (needBlank) { + pw.println(); + } + pw.println("Profile Owner (User " + entry.getKey() + "): "); + pw.increaseIndent(); + entry.getValue().dump(pw); + pw.decreaseIndent(); + needBlank = true; + } + } + if (mSystemUpdateInfo != null) { + if (needBlank) { + pw.println(); + } + pw.println("Pending System Update: " + mSystemUpdateInfo); + needBlank = true; + } + if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) { + if (needBlank) { + pw.println(); + } + pw.println("System update freeze record: " + + getSystemUpdateFreezePeriodRecordAsString()); + needBlank = true; + } + } + + String getSystemUpdateFreezePeriodRecordAsString() { + StringBuilder freezePeriodRecord = new StringBuilder(); + freezePeriodRecord.append("start: "); + if (mSystemUpdateFreezeStart != null) { + freezePeriodRecord.append(mSystemUpdateFreezeStart.toString()); + } else { + freezePeriodRecord.append("null"); + } + freezePeriodRecord.append("; end: "); + if (mSystemUpdateFreezeEnd != null) { + freezePeriodRecord.append(mSystemUpdateFreezeEnd.toString()); + } else { + freezePeriodRecord.append("null"); + } + return freezePeriodRecord.toString(); + } + + @VisibleForTesting + File getDeviceOwnerFile() { + return new File(mInjector.environmentGetDataSystemDirectory(), DEVICE_OWNER_XML); + } + + @VisibleForTesting + File getProfileOwnerFile(int userId) { + return new File(mInjector.environmentGetUserSystemDirectory(userId), PROFILE_OWNER_XML); + } + + private abstract static class FileReadWriter { + private final File mFile; + + protected FileReadWriter(File file) { + mFile = file; + } + + abstract boolean shouldWrite(); + + void writeToFileLocked() { + if (!shouldWrite()) { + if (DEBUG) { + Log.d(TAG, "No need to write to " + mFile); + } + // No contents, remove the file. + if (mFile.exists()) { + if (DEBUG) { + Log.d(TAG, "Deleting existing " + mFile); + } + if (!mFile.delete()) { + Slog.e(TAG, "Failed to remove " + mFile.getPath()); + } + } + return; + } + if (DEBUG) { + Log.d(TAG, "Writing to " + mFile); + } + + final AtomicFile f = new AtomicFile(mFile); + FileOutputStream outputStream = null; + try { + outputStream = f.startWrite(); + final TypedXmlSerializer out = Xml.resolveSerializer(outputStream); + + // Root tag + out.startDocument(null, true); + out.startTag(null, TAG_ROOT); + + // Actual content + writeInner(out); + + // Close root + out.endTag(null, TAG_ROOT); + out.endDocument(); + out.flush(); + + // Commit the content. + f.finishWrite(outputStream); + outputStream = null; + + } catch (IOException e) { + Slog.e(TAG, "Exception when writing", e); + if (outputStream != null) { + f.failWrite(outputStream); + } + } + } + + void readFromFileLocked() { + if (!mFile.exists()) { + if (DEBUG) { + Log.d(TAG, "" + mFile + " doesn't exist"); + } + return; + } + if (DEBUG) { + Log.d(TAG, "Reading from " + mFile); + } + final AtomicFile f = new AtomicFile(mFile); + InputStream input = null; + try { + input = f.openRead(); + final TypedXmlPullParser parser = Xml.resolvePullParser(input); + + int type; + int depth = 0; + while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) { + switch (type) { + case TypedXmlPullParser.START_TAG: + depth++; + break; + case TypedXmlPullParser.END_TAG: + depth--; + // fallthrough + default: + continue; + } + // Check the root tag + final String tag = parser.getName(); + if (depth == 1) { + if (!TAG_ROOT.equals(tag)) { + Slog.e(TAG, "Invalid root tag: " + tag); + return; + } + continue; + } + // readInner() will only see START_TAG at depth >= 2. + if (!readInner(parser, depth, tag)) { + return; // Error + } + } + } catch (XmlPullParserException | IOException e) { + Slog.e(TAG, "Error parsing owners information file", e); + } finally { + IoUtils.closeQuietly(input); + } + } + + abstract void writeInner(TypedXmlSerializer out) throws IOException; + + abstract boolean readInner(TypedXmlPullParser parser, int depth, String tag); + } + + private class DeviceOwnerReadWriter extends FileReadWriter { + + protected DeviceOwnerReadWriter() { + super(getDeviceOwnerFile()); + } + + @Override + boolean shouldWrite() { + return (mDeviceOwner != null) || (mSystemUpdatePolicy != null) + || (mSystemUpdateInfo != null); + } + + @Override + void writeInner(TypedXmlSerializer out) throws IOException { + if (mDeviceOwner != null) { + mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER); + out.startTag(null, TAG_DEVICE_OWNER_CONTEXT); + out.attributeInt(null, ATTR_USERID, mDeviceOwnerUserId); + out.endTag(null, TAG_DEVICE_OWNER_CONTEXT); + + } + + if (!mDeviceOwnerTypes.isEmpty()) { + for (ArrayMap.Entry entry : mDeviceOwnerTypes.entrySet()) { + out.startTag(null, TAG_DEVICE_OWNER_TYPE); + out.attribute(null, ATTR_PACKAGE, entry.getKey()); + out.attributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE, entry.getValue()); + out.endTag(null, TAG_DEVICE_OWNER_TYPE); + } + } + + if (!mDeviceOwnerProtectedPackages.isEmpty()) { + for (ArrayMap.Entry> entry : + mDeviceOwnerProtectedPackages.entrySet()) { + List protectedPackages = entry.getValue(); + + out.startTag(null, TAG_DEVICE_OWNER_PROTECTED_PACKAGES); + out.attribute(null, ATTR_PACKAGE, entry.getKey()); + out.attributeInt(null, ATTR_SIZE, protectedPackages.size()); + for (int i = 0, size = protectedPackages.size(); i < size; i++) { + out.attribute(null, ATTR_NAME + i, protectedPackages.get(i)); + } + out.endTag(null, TAG_DEVICE_OWNER_PROTECTED_PACKAGES); + } + } + + if (mSystemUpdatePolicy != null) { + out.startTag(null, TAG_SYSTEM_UPDATE_POLICY); + mSystemUpdatePolicy.saveToXml(out); + out.endTag(null, TAG_SYSTEM_UPDATE_POLICY); + } + + if (mSystemUpdateInfo != null) { + mSystemUpdateInfo.writeToXml(out, TAG_PENDING_OTA_INFO); + } + + if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) { + out.startTag(null, TAG_FREEZE_PERIOD_RECORD); + if (mSystemUpdateFreezeStart != null) { + out.attribute( + null, ATTR_FREEZE_RECORD_START, mSystemUpdateFreezeStart.toString()); + } + if (mSystemUpdateFreezeEnd != null) { + out.attribute(null, ATTR_FREEZE_RECORD_END, mSystemUpdateFreezeEnd.toString()); + } + out.endTag(null, TAG_FREEZE_PERIOD_RECORD); + } + } + + @Override + boolean readInner(TypedXmlPullParser parser, int depth, String tag) { + if (depth > 2) { + return true; // Ignore + } + switch (tag) { + case TAG_DEVICE_OWNER: + mDeviceOwner = OwnerInfo.readFromXml(parser); + mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default + break; + case TAG_DEVICE_OWNER_CONTEXT: { + mDeviceOwnerUserId = + parser.getAttributeInt(null, ATTR_USERID, mDeviceOwnerUserId); + break; + } + case TAG_SYSTEM_UPDATE_POLICY: + mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser); + break; + case TAG_PENDING_OTA_INFO: + mSystemUpdateInfo = SystemUpdateInfo.readFromXml(parser); + break; + case TAG_FREEZE_PERIOD_RECORD: + String startDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_START); + String endDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_END); + if (startDate != null && endDate != null) { + mSystemUpdateFreezeStart = LocalDate.parse(startDate); + mSystemUpdateFreezeEnd = LocalDate.parse(endDate); + if (mSystemUpdateFreezeStart.isAfter(mSystemUpdateFreezeEnd)) { + Slog.e(TAG, "Invalid system update freeze record loaded"); + mSystemUpdateFreezeStart = null; + mSystemUpdateFreezeEnd = null; + } + } + break; + case TAG_DEVICE_OWNER_TYPE: + String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); + int deviceOwnerType = parser.getAttributeInt( + null, ATTR_DEVICE_OWNER_TYPE_VALUE, DEVICE_OWNER_TYPE_DEFAULT); + mDeviceOwnerTypes.put(packageName, deviceOwnerType); + break; + case TAG_DEVICE_OWNER_PROTECTED_PACKAGES: + packageName = parser.getAttributeValue(null, ATTR_PACKAGE); + int protectedPackagesSize = parser.getAttributeInt(null, ATTR_SIZE, 0); + List protectedPackages = new ArrayList<>(); + for (int i = 0; i < protectedPackagesSize; i++) { + protectedPackages.add(parser.getAttributeValue(null, ATTR_NAME + i)); + } + mDeviceOwnerProtectedPackages.put(packageName, protectedPackages); + break; + default: + Slog.e(TAG, "Unexpected tag: " + tag); + return false; + + } + return true; + } + } + + private class ProfileOwnerReadWriter extends FileReadWriter { + private final int mUserId; + + ProfileOwnerReadWriter(int userId) { + super(getProfileOwnerFile(userId)); + mUserId = userId; + } + + @Override + boolean shouldWrite() { + return mProfileOwners.get(mUserId) != null; + } + + @Override + void writeInner(TypedXmlSerializer out) throws IOException { + final OwnerInfo profileOwner = mProfileOwners.get(mUserId); + if (profileOwner != null) { + profileOwner.writeToXml(out, TAG_PROFILE_OWNER); + } + } + + @Override + boolean readInner(TypedXmlPullParser parser, int depth, String tag) { + if (depth > 2) { + return true; // Ignore + } + switch (tag) { + case TAG_PROFILE_OWNER: + mProfileOwners.put(mUserId, OwnerInfo.readFromXml(parser)); + break; + default: + Slog.e(TAG, "Unexpected tag: " + tag); + return false; + + } + return true; + } + } + + static class OwnerInfo { + public final String name; + public final String packageName; + public final ComponentName admin; + public String remoteBugreportUri; + public String remoteBugreportHash; + public boolean isOrganizationOwnedDevice; + + OwnerInfo(String name, ComponentName admin, String remoteBugreportUri, + String remoteBugreportHash, boolean isOrganizationOwnedDevice) { + this.name = name; + this.admin = admin; + this.packageName = admin.getPackageName(); + this.remoteBugreportUri = remoteBugreportUri; + this.remoteBugreportHash = remoteBugreportHash; + this.isOrganizationOwnedDevice = isOrganizationOwnedDevice; + } + + public void writeToXml(TypedXmlSerializer out, String tag) throws IOException { + out.startTag(null, tag); + if (name != null) { + out.attribute(null, ATTR_NAME, name); + } + if (admin != null) { + out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString()); + } + if (remoteBugreportUri != null) { + out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri); + } + if (remoteBugreportHash != null) { + out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash); + } + if (isOrganizationOwnedDevice) { + out.attributeBoolean( + null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE, isOrganizationOwnedDevice); + } + out.endTag(null, tag); + } + + public static OwnerInfo readFromXml(TypedXmlPullParser parser) { + final String name = parser.getAttributeValue(null, ATTR_NAME); + final String componentName = parser.getAttributeValue(null, ATTR_COMPONENT_NAME); + final String remoteBugreportUri = + parser.getAttributeValue(null, ATTR_REMOTE_BUGREPORT_URI); + final String remoteBugreportHash = + parser.getAttributeValue(null, ATTR_REMOTE_BUGREPORT_HASH); + final String canAccessDeviceIdsStr = + parser.getAttributeValue(null, ATTR_CAN_ACCESS_DEVICE_IDS); + final boolean canAccessDeviceIds = "true".equals(canAccessDeviceIdsStr); + final String isOrgOwnedDeviceStr = + parser.getAttributeValue(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE); + final boolean isOrgOwnedDevice = + "true".equals(isOrgOwnedDeviceStr) | canAccessDeviceIds; + + if (componentName == null) { + Slog.e(TAG, "Owner component not found"); + return null; + } + final ComponentName admin = ComponentName.unflattenFromString(componentName); + if (admin == null) { + Slog.e(TAG, "Owner component not parsable: " + componentName); + return null; + } + + return new OwnerInfo( + name, admin, remoteBugreportUri, remoteBugreportHash, isOrgOwnedDevice); + } + + public void dump(IndentingPrintWriter pw) { + pw.println("admin=" + admin); + pw.println("name=" + name); + pw.println("package=" + packageName); + pw.println("isOrganizationOwnedDevice=" + isOrganizationOwnedDevice); + } + } + + @VisibleForTesting + static class Injector { + File environmentGetDataSystemDirectory() { + return Environment.getDataSystemDirectory(); + } + + File environmentGetUserSystemDirectory(int userId) { + return Environment.getUserSystemDirectory(userId); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index 2dbf728c577eb..bacef472bf998 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -75,7 +75,7 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi services.activityManagerInternal, new MockInjector(services)); } - static class MockInjector extends Injector { + static class MockInjector extends OwnersData.Injector { private final MockSystemServices mServices; private MockInjector(MockSystemServices services) { From 0fe6a8babd24025e4daf6f0cf51b2acbb6125e7a Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Wed, 13 Apr 2022 14:19:07 +0100 Subject: [PATCH 2/2] Use Owners in PolicyVersionUpgrader Currently PolicyVersionUpgrader operates on device_policies.xml files, that contain ActiveAdmin objects and some of the device state Owners data is accessed during the upgrade but cannot be modified thus making it impossible to migrate a field from Owners to ActiveAdmin. With this change PolicyVersionUpgrader will access Owners data directly by reading and writing XML files, which allows such field migrations and more. Also extracted path getters from DPMS Injector to reduce duplication (separate path getters were used in Owners) and make it possible to override those paths once and for all in tests. Bug: 218639412 Test: atest com.android.server.devicepolicy Change-Id: I26013c00f3422522fbf0b6b119fe23953756c6d0 --- .../DevicePolicyManagerService.java | 83 ++++++++---------- .../android/server/devicepolicy/Owners.java | 14 +-- .../server/devicepolicy/OwnersData.java | 42 ++++----- .../devicepolicy/PolicyPathProvider.java | 42 +++++++++ .../PolicyUpgraderDataProvider.java | 12 --- .../devicepolicy/PolicyVersionUpgrader.java | 55 ++++++++---- .../device_owner_2.xml | 6 ++ ...vicePolicyManagerServiceMigrationTest.java | 7 +- .../DevicePolicyManagerServiceTestable.java | 61 +++---------- .../devicepolicy/DevicePolicyManagerTest.java | 3 +- .../devicepolicy/MockSystemServices.java | 12 +++ .../server/devicepolicy/OwnersTest.java | 15 ++-- .../PolicyVersionUpgraderTest.java | 87 ++++++++----------- 13 files changed, 221 insertions(+), 218 deletions(-) create mode 100644 services/devicepolicy/java/com/android/server/devicepolicy/PolicyPathProvider.java create mode 100644 services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_owner_2.xml diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 0a426eb80c543..8a7134e24cf86 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -279,7 +279,6 @@ import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -679,6 +678,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final Context mContext; final Injector mInjector; + final PolicyPathProvider mPathProvider; final IPackageManager mIPackageManager; final IPermissionManager mIPermissionManager; final UserManager mUserManager; @@ -890,7 +890,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @GuardedBy("getLockObject()") - final SparseArray mUserData = new SparseArray<>(); + final SparseArray mUserData; @GuardedBy("getLockObject()") @@ -1365,7 +1365,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { public final Context mContext; - private @Nullable DevicePolicySafetyChecker mSafetyChecker; + @Nullable private DevicePolicySafetyChecker mSafetyChecker; Injector(Context context) { mContext = context; @@ -1384,12 +1384,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return mContext.getResources(); } - Owners newOwners() { - return new Owners(getUserManager(), getUserManagerInternal(), - getPackageManagerInternal(), getActivityTaskManagerInternal(), - getActivityManagerInternal()); - } - UserManager getUserManager() { return UserManager.get(mContext); } @@ -1595,10 +1589,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return UserHandle.getUserId(binderGetCallingUid()); } - File environmentGetUserSystemDirectory(int userId) { - return Environment.getUserSystemDirectory(userId); - } - void powerManagerGoToSleep(long time, int reason, int flags) { mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags); } @@ -1641,10 +1631,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return UserManager.isHeadlessSystemUserMode(); } - String getDevicePolicyFilePathForSystemUser() { - return "/data/system/"; - } - @SuppressWarnings("AndroidFrameworkPendingIntentMutability") PendingIntent pendingIntentGetActivityAsUser(Context context, int requestCode, @NonNull Intent intent, int flags, Bundle options, UserHandle user) { @@ -1777,14 +1763,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * Instantiates the service. */ public DevicePolicyManagerService(Context context) { - this(new Injector(context.createAttributionContext(ATTRIBUTION_TAG))); + this(new Injector( + context.createAttributionContext(ATTRIBUTION_TAG)), new PolicyPathProvider() {}); } @VisibleForTesting - DevicePolicyManagerService(Injector injector) { + DevicePolicyManagerService(Injector injector, PolicyPathProvider pathProvider) { DevicePolicyManager.disableLocalCaches(); mInjector = injector; + mPathProvider = pathProvider; mContext = Objects.requireNonNull(injector.mContext); mHandler = new Handler(Objects.requireNonNull(injector.getMyLooper())); @@ -1792,8 +1780,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mConstantsObserver.register(); mConstants = loadConstants(); - mOwners = Objects.requireNonNull(injector.newOwners()); - mUserManager = Objects.requireNonNull(injector.getUserManager()); mUserManagerInternal = Objects.requireNonNull(injector.getUserManagerInternal()); mUsageStatsManagerInternal = Objects.requireNonNull( @@ -1831,12 +1817,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // "Lite" interface is available even when the device doesn't have the feature LocalServices.addService(DevicePolicyManagerLiteInternal.class, mLocalService); + + // Policy version upgrade must not depend on either mOwners or mUserData, so they are + // initialized only after performing the upgrade. + if (mHasFeature) { + performPolicyVersionUpgrade(); + } + mUserData = new SparseArray<>(); + mOwners = makeOwners(injector, pathProvider); + if (!mHasFeature) { // Skip the rest of the initialization mSetupContentObserver = null; return; } + loadOwners(); + IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BOOT_COMPLETED); filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION); @@ -1872,16 +1869,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { new RestrictionsListener(mContext, mUserManagerInternal, this)); mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener()); - loadOwners(); - - performPolicyVersionUpgrade(); - mDeviceManagementResourcesProvider.load(); // The binder caches are not enabled until the first invalidation. invalidateBinderCaches(); } + private Owners makeOwners(Injector injector, PolicyPathProvider pathProvider) { + return new Owners(injector.getUserManager(), injector.getUserManagerInternal(), + injector.getPackageManagerInternal(), + injector.getActivityTaskManagerInternal(), + injector.getActivityManagerInternal(), pathProvider); + } + /** * Invalidate the binder API caches. The invalidation itself does not require any * locking, but this specific call should be protected by getLockObject() to ensure @@ -1975,8 +1975,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mUserData.remove(userHandle); } - File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle), - DEVICE_POLICIES_XML); + File policyFile = + new File(mPathProvider.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML); policyFile.delete(); Slogf.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); } @@ -2879,8 +2879,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private File getPolicyFileDirectory(@UserIdInt int userId) { return userId == UserHandle.USER_SYSTEM - ? new File(mInjector.getDevicePolicyFilePathForSystemUser()) - : mInjector.environmentGetUserSystemDirectory(userId); + ? mPathProvider.getDataSystemDirectory() + : mPathProvider.getUserSystemDirectory(userId); } private JournaledFile makeJournaledFile(@UserIdInt int userId, String fileName) { @@ -3087,13 +3087,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { updateUsbDataSignal(); } + // TODO(b/230841522) Make it static. private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider { - @Override - public boolean isDeviceOwner(int userId, ComponentName who) { - return mOwners.isDeviceOwnerUserId(userId) - && mOwners.getDeviceOwnerComponent().equals(who); - } - @Override public boolean storageManagerIsFileBasedEncryptionEnabled() { return mInjector.storageManagerIsFileBasedEncryptionEnabled(); @@ -3109,15 +3104,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return DevicePolicyManagerService.this.makeJournaledFile(userId, POLICIES_VERSION_XML); } - @Override - public ComponentName getOwnerComponent(int userId) { - return DevicePolicyManagerService.this.getOwnerComponent(userId); - } - @Override public Function getAdminInfoSupplier(int userId) { - return component -> findAdmin(component, userId, /* throwForMissingPermission= */ - false); + return component -> + findAdmin(component, userId, /* throwForMissingPermission= */ false); } @Override @@ -3128,7 +3118,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void performPolicyVersionUpgrade() { - PolicyVersionUpgrader upgrader = new PolicyVersionUpgrader(new DpmsUpgradeDataProvider()); + PolicyVersionUpgrader upgrader = new PolicyVersionUpgrader( + new DpmsUpgradeDataProvider(), mPathProvider); upgrader.upgradePolicy(DPMS_VERSION); } @@ -16280,7 +16271,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { final int callingUserId = caller.getUserId(); final File bundleFile = new File( - mInjector.environmentGetUserSystemDirectory(callingUserId), + mPathProvider.getUserSystemDirectory(callingUserId), TRANSFER_OWNERSHIP_PARAMETERS_XML); if (!bundleFile.exists()) { return null; @@ -16474,7 +16465,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @VisibleForTesting void saveTransferOwnershipBundleLocked(PersistableBundle bundle, int userId) { final File parametersFile = new File( - mInjector.environmentGetUserSystemDirectory(userId), + mPathProvider.getUserSystemDirectory(userId), TRANSFER_OWNERSHIP_PARAMETERS_XML); final AtomicFile atomicFile = new AtomicFile(parametersFile); FileOutputStream stream = null; @@ -16496,7 +16487,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } void deleteTransferOwnershipBundleLocked(int userId) { - final File parametersFile = new File(mInjector.environmentGetUserSystemDirectory(userId), + final File parametersFile = new File(mPathProvider.getUserSystemDirectory(userId), TRANSFER_OWNERSHIP_PARAMETERS_XML); parametersFile.delete(); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java index 09d5c4a60c820..d1c6b3411b202 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java @@ -42,7 +42,6 @@ import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; -import com.android.server.devicepolicy.OwnersData.Injector; import com.android.server.devicepolicy.OwnersData.OwnerInfo; import com.android.server.pm.UserManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; @@ -78,28 +77,19 @@ class Owners { private boolean mSystemReady; - public Owners(UserManager userManager, - UserManagerInternal userManagerInternal, - PackageManagerInternal packageManagerInternal, - ActivityTaskManagerInternal activityTaskManagerInternal, - ActivityManagerInternal activityManagerInternal) { - this(userManager, userManagerInternal, packageManagerInternal, - activityTaskManagerInternal, activityManagerInternal, new Injector()); - } - @VisibleForTesting Owners(UserManager userManager, UserManagerInternal userManagerInternal, PackageManagerInternal packageManagerInternal, ActivityTaskManagerInternal activityTaskManagerInternal, ActivityManagerInternal activityManagerInternal, - Injector injector) { + PolicyPathProvider pathProvider) { mUserManager = userManager; mUserManagerInternal = userManagerInternal; mPackageManagerInternal = packageManagerInternal; mActivityTaskManagerInternal = activityTaskManagerInternal; mActivityManagerInternal = activityManagerInternal; - mData = new OwnersData(injector); + mData = new OwnersData(pathProvider); } /** diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java index 06a5b9ea2d171..4fe4f0d83f1ae 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java @@ -21,7 +21,6 @@ import android.annotation.Nullable; import android.app.admin.SystemUpdateInfo; import android.app.admin.SystemUpdatePolicy; import android.content.ComponentName; -import android.os.Environment; import android.os.UserHandle; import android.util.ArrayMap; import android.util.AtomicFile; @@ -106,10 +105,10 @@ class OwnersData { // Pending OTA info if there is one. @Nullable SystemUpdateInfo mSystemUpdateInfo; - private final Injector mInjector; + private final PolicyPathProvider mPathProvider; - OwnersData(Injector injector) { - mInjector = injector; + OwnersData(PolicyPathProvider pathProvider) { + mPathProvider = pathProvider; } void load(int[] allUsers) { @@ -127,18 +126,24 @@ class OwnersData { } } - void writeDeviceOwner() { + /** + * @return true upon success, false otherwise. + */ + boolean writeDeviceOwner() { if (DEBUG) { Log.d(TAG, "Writing to device owner file"); } - new DeviceOwnerReadWriter().writeToFileLocked(); + return new DeviceOwnerReadWriter().writeToFileLocked(); } - void writeProfileOwner(int userId) { + /** + * @return true upon success, false otherwise. + */ + boolean writeProfileOwner(int userId) { if (DEBUG) { Log.d(TAG, "Writing to profile owner file for user " + userId); } - new ProfileOwnerReadWriter(userId).writeToFileLocked(); + return new ProfileOwnerReadWriter(userId).writeToFileLocked(); } void dump(IndentingPrintWriter pw) { @@ -206,12 +211,12 @@ class OwnersData { @VisibleForTesting File getDeviceOwnerFile() { - return new File(mInjector.environmentGetDataSystemDirectory(), DEVICE_OWNER_XML); + return new File(mPathProvider.getDataSystemDirectory(), DEVICE_OWNER_XML); } @VisibleForTesting File getProfileOwnerFile(int userId) { - return new File(mInjector.environmentGetUserSystemDirectory(userId), PROFILE_OWNER_XML); + return new File(mPathProvider.getUserSystemDirectory(userId), PROFILE_OWNER_XML); } private abstract static class FileReadWriter { @@ -223,7 +228,7 @@ class OwnersData { abstract boolean shouldWrite(); - void writeToFileLocked() { + boolean writeToFileLocked() { if (!shouldWrite()) { if (DEBUG) { Log.d(TAG, "No need to write to " + mFile); @@ -237,7 +242,7 @@ class OwnersData { Slog.e(TAG, "Failed to remove " + mFile.getPath()); } } - return; + return true; } if (DEBUG) { Log.d(TAG, "Writing to " + mFile); @@ -270,7 +275,9 @@ class OwnersData { if (outputStream != null) { f.failWrite(outputStream); } + return false; } + return true; } void readFromFileLocked() { @@ -569,15 +576,4 @@ class OwnersData { pw.println("isOrganizationOwnedDevice=" + isOrganizationOwnedDevice); } } - - @VisibleForTesting - static class Injector { - File environmentGetDataSystemDirectory() { - return Environment.getDataSystemDirectory(); - } - - File environmentGetUserSystemDirectory(int userId) { - return Environment.getUserSystemDirectory(userId); - } - } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyPathProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyPathProvider.java new file mode 100644 index 0000000000000..96cc0e5323efa --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyPathProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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.devicepolicy; + +import android.os.Environment; + +import java.io.File; + +/** + * Interface providing directories for various DPMS files. + */ +public interface PolicyPathProvider { + /** + * Returns policy data directory for system user, typically /data/system + * Used for SYSTEM_USER policies, device owner file and policy version file. + */ + default File getDataSystemDirectory() { + return Environment.getDataSystemDirectory(); + } + + /** + * Returns policy data directory for a given user, typically /data/system/users/$userId + * Used for non-system user policies and profile owner files. + */ + default File getUserSystemDirectory(int userId) { + return Environment.getUserSystemDirectory(userId); + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java index 19a7659f4d608..7b7a454fc9454 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java @@ -16,7 +16,6 @@ package com.android.server.devicepolicy; -import android.annotation.Nullable; import android.app.admin.DeviceAdminInfo; import android.content.ComponentName; @@ -29,12 +28,6 @@ import java.util.function.Function; * to go through the upgrade process. */ public interface PolicyUpgraderDataProvider { - /** - * Returns true if the provided {@code userId} is a device owner. May affect some policy - * defaults. - */ - boolean isDeviceOwner(int userId, ComponentName who); - /** * Returns true if the storage manager indicates file-based encryption is enabled. */ @@ -50,11 +43,6 @@ public interface PolicyUpgraderDataProvider { */ JournaledFile makePoliciesVersionJournaledFile(int userId); - /** - * Returns the {@code ComponentName} of the owner component for a user. - */ - @Nullable ComponentName getOwnerComponent(int userId); - /** * Returns a function which provides the component name and device admin info for a given * user. diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java index f0ceb311cd8b8..7556d690f6fd0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java @@ -16,10 +16,12 @@ package com.android.server.devicepolicy; +import android.content.ComponentName; import android.os.UserHandle; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.JournaledFile; import java.io.File; @@ -50,16 +52,16 @@ public class PolicyVersionUpgrader { private static final String LOG_TAG = "DevicePolicyManager"; private static final boolean VERBOSE_LOG = DevicePolicyManagerService.VERBOSE_LOG; private final PolicyUpgraderDataProvider mProvider; + private final PolicyPathProvider mPathProvider; - public PolicyVersionUpgrader(PolicyUpgraderDataProvider provider) { + @VisibleForTesting + PolicyVersionUpgrader(PolicyUpgraderDataProvider provider, PolicyPathProvider pathProvider) { mProvider = provider; + mPathProvider = pathProvider; } - /** * Performs the upgrade steps for all users on the system. * - * @param allUsers List of all user IDs on the system, including disabled users, as well as - * managed profile user IDs. * @param dpmsVersion The version to upgrade to. */ public void upgradePolicy(int dpmsVersion) { @@ -71,11 +73,13 @@ public class PolicyVersionUpgrader { } final int[] allUsers = mProvider.getUsersForUpgrade(); + final OwnersData ownersData = loadOwners(allUsers); - //NOTE: The current version is provided in case the XML file format changes in a + // NOTE: The current version is provided in case the XML file format changes in a // non-backwards-compatible way, so that DeviceAdminData could load it with // old tags, for example. - final SparseArray allUsersData = loadAllUsersData(allUsers, oldVersion); + final SparseArray allUsersData = + loadAllUsersData(allUsers, oldVersion, ownersData); int currentVersion = oldVersion; if (currentVersion == 0) { @@ -96,7 +100,9 @@ public class PolicyVersionUpgrader { continue; } for (ActiveAdmin admin : userData.mAdminList) { - if (mProvider.isDeviceOwner(userId, admin.info.getComponent())) { + if (ownersData.mDeviceOwnerUserId == userId + && ownersData.mDeviceOwner != null + && ownersData.mDeviceOwner.admin.equals(admin.info.getComponent())) { Slog.i(LOG_TAG, String.format( "Marking Device Owner in user %d for permission grant ", userId)); admin.mAdminCanGrantSensorsPermissions = true; @@ -106,15 +112,26 @@ public class PolicyVersionUpgrader { currentVersion = 2; } - writePoliciesAndVersion(allUsers, allUsersData, currentVersion); + writePoliciesAndVersion(allUsers, allUsersData, ownersData, currentVersion); + } + + private OwnersData loadOwners(int[] allUsers) { + OwnersData ownersData = new OwnersData(mPathProvider); + ownersData.load(allUsers); + return ownersData; } private void writePoliciesAndVersion(int[] allUsers, SparseArray allUsersData, - int currentVersion) { + OwnersData ownersData, int currentVersion) { boolean allWritesSuccessful = true; for (int user : allUsers) { - allWritesSuccessful = allWritesSuccessful && writeDataForUser(user, - allUsersData.get(user)); + allWritesSuccessful = + allWritesSuccessful && writeDataForUser(user, allUsersData.get(user)); + } + + allWritesSuccessful = allWritesSuccessful && ownersData.writeDeviceOwner(); + for (int user : allUsers) { + allWritesSuccessful = allWritesSuccessful && ownersData.writeProfileOwner(user); } if (allWritesSuccessful) { @@ -125,21 +142,29 @@ public class PolicyVersionUpgrader { } } - private SparseArray loadAllUsersData(int[] allUsers, int loadVersion) { + private SparseArray loadAllUsersData(int[] allUsers, int loadVersion, + OwnersData ownersData) { final SparseArray allUsersData = new SparseArray<>(); for (int user: allUsers) { - allUsersData.append(user, loadDataForUser(user, loadVersion)); + ComponentName owner = null; + if (ownersData.mDeviceOwnerUserId == user && ownersData.mDeviceOwner != null) { + owner = ownersData.mDeviceOwner.admin; + } else if (ownersData.mProfileOwners.containsKey(user)) { + owner = ownersData.mProfileOwners.get(user).admin; + } + allUsersData.append(user, loadDataForUser(user, loadVersion, owner)); } return allUsersData; } - private DevicePolicyData loadDataForUser(int userId, int loadVersion) { + private DevicePolicyData loadDataForUser( + int userId, int loadVersion, ComponentName ownerComponent) { DevicePolicyData policy = new DevicePolicyData(userId); DevicePolicyData.load(policy, !mProvider.storageManagerIsFileBasedEncryptionEnabled(), mProvider.makeDevicePoliciesJournaledFile(userId), mProvider.getAdminInfoSupplier(userId), - mProvider.getOwnerComponent(userId)); + ownerComponent); return policy; } diff --git a/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_owner_2.xml b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_owner_2.xml new file mode 100644 index 0000000000000..fb0b02e038fee --- /dev/null +++ b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_owner_2.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index 8bb619f1976a1..673b696a2f997 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -289,12 +289,11 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { private void prepareAdmin1AsDo() throws Exception { setUpPackageManagerForAdmin(admin1, UserHandle.getUid(USER_SYSTEM, COPE_ADMIN1_APP_ID)); final int xmlResource = R.raw.comp_policies_primary; + File dataSystemDirectory = getServices().pathProvider.getDataSystemDirectory(); writeInputStreamToFile(getRawStream(xmlResource), - (new File(getServices().systemUserDataDir, "device_policies.xml")) - .getAbsoluteFile()); + (new File(dataSystemDirectory, "device_policies.xml")).getAbsoluteFile()); writeInputStreamToFile(getRawStream(R.raw.comp_device_owner), - (new File(getServices().dataDir, "device_owner_2.xml")) - .getAbsoluteFile()); + (new File(dataSystemDirectory, "device_owner_2.xml")).getAbsoluteFile()); } private void prepareAdmin1AsPo(int profileUserId, int targetSdk) throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index bacef472bf998..c771998de8626 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -55,8 +55,8 @@ import com.android.server.LocalServices; import com.android.server.PersistentDataBlockManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.UserManagerInternal; +import com.android.server.wm.ActivityTaskManagerInternal; -import java.io.File; import java.io.IOException; import java.util.Map; @@ -64,45 +64,16 @@ import java.util.Map; * Overrides {@link #DevicePolicyManagerService} for dependency injection. */ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerService { - /** - * Overrides {@link #Owners} for dependency injection. - */ - public static class OwnersTestable extends Owners { - - public OwnersTestable(MockSystemServices services) { - super(services.userManager, services.userManagerInternal, - services.packageManagerInternal, services.activityTaskManagerInternal, - services.activityManagerInternal, new MockInjector(services)); - } - - static class MockInjector extends OwnersData.Injector { - private final MockSystemServices mServices; - - private MockInjector(MockSystemServices services) { - mServices = services; - } - - @Override - File environmentGetDataSystemDirectory() { - return mServices.dataDir; - } - - @Override - File environmentGetUserSystemDirectory(int userId) { - return mServices.environment.getUserSystemDirectory(userId); - } - } - } - public final DpmMockContext context; - protected final MockInjector mMockInjector; + public final MockInjector mMockInjector; public DevicePolicyManagerServiceTestable(MockSystemServices services, DpmMockContext context) { - this(new MockInjector(services, context)); + this(new MockInjector(services, context), services.pathProvider); } - private DevicePolicyManagerServiceTestable(MockInjector injector) { - super(unregisterLocalServices(injector)); + private DevicePolicyManagerServiceTestable( + MockInjector injector, PolicyPathProvider pathProvider) { + super(unregisterLocalServices(injector), pathProvider); mMockInjector = injector; this.context = injector.context; } @@ -150,11 +121,6 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi this.context = context; } - @Override - Owners newOwners() { - return new OwnersTestable(services); - } - @Override UserManager getUserManager() { return services.userManager; @@ -215,6 +181,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi return services.activityManagerInternal; } + @Override + ActivityTaskManagerInternal getActivityTaskManagerInternal() { + return services.activityTaskManagerInternal; + } + @Override IPackageManager getIPackageManager() { return services.ipackageManager; @@ -268,11 +239,6 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi return services.storageManager.isFileBasedEncryptionEnabled(); } - @Override - String getDevicePolicyFilePathForSystemUser() { - return services.systemUserDataDir.getAbsolutePath() + "/"; - } - @Override long binderClearCallingIdentity() { return context.binder.clearCallingIdentity(); @@ -308,11 +274,6 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi return context.binder.isCallerUidMyUid(); } - @Override - File environmentGetUserSystemDirectory(int userId) { - return services.environment.getUserSystemDirectory(userId); - } - @Override void powerManagerGoToSleep(long time, int reason, int flags) { services.powerManager.goToSleep(time, reason, flags); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 545361c934d2b..0fc201eae3d41 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -8613,8 +8613,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private File getProfileOwnerPoliciesFile() { - File parentDir = dpms.mMockInjector.environmentGetUserSystemDirectory( - CALLER_USER_HANDLE); + File parentDir = getServices().pathProvider.getUserSystemDirectory(CALLER_USER_HANDLE); return getPoliciesFile(parentDir); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 884ffce155d7c..46cc68ffb914c 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -137,6 +137,7 @@ public class MockSystemServices { public final PackageManager packageManager; public final BuildMock buildMock = new BuildMock(); public final File dataDir; + public final PolicyPathProvider pathProvider; public MockSystemServices(Context realContext, String name) { dataDir = new File(realContext.getCacheDir(), name); @@ -217,6 +218,17 @@ public class MockSystemServices { // System user is always running. setUserRunning(UserHandle.USER_SYSTEM, true); + pathProvider = new PolicyPathProvider() { + @Override + public File getDataSystemDirectory() { + return new File(systemUserDataDir.getAbsolutePath()); + } + + @Override + public File getUserSystemDirectory(int userId) { + return environment.getUserSystemDirectory(userId); + } + }; } /** Optional mapping of other user contexts for {@link #createPackageContextAsUser} to return */ diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java index 37ba8a42da86c..f535fdac6cf69 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java @@ -28,8 +28,6 @@ import android.test.suitebuilder.annotation.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -58,7 +56,7 @@ public class OwnersTest extends DpmTestBase { public void loadProfileOwner() throws Exception { getServices().addUsers(10); - final OwnersTestable owners = new OwnersTestable(getServices()); + final Owners owners = makeOwners(); DpmTestUtils.writeToFile(owners.getProfileOwnerFile(10), DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/profile_owner_1.xml")); @@ -76,7 +74,7 @@ public class OwnersTest extends DpmTestBase { @Test public void loadDeviceOwner() throws Exception { - final OwnersTestable owners = new OwnersTestable(getServices()); + final Owners owners = makeOwners(); DpmTestUtils.writeToFile(owners.getDeviceOwnerFile(), DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/device_owner_1.xml")); @@ -95,7 +93,7 @@ public class OwnersTest extends DpmTestBase { @Test public void testDeviceOwnerType() throws Exception { - final OwnersTestable owners = new OwnersTestable(getServices()); + final Owners owners = makeOwners(); DpmTestUtils.writeToFile(owners.getDeviceOwnerFile(), DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/device_owner_1.xml")); @@ -117,4 +115,11 @@ public class OwnersTest extends DpmTestBase { assertThat(owners.getDeviceOwnerType(TESTDPC_PACKAGE)) .isEqualTo(DEVICE_OWNER_TYPE_FINANCED); } + + private Owners makeOwners() { + final MockSystemServices services = getServices(); + return new Owners(services.userManager, services.userManagerInternal, + services.packageManagerInternal, services.activityTaskManagerInternal, + services.activityManagerInternal, services.pathProvider); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java index 834a514b978a6..9efc10cb55ec9 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java @@ -16,10 +16,12 @@ package com.android.server.devicepolicy; -import static android.os.UserHandle.USER_SYSTEM; +import static android.content.pm.UserInfo.FLAG_PRIMARY; +import static android.os.UserManager.USER_TYPE_FULL_SYSTEM; +import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; +import static com.android.server.devicepolicy.DevicePolicyManagerService.DEVICE_POLICIES_XML; import static com.android.server.devicepolicy.DevicePolicyManagerService.POLICIES_VERSION_XML; -import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile; import static com.google.common.truth.Truth.assertThat; @@ -36,7 +38,6 @@ import android.util.Xml; import androidx.test.InstrumentationRegistry; -import com.android.frameworks.servicestests.R; import com.android.internal.util.JournaledFile; import com.android.server.SystemService; @@ -51,7 +52,6 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileInputStream; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; @@ -67,30 +67,18 @@ public class PolicyVersionUpgraderTest extends DpmTestBase { public static final String PERMISSIONS_TAG = "admin-can-grant-sensors-permissions"; private ComponentName mFakeAdmin; - private static class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider { - int mDeviceOwnerUserId; - ComponentName mDeviceOwnerComponent = new ComponentName("", ""); + private class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider { boolean mIsFileBasedEncryptionEnabled; - Map mUserToComponent = new HashMap<>(); Map mComponentToDeviceAdminInfo = new HashMap<>(); - File mDataDir; int[] mUsers; - @Override - public boolean isDeviceOwner(int userId, ComponentName who) { - return userId == mDeviceOwnerUserId && mDeviceOwnerComponent.equals(who); - } - @Override public boolean storageManagerIsFileBasedEncryptionEnabled() { return mIsFileBasedEncryptionEnabled; } private JournaledFile makeJournaledFile(int userId, String fileName) { - File parentDir = new File(mDataDir, String.format("user%d", userId)); - if (!parentDir.exists()) { - parentDir.mkdirs(); - } + File parentDir = getServices().environment.getUserSystemDirectory(userId); final String base = new File(parentDir, fileName).getAbsolutePath(); return new JournaledFile(new File(base), new File(base + ".tmp")); @@ -98,17 +86,12 @@ public class PolicyVersionUpgraderTest extends DpmTestBase { @Override public JournaledFile makeDevicePoliciesJournaledFile(int userId) { - return makeJournaledFile(userId, DevicePolicyManagerService.DEVICE_POLICIES_XML); + return makeJournaledFile(userId, DEVICE_POLICIES_XML); } @Override public JournaledFile makePoliciesVersionJournaledFile(int userId) { - return makeJournaledFile(userId, DevicePolicyManagerService.POLICIES_VERSION_XML); - } - - @Override - public ComponentName getOwnerComponent(int userId) { - return mUserToComponent.get(userId); + return makeJournaledFile(userId, POLICIES_VERSION_XML); } @Override @@ -125,7 +108,6 @@ public class PolicyVersionUpgraderTest extends DpmTestBase { private final Context mRealTestContext = InstrumentationRegistry.getTargetContext(); private FakePolicyUpgraderDataProvider mProvider; private PolicyVersionUpgrader mUpgrader; - private File mDataDir; @Before public void setUp() { @@ -134,11 +116,7 @@ public class PolicyVersionUpgraderTest extends DpmTestBase { IpcDataCache.disableForTestMode(); mProvider = new FakePolicyUpgraderDataProvider(); - mUpgrader = new PolicyVersionUpgrader(mProvider); - mDataDir = new File(mRealTestContext.getCacheDir(), "test-data"); - mDataDir.getParentFile().mkdirs(); - // Prepare provider. - mProvider.mDataDir = mDataDir; + mUpgrader = new PolicyVersionUpgrader(mProvider, getServices().pathProvider); mFakeAdmin = new ComponentName( "com.android.frameworks.servicestests", "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"); @@ -165,6 +143,7 @@ public class PolicyVersionUpgraderTest extends DpmTestBase { public void testUpgrade0To1RemovesPasswordMetrics() throws IOException, XmlPullParserException { final String activePasswordTag = "active-password"; mProvider.mUsers = new int[] {0, 10}; + getServices().addUser(10, /* flags= */ 0, USER_TYPE_PROFILE_MANAGED); writeVersionToXml(0); for (int userId : mProvider.mUsers) { preparePoliciesFile(userId); @@ -185,13 +164,12 @@ public class PolicyVersionUpgraderTest extends DpmTestBase { throws IOException, XmlPullParserException { final int ownerUser = 10; mProvider.mUsers = new int[] {0, ownerUser}; + getServices().addUser(ownerUser, FLAG_PRIMARY, USER_TYPE_FULL_SYSTEM); writeVersionToXml(1); for (int userId : mProvider.mUsers) { preparePoliciesFile(userId); } - mProvider.mDeviceOwnerUserId = ownerUser; - mProvider.mDeviceOwnerComponent = mFakeAdmin; - mProvider.mUserToComponent.put(ownerUser, mFakeAdmin); + prepareDeviceOwnerFile(ownerUser); mUpgrader.upgradePolicy(2); @@ -204,19 +182,12 @@ public class PolicyVersionUpgraderTest extends DpmTestBase { @Test public void testNoStaleDataInCacheAfterUpgrade() throws Exception { - setUpPackageManagerForAdmin(admin1, UserHandle.getUid(USER_SYSTEM, 123 /* admin app ID */)); - // Reusing COPE migration policy files there, only DO on user 0 is needed. - writeInputStreamToFile(getRawStream(R.raw.comp_policies_primary), - new File(getServices().systemUserDataDir, "device_policies.xml") - .getAbsoluteFile()); - writeInputStreamToFile(getRawStream(R.raw.comp_device_owner), - new File(getServices().dataDir, "device_owner_2.xml") - .getAbsoluteFile()); - - // Write policy version 0 - File versionFilePath = - new File(getServices().systemUserDataDir, POLICIES_VERSION_XML).getAbsoluteFile(); - DpmTestUtils.writeToFile(versionFilePath, "0\n"); + final int ownerUser = 0; + getServices().addUser(ownerUser, FLAG_PRIMARY, USER_TYPE_FULL_SYSTEM); + setUpPackageManagerForAdmin(admin1, UserHandle.getUid(ownerUser, 123 /* admin app ID */)); + writeVersionToXml(0); + preparePoliciesFile(ownerUser); + prepareDeviceOwnerFile(ownerUser); DevicePolicyManagerServiceTestable dpms; final long ident = getContext().binder.clearCallingIdentity(); @@ -233,7 +204,7 @@ public class PolicyVersionUpgraderTest extends DpmTestBase { // DO should be marked as able to grant sensors permission during upgrade and should be // reported as such via the API. - assertThat(dpms.canAdminGrantSensorsPermissionsForUser(/* userId= */0)).isTrue(); + assertThat(dpms.canAdminGrantSensorsPermissionsForUser(ownerUser)).isTrue(); } @Test @@ -264,9 +235,27 @@ public class PolicyVersionUpgraderTest extends DpmTestBase { policiesFile.commit(); } + private void prepareDeviceOwnerFile(int userId) throws IOException { + File parentDir = getServices().pathProvider.getDataSystemDirectory(); + File doFilePath = (new File(parentDir, "device_owner_2.xml")).getAbsoluteFile(); + android.util.Log.i("YYYYYY", "DO paath: " + doFilePath); + String doFileContent = DpmTestUtils.readAsset(mRealTestContext, + "PolicyVersionUpgraderTest/device_owner_2.xml") + // Substitute the right DO userId, XML in resources has 0 + .replace("userId=\"0\"", "userId=\"" + userId + "\""); + DpmTestUtils.writeToFile(doFilePath, doFileContent); + } + + private void prepareProfileOwnerFile(int userId) throws IOException { + File parentDir = getServices().pathProvider.getUserSystemDirectory(userId); + DpmTestUtils.writeToFile( + (new File(parentDir, "profile_owner.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "PolicyVersionUpgraderTest/profile_owner.xml")); + } + private String readPoliciesFile(int userId) throws IOException { File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); - FileReader reader = new FileReader(policiesFile); return new String(Files.asByteSource(policiesFile).read(), Charset.defaultCharset()); }