From 6b0d330da013ab84f01449a51b402db7a8a69e89 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Mon, 4 Apr 2022 12:22:45 +0100 Subject: [PATCH] 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) {