summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Pavel Grafov <pgrafov@google.com> 2022-11-21 17:40:52 +0000
committer Pavel Grafov <pgrafov@google.com> 2022-12-09 17:35:33 +0000
commit3532c6accf5e69f35750c399dbf42886bcff43d8 (patch)
treed25c3c7887d710c7f9beac997544bfe9c2cf07c7
parenta2063a9dca2c6e6888471839d9fb4e5f0acd51ba (diff)
Store admin suspended packages in ActiveAdmin
Bug: 258823777 Test: atest PolicyVersionUpgraderTest Change-Id: Ia41884124418453d63490f5fea637dbb7dada4ac
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java11
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java47
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java6
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java44
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java82
5 files changed, 186 insertions, 4 deletions
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 8047a534f4a3..9af30ba14b47 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -162,6 +162,7 @@ class ActiveAdmin {
private static final String TAG_PREFERENTIAL_NETWORK_SERVICE_CONFIG =
"preferential_network_service_config";
private static final String TAG_PROTECTED_PACKAGES = "protected_packages";
+ private static final String TAG_SUSPENDED_PACKAGES = "suspended-packages";
private static final String ATTR_VALUE = "value";
private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
@@ -257,6 +258,8 @@ class ActiveAdmin {
// List of packages for which the user cannot invoke "clear data" or "force stop".
List<String> protectedPackages;
+ List<String> suspendedPackages;
+
// Wi-Fi SSID restriction policy.
WifiSsidPolicy mWifiSsidPolicy;
@@ -508,6 +511,7 @@ class ActiveAdmin {
writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages);
writePackageListToXml(out, TAG_METERED_DATA_DISABLED_PACKAGES, meteredDisabledPackages);
writePackageListToXml(out, TAG_PROTECTED_PACKAGES, protectedPackages);
+ writePackageListToXml(out, TAG_SUSPENDED_PACKAGES, suspendedPackages);
if (hasUserRestrictions()) {
UserRestrictionsUtils.writeRestrictions(
out, userRestrictions, TAG_USER_RESTRICTIONS);
@@ -776,6 +780,8 @@ class ActiveAdmin {
meteredDisabledPackages = readPackageList(parser, tag);
} else if (TAG_PROTECTED_PACKAGES.equals(tag)) {
protectedPackages = readPackageList(parser, tag);
+ } else if (TAG_SUSPENDED_PACKAGES.equals(tag)) {
+ suspendedPackages = readPackageList(parser, tag);
} else if (TAG_USER_RESTRICTIONS.equals(tag)) {
userRestrictions = UserRestrictionsUtils.readRestrictions(parser);
} else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) {
@@ -1225,6 +1231,11 @@ class ActiveAdmin {
pw.println(protectedPackages);
}
+ if (suspendedPackages != null) {
+ pw.print("suspendedPackages=");
+ pw.println(suspendedPackages);
+ }
+
pw.print("organizationColor=");
pw.println(organizationColor);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1ec2438613d2..3d09e69e0b1d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -546,7 +546,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// 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
// step.
- static final int DPMS_VERSION = 3;
+ static final int DPMS_VERSION = 4;
static {
SECURE_SETTINGS_ALLOWLIST = new ArraySet<>();
@@ -1498,8 +1498,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
PackageManager getPackageManager(int userId) {
- return mContext
- .createContextAsUser(UserHandle.of(userId), 0 /* flags */).getPackageManager();
+ try {
+ return createContextAsUser(UserHandle.of(userId)).getPackageManager();
+ } catch (NameNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
}
PowerManagerInternal getPowerManagerInternal() {
@@ -3111,6 +3114,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
List<UserInfo> allUsers = mUserManager.getUsers();
return allUsers.stream().mapToInt(u -> u.id).toArray();
}
+
+ @Override
+ public List<String> getPlatformSuspendedPackages(int userId) {
+ PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
+ return mInjector.getPackageManager(userId)
+ .getInstalledPackages(PackageManager.PackageInfoFlags.of(
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE))
+ .stream()
+ .map(packageInfo -> packageInfo.packageName)
+ .filter(pkg ->
+ PLATFORM_PACKAGE_NAME.equals(pmi.getSuspendingPackage(pkg, userId))
+ )
+ .collect(Collectors.toList());
+ }
}
private void performPolicyVersionUpgrade() {
@@ -11383,6 +11400,30 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Slogf.w(LOG_TAG, "PM failed to suspend packages (%s)", Arrays.toString(packageNames));
return packageNames;
}
+
+ ArraySet<String> changed = new ArraySet<>(packageNames);
+ if (suspended) {
+ // Only save those packages that are actually suspended. If a package is exempt or is
+ // unsuspendable, it is skipped.
+ changed.removeAll(List.of(nonSuspendedPackages));
+ } else {
+ // If an admin tries to unsuspend a package that is either exempt or is not
+ // suspendable, drop it from the stored list assuming it must be already unsuspended.
+ changed.addAll(exemptApps);
+ }
+
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
+ ArraySet<String> current = new ArraySet<>(admin.suspendedPackages);
+ if (suspended) {
+ current.addAll(changed);
+ } else {
+ current.removeAll(changed);
+ }
+ admin.suspendedPackages = current.isEmpty() ? null : new ArrayList<>(current);
+ saveSettingsLocked(caller.getUserId());
+ }
+
if (exemptApps.isEmpty()) {
return nonSuspendedPackages;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
index 147474907f29..c0ef0b0f80df 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
@@ -21,6 +21,7 @@ import android.content.ComponentName;
import com.android.internal.util.JournaledFile;
+import java.util.List;
import java.util.function.Function;
/**
@@ -48,4 +49,9 @@ public interface PolicyUpgraderDataProvider {
* Returns the users to upgrade.
*/
int[] getUsersForUpgrade();
+
+ /**
+ * Returns packages suspended by platform for a given user.
+ */
+ List<String> getPlatformSuspendedPackages(int userId);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 808133164cd1..1fe4b571a770 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -104,6 +104,12 @@ public class PolicyVersionUpgrader {
currentVersion = 3;
}
+ if (currentVersion == 3) {
+ Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion));
+ upgradePackageSuspension(allUsers, ownersData, allUsersData);
+ currentVersion = 4;
+ }
+
writePoliciesAndVersion(allUsers, allUsersData, ownersData, currentVersion);
}
@@ -170,6 +176,44 @@ public class PolicyVersionUpgrader {
}
}
+ /**
+ * This upgrade step stores packages suspended via DPM.setPackagesSuspended() into ActiveAdmin
+ * data structure. Prior to this it was only persisted in PackageManager which doesn't have any
+ * way of knowing which admin suspended it.
+ */
+ private void upgradePackageSuspension(
+ int[] allUsers, OwnersData ownersData, SparseArray<DevicePolicyData> allUsersData) {
+ if (ownersData.mDeviceOwner != null) {
+ saveSuspendedPackages(allUsersData, ownersData.mDeviceOwnerUserId,
+ ownersData.mDeviceOwner.admin);
+ }
+
+ for (int i = 0; i < ownersData.mProfileOwners.size(); i++) {
+ int ownerUserId = ownersData.mProfileOwners.keyAt(i);
+ OwnersData.OwnerInfo ownerInfo = ownersData.mProfileOwners.valueAt(i);
+ saveSuspendedPackages(allUsersData, ownerUserId, ownerInfo.admin);
+ }
+ }
+
+ private void saveSuspendedPackages(SparseArray<DevicePolicyData> allUsersData, int ownerUserId,
+ ComponentName ownerPackage) {
+ DevicePolicyData ownerUserData = allUsersData.get(ownerUserId);
+ if (ownerUserData == null) {
+ Slog.e(LOG_TAG, "No policy data for owner user, cannot migrate suspended packages");
+ return;
+ }
+
+ ActiveAdmin ownerAdmin = ownerUserData.mAdminMap.get(ownerPackage);
+ if (ownerAdmin == null) {
+ Slog.e(LOG_TAG, "No admin for owner, cannot migrate suspended packages");
+ return;
+ }
+
+ ownerAdmin.suspendedPackages = mProvider.getPlatformSuspendedPackages(ownerUserId);
+ Slog.i(LOG_TAG, String.format("Saved %d packages suspended by %s in user %d",
+ ownerAdmin.suspendedPackages.size(), ownerPackage, ownerUserId));
+ }
+
private OwnersData loadOwners(int[] allUsers) {
OwnersData ownersData = new OwnersData(mPathProvider);
ownersData.load(allUsers);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index d540734d0938..1779b16a7471 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -33,6 +33,7 @@ import android.content.pm.ApplicationInfo;
import android.os.IpcDataCache;
import android.os.Parcel;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
@@ -47,29 +48,42 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.function.Function;
+import javax.xml.parsers.DocumentBuilderFactory;
+
@RunWith(JUnit4.class)
public class PolicyVersionUpgraderTest extends DpmTestBase {
// NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade
// to the new version.
- private static final int LATEST_TESTED_VERSION = 3;
+ private static final int LATEST_TESTED_VERSION = 4;
public static final String PERMISSIONS_TAG = "admin-can-grant-sensors-permissions";
public static final String DEVICE_OWNER_XML = "device_owner_2.xml";
private ComponentName mFakeAdmin;
private class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider {
Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>();
+ ArrayList<String> mPlatformSuspendedPackages = new ArrayList<>();
int[] mUsers;
private JournaledFile makeJournaledFile(int userId, String fileName) {
@@ -98,6 +112,11 @@ public class PolicyVersionUpgraderTest extends DpmTestBase {
public int[] getUsersForUpgrade() {
return mUsers;
}
+
+ @Override
+ public List<String> getPlatformSuspendedPackages(int userId) {
+ return mPlatformSuspendedPackages;
+ }
}
private final Context mRealTestContext = InstrumentationRegistry.getTargetContext();
@@ -257,10 +276,71 @@ public class PolicyVersionUpgraderTest extends DpmTestBase {
}
@Test
+ public void testAdminPackageSuspensionSaved() throws Exception {
+ final int ownerUser = 0;
+ mProvider.mUsers = new int[]{ownerUser};
+ getServices().addUser(ownerUser, FLAG_PRIMARY, USER_TYPE_FULL_SYSTEM);
+ setUpPackageManagerForAdmin(admin1, UserHandle.getUid(ownerUser, 123 /* admin app ID */));
+ writeVersionToXml(3);
+ preparePoliciesFile(ownerUser, "device_policies.xml");
+ prepareDeviceOwnerFile(ownerUser, "device_owner_2.xml");
+
+ // Pretend package manager thinks these packages are suspended by the platform.
+ Set<String> suspendedPkgs = Set.of("com.some.app", "foo.bar.baz");
+ mProvider.mPlatformSuspendedPackages.addAll(suspendedPkgs);
+
+ mUpgrader.upgradePolicy(4);
+
+ assertThat(readVersionFromXml()).isAtLeast(4);
+
+ assertAdminSuspendedPackages(ownerUser, suspendedPkgs);
+ }
+
+ private void assertAdminSuspendedPackages(int ownerUser, Set<String> suspendedPkgs)
+ throws Exception {
+ Document policies = readPolicies(ownerUser);
+ Element adminElem =
+ (Element) policies.getDocumentElement().getElementsByTagName("admin").item(0);
+ Element suspendedElem =
+ (Element) adminElem.getElementsByTagName("suspended-packages").item(0);
+ NodeList pkgsNodes = suspendedElem.getElementsByTagName("item");
+ Set<String> storedSuspendedPkgs = new ArraySet<>();
+ for (int i = 0; i < pkgsNodes.getLength(); i++) {
+ Element item = (Element) pkgsNodes.item(i);
+ storedSuspendedPkgs.add(item.getAttribute("value"));
+ }
+ assertThat(storedSuspendedPkgs).isEqualTo(suspendedPkgs);
+ }
+
+ @Test
public void isLatestVersionTested() {
assertThat(DevicePolicyManagerService.DPMS_VERSION).isEqualTo(LATEST_TESTED_VERSION);
}
+ /**
+ * Reads ABX binary XML, converts it to text, and returns as an input stream.
+ */
+ private InputStream abxToXmlStream(File file) throws Exception {
+ FileInputStream fileIn = new FileInputStream(file);
+ XmlPullParser in = Xml.newBinaryPullParser();
+ in.setInput(fileIn, StandardCharsets.UTF_8.name());
+
+ ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+ XmlSerializer out = Xml.newSerializer();
+ out.setOutput(byteOut, StandardCharsets.UTF_8.name());
+
+ Xml.copy(in, out);
+ out.flush();
+
+ return new ByteArrayInputStream(byteOut.toByteArray());
+ }
+
+ private Document readPolicies(int userId) throws Exception {
+ File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead();
+ InputStream is = abxToXmlStream(policiesFile);
+ return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
+ }
+
private void writeVersionToXml(int dpmsVersion) throws IOException {
JournaledFile versionFile = mProvider.makePoliciesVersionJournaledFile(0);
Files.asCharSink(versionFile.chooseForWrite(), Charset.defaultCharset()).write(