Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +4 −3 Original line number Original line Diff line number Diff line Loading @@ -473,7 +473,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // to decide whether an existing policy in the {@link #DEVICE_POLICIES_XML} needs to // to decide whether an existing policy in the {@link #DEVICE_POLICIES_XML} needs to // be upgraded. See {@link PolicyVersionUpgrader} on instructions how to add an upgrade // be upgraded. See {@link PolicyVersionUpgrader} on instructions how to add an upgrade // step. // step. static final int DPMS_VERSION = 1; static final int DPMS_VERSION = 2; static { static { SECURE_SETTINGS_ALLOWLIST = new ArraySet<>(); SECURE_SETTINGS_ALLOWLIST = new ArraySet<>(); Loading Loading @@ -2969,8 +2969,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider { private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider { @Override @Override public boolean isUserDeviceOwner(int userId) { public boolean isUserDeviceOwner(int userId, ComponentName who) { return mOwners.isDeviceOwnerUserId(userId); return mOwners.isDeviceOwnerUserId(userId) && mOwners.getDeviceOwnerComponent().equals(who); } } @Override @Override Loading services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -33,7 +33,7 @@ public interface PolicyUpgraderDataProvider { * Returns true if the provided {@code userId} is a device owner. May affect some policy * Returns true if the provided {@code userId} is a device owner. May affect some policy * defaults. * defaults. */ */ boolean isUserDeviceOwner(int userId); boolean isUserDeviceOwner(int userId, ComponentName who); /** /** * Returns true if the storage manager indicates file-based encryption is enabled. * Returns true if the storage manager indicates file-based encryption is enabled. Loading services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -83,6 +83,27 @@ public class PolicyVersionUpgrader { currentVersion = 1; currentVersion = 1; } } if (currentVersion == 1) { Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion)); // This upgrade step is for Device Owner scenario only: For devices upgrading to S, // if there is a device owner, it retains the ability to control sensors-related // permission grants. for (int userId : allUsers) { DevicePolicyData userData = allUsersData.get(userId); if (userData == null) { continue; } for (ActiveAdmin admin : userData.mAdminList) { if (mProvider.isUserDeviceOwner(userId, admin.info.getComponent())) { Slog.i(LOG_TAG, String.format( "Marking Device Owner in user %d for permission grant ", userId)); admin.mAdminCanGrantSensorsPermissions = true; } } } currentVersion = 2; } writePoliciesAndVersion(allUsers, allUsersData, currentVersion); writePoliciesAndVersion(allUsers, allUsersData, currentVersion); } } Loading services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java +118 −12 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,11 @@ import static com.google.common.truth.Truth.assertThat; import android.app.admin.DeviceAdminInfo; import android.app.admin.DeviceAdminInfo; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.os.Parcel; import android.util.TypedXmlPullParser; import android.util.Xml; import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry; Loading @@ -32,9 +37,14 @@ import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.junit.runners.JUnit4; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.nio.charset.Charset; import java.util.HashMap; import java.util.HashMap; import java.util.Map; import java.util.Map; Loading @@ -44,18 +54,21 @@ import java.util.function.Function; public class PolicyVersionUpgraderTest { public class PolicyVersionUpgraderTest { // NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade // NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade // to the new version. // to the new version. private static final int LATEST_TESTED_VERSION = 1; private static final int LATEST_TESTED_VERSION = 2; public static final String PERMISSIONS_TAG = "admin-can-grant-sensors-permissions"; private ComponentName mFakeAdmin; private static class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider { private static class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider { int mDeviceOwnerUserId; int mDeviceOwnerUserId; ComponentName mDeviceOwnerComponent = new ComponentName("", ""); boolean mIsFileBasedEncryptionEnabled; boolean mIsFileBasedEncryptionEnabled; Map<Integer, ComponentName> mUserToComponent = new HashMap<>(); Map<Integer, ComponentName> mUserToComponent = new HashMap<>(); Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo; Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>(); File mDataDir; File mDataDir; @Override @Override public boolean isUserDeviceOwner(int userId) { public boolean isUserDeviceOwner(int userId, ComponentName who) { return userId == mDeviceOwnerUserId; return userId == mDeviceOwnerUserId && mDeviceOwnerComponent.equals(who); } } @Override @Override Loading Loading @@ -105,7 +118,14 @@ public class PolicyVersionUpgraderTest { mUpgrader = new PolicyVersionUpgrader(mProvider); mUpgrader = new PolicyVersionUpgrader(mProvider); mDataDir = new File(mRealTestContext.getCacheDir(), "test-data"); mDataDir = new File(mRealTestContext.getCacheDir(), "test-data"); mDataDir.getParentFile().mkdirs(); mDataDir.getParentFile().mkdirs(); // Prepare provider. mProvider.mDataDir = mDataDir; mProvider.mDataDir = mDataDir; mFakeAdmin = new ComponentName( "com.android.frameworks.servicestests", "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"); ActivityInfo activityInfo = createActivityInfo(mFakeAdmin); DeviceAdminInfo dai = createDeviceAdminInfo(activityInfo); mProvider.mComponentToDeviceAdminInfo.put(mFakeAdmin, dai); } } @Test @Test Loading @@ -122,21 +142,43 @@ public class PolicyVersionUpgraderTest { } } @Test @Test public void testUpgrade0To1RemovesPasswordMetrics() throws IOException { public void testUpgrade0To1RemovesPasswordMetrics() throws IOException, XmlPullParserException { final String activePasswordTag = "active-password"; int[] users = new int[] {0, 10}; int[] users = new int[] {0, 10}; writeVersionToXml(0); writeVersionToXml(0); for (int userId : users) { for (int userId : users) { preparePoliciesFile(userId); preparePoliciesFile(userId); } } // Validate test set-up. String oldContents = readPoliciesFile(0); assertThat(isTagPresent(readPoliciesFileToStream(0), activePasswordTag)).isTrue(); assertThat(oldContents).contains("active-password"); mUpgrader.upgradePolicy(users, 1); mUpgrader.upgradePolicy(users, 1); assertThat(readVersionFromXml()).isEqualTo(1); assertThat(readVersionFromXml()).isGreaterThan(1); assertThat(readPoliciesFile(users[0])).doesNotContain("active-password"); for (int user: users) { assertThat(readPoliciesFile(users[1])).doesNotContain("active-password"); assertThat(isTagPresent(readPoliciesFileToStream(user), activePasswordTag)).isFalse(); } } @Test public void testUpgrade1To2MarksDoForPermissionControl() throws IOException, XmlPullParserException { int[] users = new int[] {0, 10}; writeVersionToXml(1); for (int userId : users) { preparePoliciesFile(userId); } mProvider.mDeviceOwnerUserId = 10; mProvider.mDeviceOwnerComponent = mFakeAdmin; mProvider.mUserToComponent.put(10, mFakeAdmin); mUpgrader.upgradePolicy(users, 2); assertThat(readVersionFromXml()).isEqualTo(2); assertThat(getBooleanValueTag(readPoliciesFileToStream(users[0]), PERMISSIONS_TAG)).isFalse(); assertThat(getBooleanValueTag(readPoliciesFileToStream(users[1]), PERMISSIONS_TAG)).isTrue(); } } @Test @Test Loading Loading @@ -169,6 +211,70 @@ public class PolicyVersionUpgraderTest { private String readPoliciesFile(int userId) throws IOException { private String readPoliciesFile(int userId) throws IOException { File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); return new String(Files.asByteSource(policiesFile).read()); FileReader reader = new FileReader(policiesFile); return new String(Files.asByteSource(policiesFile).read(), Charset.defaultCharset()); } private InputStream readPoliciesFileToStream(int userId) throws IOException { File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); return new FileInputStream(policiesFile); } private boolean getBooleanValueTag(InputStream inputXml, String tagName) throws IOException, XmlPullParserException { TypedXmlPullParser parser = Xml.resolvePullParser(inputXml); int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG) { String tag = parser.getName(); if (tagName.equals(tag)) { String res = parser.getAttributeValue(null, "value"); return Boolean.parseBoolean(res); } } eventType = parser.next(); } throw new IllegalStateException("Could not find " + tagName); } private boolean isTagPresent(InputStream inputXml, String tagName) throws IOException, XmlPullParserException { TypedXmlPullParser parser = Xml.resolvePullParser(inputXml); int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG) { String tag = parser.getName(); if (tagName.equals(tag)) { return true; } } eventType = parser.next(); } return false; } private ActivityInfo createActivityInfo(ComponentName admin) { ActivityInfo ai = new ActivityInfo(); ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.className = admin.getClassName(); applicationInfo.uid = 2222; ai.applicationInfo = applicationInfo; ai.name = admin.getClassName(); ai.packageName = admin.getPackageName(); return ai; } private DeviceAdminInfo createDeviceAdminInfo(ActivityInfo activityInfo) { Parcel parcel = Parcel.obtain(); activityInfo.writeToParcel(parcel, 0); parcel.writeInt(0); parcel.writeBoolean(true); parcel.setDataPosition(0); return DeviceAdminInfo.CREATOR.createFromParcel(parcel); } } } } Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +4 −3 Original line number Original line Diff line number Diff line Loading @@ -473,7 +473,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // to decide whether an existing policy in the {@link #DEVICE_POLICIES_XML} needs to // to decide whether an existing policy in the {@link #DEVICE_POLICIES_XML} needs to // be upgraded. See {@link PolicyVersionUpgrader} on instructions how to add an upgrade // be upgraded. See {@link PolicyVersionUpgrader} on instructions how to add an upgrade // step. // step. static final int DPMS_VERSION = 1; static final int DPMS_VERSION = 2; static { static { SECURE_SETTINGS_ALLOWLIST = new ArraySet<>(); SECURE_SETTINGS_ALLOWLIST = new ArraySet<>(); Loading Loading @@ -2969,8 +2969,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider { private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider { @Override @Override public boolean isUserDeviceOwner(int userId) { public boolean isUserDeviceOwner(int userId, ComponentName who) { return mOwners.isDeviceOwnerUserId(userId); return mOwners.isDeviceOwnerUserId(userId) && mOwners.getDeviceOwnerComponent().equals(who); } } @Override @Override Loading
services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -33,7 +33,7 @@ public interface PolicyUpgraderDataProvider { * Returns true if the provided {@code userId} is a device owner. May affect some policy * Returns true if the provided {@code userId} is a device owner. May affect some policy * defaults. * defaults. */ */ boolean isUserDeviceOwner(int userId); boolean isUserDeviceOwner(int userId, ComponentName who); /** /** * Returns true if the storage manager indicates file-based encryption is enabled. * Returns true if the storage manager indicates file-based encryption is enabled. Loading
services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -83,6 +83,27 @@ public class PolicyVersionUpgrader { currentVersion = 1; currentVersion = 1; } } if (currentVersion == 1) { Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion)); // This upgrade step is for Device Owner scenario only: For devices upgrading to S, // if there is a device owner, it retains the ability to control sensors-related // permission grants. for (int userId : allUsers) { DevicePolicyData userData = allUsersData.get(userId); if (userData == null) { continue; } for (ActiveAdmin admin : userData.mAdminList) { if (mProvider.isUserDeviceOwner(userId, admin.info.getComponent())) { Slog.i(LOG_TAG, String.format( "Marking Device Owner in user %d for permission grant ", userId)); admin.mAdminCanGrantSensorsPermissions = true; } } } currentVersion = 2; } writePoliciesAndVersion(allUsers, allUsersData, currentVersion); writePoliciesAndVersion(allUsers, allUsersData, currentVersion); } } Loading
services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java +118 −12 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,11 @@ import static com.google.common.truth.Truth.assertThat; import android.app.admin.DeviceAdminInfo; import android.app.admin.DeviceAdminInfo; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.os.Parcel; import android.util.TypedXmlPullParser; import android.util.Xml; import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry; Loading @@ -32,9 +37,14 @@ import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.junit.runners.JUnit4; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.nio.charset.Charset; import java.util.HashMap; import java.util.HashMap; import java.util.Map; import java.util.Map; Loading @@ -44,18 +54,21 @@ import java.util.function.Function; public class PolicyVersionUpgraderTest { public class PolicyVersionUpgraderTest { // NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade // NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade // to the new version. // to the new version. private static final int LATEST_TESTED_VERSION = 1; private static final int LATEST_TESTED_VERSION = 2; public static final String PERMISSIONS_TAG = "admin-can-grant-sensors-permissions"; private ComponentName mFakeAdmin; private static class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider { private static class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider { int mDeviceOwnerUserId; int mDeviceOwnerUserId; ComponentName mDeviceOwnerComponent = new ComponentName("", ""); boolean mIsFileBasedEncryptionEnabled; boolean mIsFileBasedEncryptionEnabled; Map<Integer, ComponentName> mUserToComponent = new HashMap<>(); Map<Integer, ComponentName> mUserToComponent = new HashMap<>(); Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo; Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>(); File mDataDir; File mDataDir; @Override @Override public boolean isUserDeviceOwner(int userId) { public boolean isUserDeviceOwner(int userId, ComponentName who) { return userId == mDeviceOwnerUserId; return userId == mDeviceOwnerUserId && mDeviceOwnerComponent.equals(who); } } @Override @Override Loading Loading @@ -105,7 +118,14 @@ public class PolicyVersionUpgraderTest { mUpgrader = new PolicyVersionUpgrader(mProvider); mUpgrader = new PolicyVersionUpgrader(mProvider); mDataDir = new File(mRealTestContext.getCacheDir(), "test-data"); mDataDir = new File(mRealTestContext.getCacheDir(), "test-data"); mDataDir.getParentFile().mkdirs(); mDataDir.getParentFile().mkdirs(); // Prepare provider. mProvider.mDataDir = mDataDir; mProvider.mDataDir = mDataDir; mFakeAdmin = new ComponentName( "com.android.frameworks.servicestests", "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"); ActivityInfo activityInfo = createActivityInfo(mFakeAdmin); DeviceAdminInfo dai = createDeviceAdminInfo(activityInfo); mProvider.mComponentToDeviceAdminInfo.put(mFakeAdmin, dai); } } @Test @Test Loading @@ -122,21 +142,43 @@ public class PolicyVersionUpgraderTest { } } @Test @Test public void testUpgrade0To1RemovesPasswordMetrics() throws IOException { public void testUpgrade0To1RemovesPasswordMetrics() throws IOException, XmlPullParserException { final String activePasswordTag = "active-password"; int[] users = new int[] {0, 10}; int[] users = new int[] {0, 10}; writeVersionToXml(0); writeVersionToXml(0); for (int userId : users) { for (int userId : users) { preparePoliciesFile(userId); preparePoliciesFile(userId); } } // Validate test set-up. String oldContents = readPoliciesFile(0); assertThat(isTagPresent(readPoliciesFileToStream(0), activePasswordTag)).isTrue(); assertThat(oldContents).contains("active-password"); mUpgrader.upgradePolicy(users, 1); mUpgrader.upgradePolicy(users, 1); assertThat(readVersionFromXml()).isEqualTo(1); assertThat(readVersionFromXml()).isGreaterThan(1); assertThat(readPoliciesFile(users[0])).doesNotContain("active-password"); for (int user: users) { assertThat(readPoliciesFile(users[1])).doesNotContain("active-password"); assertThat(isTagPresent(readPoliciesFileToStream(user), activePasswordTag)).isFalse(); } } @Test public void testUpgrade1To2MarksDoForPermissionControl() throws IOException, XmlPullParserException { int[] users = new int[] {0, 10}; writeVersionToXml(1); for (int userId : users) { preparePoliciesFile(userId); } mProvider.mDeviceOwnerUserId = 10; mProvider.mDeviceOwnerComponent = mFakeAdmin; mProvider.mUserToComponent.put(10, mFakeAdmin); mUpgrader.upgradePolicy(users, 2); assertThat(readVersionFromXml()).isEqualTo(2); assertThat(getBooleanValueTag(readPoliciesFileToStream(users[0]), PERMISSIONS_TAG)).isFalse(); assertThat(getBooleanValueTag(readPoliciesFileToStream(users[1]), PERMISSIONS_TAG)).isTrue(); } } @Test @Test Loading Loading @@ -169,6 +211,70 @@ public class PolicyVersionUpgraderTest { private String readPoliciesFile(int userId) throws IOException { private String readPoliciesFile(int userId) throws IOException { File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); return new String(Files.asByteSource(policiesFile).read()); FileReader reader = new FileReader(policiesFile); return new String(Files.asByteSource(policiesFile).read(), Charset.defaultCharset()); } private InputStream readPoliciesFileToStream(int userId) throws IOException { File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); return new FileInputStream(policiesFile); } private boolean getBooleanValueTag(InputStream inputXml, String tagName) throws IOException, XmlPullParserException { TypedXmlPullParser parser = Xml.resolvePullParser(inputXml); int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG) { String tag = parser.getName(); if (tagName.equals(tag)) { String res = parser.getAttributeValue(null, "value"); return Boolean.parseBoolean(res); } } eventType = parser.next(); } throw new IllegalStateException("Could not find " + tagName); } private boolean isTagPresent(InputStream inputXml, String tagName) throws IOException, XmlPullParserException { TypedXmlPullParser parser = Xml.resolvePullParser(inputXml); int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG) { String tag = parser.getName(); if (tagName.equals(tag)) { return true; } } eventType = parser.next(); } return false; } private ActivityInfo createActivityInfo(ComponentName admin) { ActivityInfo ai = new ActivityInfo(); ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.className = admin.getClassName(); applicationInfo.uid = 2222; ai.applicationInfo = applicationInfo; ai.name = admin.getClassName(); ai.packageName = admin.getPackageName(); return ai; } private DeviceAdminInfo createDeviceAdminInfo(ActivityInfo activityInfo) { Parcel parcel = Parcel.obtain(); activityInfo.writeToParcel(parcel, 0); parcel.writeInt(0); parcel.writeBoolean(true); parcel.setDataPosition(0); return DeviceAdminInfo.CREATOR.createFromParcel(parcel); } } } }