Add lockTask policy definition
Bug: 232918480
Test: manual
Change-Id: Ifbaf0f19d018fa9aadcbab3dd6c8eefe8d79f492
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9fd990f..ef098c6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3936,6 +3936,12 @@
return PERMISSION_GRANT_POLICY_KEY + "_" + packageName + "_" + permission;
}
+ // TODO: Expose this as SystemAPI once we add the query API
+ /**
+ * @hide
+ */
+ public static final String LOCK_TASK_POLICY = "lockTask";
+
/**
* This object is a single place to tack on invalidation and disable calls. All
* binder caches in this class derive from this Config, so all can be invalidated or
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 316c736..d492fd6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -332,6 +332,7 @@
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Pair;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
import android.view.IWindowManager;
@@ -2878,60 +2879,60 @@
policy.validatePasswordOwner();
updateMaximumTimeToLockLocked(userHandle);
- updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle);
+ updateLockTaskPackagesLocked(mContext, policy.mLockTaskPackages, userHandle);
updateLockTaskFeaturesLocked(policy.mLockTaskFeatures, userHandle);
if (policy.mStatusBarDisabled) {
setStatusBarDisabledInternal(policy.mStatusBarDisabled, userHandle);
}
}
- private void updateLockTaskPackagesLocked(List<String> packages, int userId) {
- String[] packagesArray = null;
+ static void updateLockTaskPackagesLocked(Context context, List<String> packages, int userId) {
+ Binder.withCleanCallingIdentity(() -> {
- if (!packages.isEmpty()) {
- // When adding packages, we need to include the exempt apps so they can still be
- // launched (ideally we should use a different AM API as these apps don't need to use
- // lock-task mode).
- // They're not added when the packages is empty though, as in that case we're disabling
- // lock-task mode.
- List<String> exemptApps = listPolicyExemptAppsUnchecked();
- if (!exemptApps.isEmpty()) {
- // TODO(b/175377361): add unit test to verify it (cannot be CTS because the policy-
- // -exempt apps are provided by OEM and the test would have no control over it) once
- // tests are migrated to the new infra-structure
- HashSet<String> updatedPackages = new HashSet<>(packages);
- updatedPackages.addAll(exemptApps);
- if (VERBOSE_LOG) {
- Slogf.v(LOG_TAG, "added %d policy-exempt apps to %d lock task packages. Final "
- + "list: %s", exemptApps.size(), packages.size(), updatedPackages);
+ String[] packagesArray = null;
+ if (!packages.isEmpty()) {
+ // When adding packages, we need to include the exempt apps so they can still be
+ // launched (ideally we should use a different AM API as these apps don't need to
+ // use lock-task mode).
+ // They're not added when the packages is empty though, as in that case we're
+ // disabling lock-task mode.
+ List<String> exemptApps = listPolicyExemptAppsUnchecked(context);
+ if (!exemptApps.isEmpty()) {
+ // TODO(b/175377361): add unit test to verify it (cannot be CTS because the
+ // policy-exempt apps are provided by OEM and the test would have no control
+ // over it) once tests are migrated to the new infra-structure
+ HashSet<String> updatedPackages = new HashSet<>(packages);
+ updatedPackages.addAll(exemptApps);
+ if (VERBOSE_LOG) {
+ Slogf.v(LOG_TAG, "added %d policy-exempt apps to %d lock task "
+ + "packages. Final list: %s",
+ exemptApps.size(), packages.size(), updatedPackages);
+ }
+ packagesArray = updatedPackages.toArray(new String[updatedPackages.size()]);
}
- packagesArray = updatedPackages.toArray(new String[updatedPackages.size()]);
}
- }
- if (packagesArray == null) {
- packagesArray = packages.toArray(new String[packages.size()]);
- }
-
- long ident = mInjector.binderClearCallingIdentity();
- try {
- mInjector.getIActivityManager().updateLockTaskPackages(userId, packagesArray);
- } catch (RemoteException e) {
- // Not gonna happen.
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
- }
+ if (packagesArray == null) {
+ packagesArray = packages.toArray(new String[packages.size()]);
+ }
+ try {
+ ActivityManager.getService().updateLockTaskPackages(userId, packagesArray);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ Slog.wtf(LOG_TAG, "Remote Exception: ", e);
+ }
+ });
}
- private void updateLockTaskFeaturesLocked(int flags, int userId) {
- long ident = mInjector.binderClearCallingIdentity();
- try {
- mInjector.getIActivityTaskManager().updateLockTaskFeatures(userId, flags);
- } catch (RemoteException e) {
- // Not gonna happen.
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
- }
+ static void updateLockTaskFeaturesLocked(int flags, int userId) {
+ Binder.withCleanCallingIdentity(() -> {
+ try {
+ ActivityTaskManager.getService().updateLockTaskFeatures(userId, flags);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ Slog.wtf(LOG_TAG, "Remote Exception: ", e);
+ }
+ });
}
static void validateQualityConstant(int quality) {
@@ -8941,7 +8942,7 @@
policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED;
policy.mAffiliationIds.clear();
policy.mLockTaskPackages.clear();
- updateLockTaskPackagesLocked(policy.mLockTaskPackages, userId);
+ updateLockTaskPackagesLocked(mContext, policy.mLockTaskPackages, userId);
policy.mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
saveSettingsLocked(userId);
@@ -11217,7 +11218,7 @@
private String[] populateNonExemptAndExemptFromPolicyApps(String[] packageNames,
Set<String> outputExemptApps) {
Preconditions.checkArgument(outputExemptApps.isEmpty(), "outputExemptApps is not empty");
- List<String> exemptAppsList = listPolicyExemptAppsUnchecked();
+ List<String> exemptAppsList = listPolicyExemptAppsUnchecked(mContext);
if (exemptAppsList.isEmpty()) {
return packageNames;
}
@@ -11330,16 +11331,16 @@
hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS)
|| isDefaultDeviceOwner(caller) || isProfileOwner(caller));
- return listPolicyExemptAppsUnchecked();
+ return listPolicyExemptAppsUnchecked(mContext);
}
- private List<String> listPolicyExemptAppsUnchecked() {
+ private static List<String> listPolicyExemptAppsUnchecked(Context context) {
// TODO(b/181238156): decide whether it should only list the apps set by the resources,
// or also the "critical" apps defined by PersonalAppsSuspensionHelper (like SMS app).
// If it's the latter, refactor PersonalAppsSuspensionHelper so it (or a superclass) takes
// the resources on constructor.
- String[] core = mContext.getResources().getStringArray(R.array.policy_exempt_apps);
- String[] vendor = mContext.getResources().getStringArray(R.array.vendor_policy_exempt_apps);
+ String[] core = context.getResources().getStringArray(R.array.policy_exempt_apps);
+ String[] vendor = context.getResources().getStringArray(R.array.vendor_policy_exempt_apps);
int size = core.length + vendor.length;
Set<String> apps = new ArraySet<>(size);
@@ -11516,7 +11517,7 @@
&& (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
|| (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS)));
- List<String> exemptApps = listPolicyExemptAppsUnchecked();
+ List<String> exemptApps = listPolicyExemptAppsUnchecked(mContext);
if (exemptApps.contains(packageName)) {
Slogf.d(LOG_TAG, "setApplicationHidden(): ignoring %s as it's on policy-exempt list",
packageName);
@@ -12191,7 +12192,7 @@
// Store the settings persistently.
saveSettingsLocked(userHandle);
- updateLockTaskPackagesLocked(packages, userHandle);
+ updateLockTaskPackagesLocked(mContext, packages, userHandle);
}
@Override
@@ -12210,7 +12211,7 @@
@Override
public boolean isLockTaskPermitted(String pkg) {
// Check policy-exempt apps first, as it doesn't require the lock
- if (listPolicyExemptAppsUnchecked().contains(pkg)) {
+ if (listPolicyExemptAppsUnchecked(mContext).contains(pkg)) {
if (VERBOSE_LOG) {
Slogf.v(LOG_TAG, "isLockTaskPermitted(%s): returning true for policy-exempt app",
pkg);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
index f4953b4..9261d59 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
@@ -81,6 +81,10 @@
componentName.getPackageName(), componentName, Set.of(DEVICE_ADMIN_AUTHORITY));
}
+ static String getRoleAuthorityOf(String roleName) {
+ return ROLE_AUTHORITY_PREFIX + roleName;
+ }
+
private EnforcingAdmin(
String packageName, ComponentName componentName, Set<String> authorities) {
Objects.requireNonNull(packageName);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicy.java b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicy.java
new file mode 100644
index 0000000..9360fd7
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicy.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.annotation.Nullable;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.Set;
+
+final class LockTaskPolicy {
+ private Set<String> mPackages;
+ private int mFlags;
+
+ LockTaskPolicy(@Nullable Set<String> packages, int flags) {
+ mPackages = packages;
+ mFlags = flags;
+ }
+
+ @Nullable
+ Set<String> getPackages() {
+ return mPackages;
+ }
+
+ int getFlags() {
+ return mFlags;
+ }
+
+ void setPackages(Set<String> packages) {
+ mPackages = packages;
+ }
+
+ void setFlags(int flags) {
+ mFlags = flags;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ LockTaskPolicy other = (LockTaskPolicy) o;
+ return Objects.equals(mPackages, other.mPackages)
+ && mFlags == other.mFlags;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPackages, mFlags);
+ }
+
+ static final class LockTaskPolicySerializer extends PolicySerializer<LockTaskPolicy> {
+
+ private static final String ATTR_PACKAGES = ":packages";
+ private static final String ATTR_PACKAGES_SEPARATOR = ";";
+ private static final String ATTR_FLAGS = ":flags";
+
+ @Override
+ void saveToXml(
+ TypedXmlSerializer serializer, String attributeNamePrefix, LockTaskPolicy value)
+ throws IOException {
+ if (value.mPackages != null) {
+ serializer.attribute(
+ /* namespace= */ null,
+ attributeNamePrefix + ATTR_PACKAGES,
+ String.join(ATTR_PACKAGES_SEPARATOR, value.mPackages));
+ }
+ serializer.attributeInt(
+ /* namespace= */ null,
+ attributeNamePrefix + ATTR_FLAGS,
+ value.mFlags);
+ }
+
+ @Override
+ LockTaskPolicy readFromXml(TypedXmlPullParser parser, String attributeNamePrefix)
+ throws XmlPullParserException {
+ String packagesStr = parser.getAttributeValue(
+ /* namespace= */ null,
+ attributeNamePrefix + ATTR_PACKAGES);
+ Set<String> packages = packagesStr == null
+ ? null
+ : Set.of(packagesStr.split(ATTR_PACKAGES_SEPARATOR));
+ int flags = parser.getAttributeInt(
+ /* namespace= */ null,
+ attributeNamePrefix + ATTR_FLAGS);
+ return new LockTaskPolicy(packages, flags);
+ }
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index b22477b..3a18cb9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -82,11 +82,23 @@
new String[]{packageName, permission});
}
+ static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
+ DevicePolicyManager.LOCK_TASK_POLICY,
+ new TopPriority<>(List.of(
+ // TODO(b/258166155): add correct device lock role name
+ EnforcingAdmin.getRoleAuthorityOf("DeviceLock"),
+ EnforcingAdmin.DPC_AUTHORITY)),
+ POLICY_FLAG_LOCAL_ONLY_POLICY,
+ (LockTaskPolicy value, Context context, Integer userId, String[] args) ->
+ PolicyEnforcerCallbacks.setLockTask(value, context, userId),
+ new LockTaskPolicy.LockTaskPolicySerializer());
+
private static Map<String, PolicyDefinition<?>> sPolicyDefinitions = Map.of(
DevicePolicyManager.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE,
DevicePolicyManager.PERMISSION_GRANT_POLICY_KEY, PERMISSION_GRANT_NO_ARGS
);
+
private final String mPolicyKey;
private final String mPolicyDefinitionKey;
private final ResolutionMechanism<V> mResolutionMechanism;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 2b63218..b645b97 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -29,6 +29,7 @@
import com.android.server.utils.Slogf;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -103,6 +104,14 @@
}
}
+ static boolean setLockTask(
+ @Nullable LockTaskPolicy policy, @NonNull Context context, int userId) {
+ DevicePolicyManagerService.updateLockTaskPackagesLocked(
+ context, List.copyOf(policy.getPackages()), userId);
+ DevicePolicyManagerService.updateLockTaskFeaturesLocked(policy.getFlags(), userId);
+ return true;
+ }
+
private static class BlockingCallback {
private final CountDownLatch mLatch = new CountDownLatch(1);
private final AtomicReference<Boolean> mValue = new AtomicReference<>();