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) {