Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d32f01ba authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Don't remove mainline modules if they declare support in manifest...

Merge "Don't remove mainline modules if they declare support in manifest meta-data" into sc-dev am: 19e03e84

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13954467

Change-Id: I4601f2879bc148637ad6cef1ba9f0cea59ce506d
parents eca224b0 19e03e84
Loading
Loading
Loading
Loading
+95 −1
Original line number Diff line number Diff line
@@ -19,17 +19,26 @@ package com.android.server.devicepolicy;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_USER;
import static android.content.pm.PackageManager.GET_META_DATA;

import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.devicepolicy.DevicePolicyManagerService.dumpResources;

import static java.util.Objects.requireNonNull;

import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.util.ArraySet;
@@ -39,9 +48,13 @@ import android.view.inputmethod.InputMethodInfo;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.pm.ApexManager;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
@@ -51,6 +64,18 @@ import java.util.Set;
public class OverlayPackagesProvider {

    protected static final String TAG = "OverlayPackagesProvider";
    private static final Map<String, String> sActionToMetadataKeyMap = new HashMap<>();
    {
        sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_USER, REQUIRED_APP_MANAGED_USER);
        sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_PROFILE, REQUIRED_APP_MANAGED_PROFILE);
        sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_DEVICE, REQUIRED_APP_MANAGED_DEVICE);
    }
    private static final Set<String> sAllowedActions = new HashSet<>();
    {
        sAllowedActions.add(ACTION_PROVISION_MANAGED_USER);
        sAllowedActions.add(ACTION_PROVISION_MANAGED_PROFILE);
        sAllowedActions.add(ACTION_PROVISION_MANAGED_DEVICE);
    }

    private final PackageManager mPm;
    private final Context mContext;
@@ -64,6 +89,8 @@ public class OverlayPackagesProvider {
    interface Injector {
        @NonNull
        List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);

        String getActiveApexPackageNameContainingPackage(String packageName);
    }

    private static final class DefaultInjector implements Injector {
@@ -72,6 +99,11 @@ public class OverlayPackagesProvider {
        public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
            return InputMethodManagerInternal.get().getInputMethodListAsUser(userId);
        }

        @Override
        public String getActiveApexPackageNameContainingPackage(String packageName) {
            return ApexManager.getInstance().getActiveApexPackageNameContainingPackage(packageName);
        }
    }

    @VisibleForTesting
@@ -83,7 +115,8 @@ public class OverlayPackagesProvider {

    /**
     * Computes non-required apps. All the system apps with a launcher that are not in
     * the required set of packages will be considered as non-required apps.
     * the required set of packages, and all mainline modules that are not declared as required
     * via metadata in their manifests, will be considered as non-required apps.
     *
     * Note: If an app is mistakenly listed as both required and disallowed, it will be treated as
     * disallowed.
@@ -99,15 +132,76 @@ public class OverlayPackagesProvider {
    @NonNull
    public Set<String> getNonRequiredApps(@NonNull ComponentName admin, int userId,
            @NonNull String provisioningAction) {
        requireNonNull(admin);
        checkArgument(sAllowedActions.contains(provisioningAction));
        final Set<String> nonRequiredApps = getLaunchableApps(userId);
        // Newly installed system apps are uninstalled when they are not required and are either
        // disallowed or have a launcher icon.
        nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName()));
        nonRequiredApps.removeAll(getSystemInputMethods(userId));
        nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
        nonRequiredApps.removeAll(
                getRequiredAppsMainlineModules(nonRequiredApps, provisioningAction));
        return nonRequiredApps;
    }

    /**
     * Returns a subset of {@code packageNames} whose packages are mainline modules declared as
     * required apps via their app metadata.
     * @see DevicePolicyManager#REQUIRED_APP_MANAGED_USER
     * @see DevicePolicyManager#REQUIRED_APP_MANAGED_DEVICE
     * @see DevicePolicyManager#REQUIRED_APP_MANAGED_PROFILE
     */
    private Set<String> getRequiredAppsMainlineModules(
            Set<String> packageNames,
            String provisioningAction) {
        final Set<String> result = new HashSet<>();
        for (String packageName : packageNames) {
            if (!isMainlineModule(packageName)) {
                continue;
            }
            if (!isRequiredAppDeclaredInMetadata(packageName, provisioningAction)) {
                continue;
            }
            result.add(packageName);
        }
        return result;
    }

    private boolean isRequiredAppDeclaredInMetadata(String packageName, String provisioningAction) {
        PackageInfo packageInfo;
        try {
            packageInfo = mPm.getPackageInfo(packageName, GET_META_DATA);
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
        final String metadataKey = sActionToMetadataKeyMap.get(provisioningAction);
        return packageInfo.applicationInfo.metaData.getBoolean(metadataKey);
    }

    /**
     * Returns {@code true} if the provided package name is a mainline module.
     * <p>There are 2 types of mainline modules: a regular mainline module and apk-in-apex module.
     */
    private boolean isMainlineModule(String packageName) {
        return isRegularMainlineModule(packageName) || isApkInApexMainlineModule(packageName);
    }

    private boolean isRegularMainlineModule(String packageName) {
        try {
            mPm.getModuleInfo(packageName, /* flags= */ 0);
            return true;
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }

    private boolean isApkInApexMainlineModule(String packageName) {
        final String apexPackageName =
                mInjector.getActiveApexPackageNameContainingPackage(packageName);
        return apexPackageName != null;
    }

    private Set<String> getLaunchableApps(int userId) {
        final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
        launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+123 −1
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@ package com.android.server.devicepolicy;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_USER;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -31,13 +34,17 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.os.Bundle;
import android.test.mock.MockPackageManager;
import android.view.inputmethod.InputMethodInfo;

import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

@@ -51,8 +58,10 @@ import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
@@ -76,6 +85,8 @@ public class OverlayPackagesProviderTest {

    private FakePackageManager mPackageManager;
    private String[] mSystemAppsWithLauncher;
    private Set<String> mRegularMainlineModules = new HashSet<>();
    private Map<String, String> mMainlineModuleToDeclaredMetadataMap = new HashMap<>();
    private OverlayPackagesProvider mHelper;

    @Before
@@ -168,7 +179,7 @@ public class OverlayPackagesProviderTest {
        setSystemAppsWithLauncher("app.a", "app.b");
        setSystemInputMethods("app.a");

        verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "app.a", "app.b");
        verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "app.b");
    }

    @Test
@@ -257,6 +268,93 @@ public class OverlayPackagesProviderTest {
                R.array.vendor_disallowed_apps_managed_profile);
    }

    @Test
    public void testGetNonRequiredApps_mainlineModules_managedProfile_works() {
        setupApexModulesWithManagedProfile("package1");
        setupRegularModulesWithManagedProfile("package2");
        setSystemAppsWithLauncher("package1", "package2", "package3");

        verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "package3");
    }

    @Test
    public void testGetNonRequiredApps_mainlineModules_managedDevice_works() {
        setupApexModulesWithManagedDevice("package1");
        setupRegularModulesWithManagedDevice("package2");
        setSystemAppsWithLauncher("package1", "package2", "package3");

        verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_DEVICE, "package3");
    }

    @Test
    public void testGetNonRequiredApps_mainlineModules_managedUser_works() {
        setupApexModulesWithManagedUser("package1");
        setupRegularModulesWithManagedUser("package2");
        setSystemAppsWithLauncher("package1", "package2", "package3");

        verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_USER, "package3");
    }

    @Test
    public void testGetNonRequiredApps_mainlineModules_noMetadata_works() {
        setupApexModulesWithNoMetadata("package1");
        setupRegularModulesWithNoMetadata("package2");
        setSystemAppsWithLauncher("package1", "package2", "package3");

        verifyAppsAreNonRequired(
                ACTION_PROVISION_MANAGED_PROFILE, "package1", "package2", "package3");
    }

    private void setupRegularModulesWithManagedUser(String... regularModules) {
        setupRegularModulesWithMetadata(regularModules, REQUIRED_APP_MANAGED_USER);
    }

    private void setupRegularModulesWithManagedDevice(String... regularModules) {
        setupRegularModulesWithMetadata(regularModules, REQUIRED_APP_MANAGED_DEVICE);
    }

    private void setupRegularModulesWithManagedProfile(String... regularModules) {
        setupRegularModulesWithMetadata(regularModules, REQUIRED_APP_MANAGED_PROFILE);
    }

    private void setupRegularModulesWithNoMetadata(String... regularModules) {
        mRegularMainlineModules.addAll(Arrays.asList(regularModules));
    }

    private void setupRegularModulesWithMetadata(String[] regularModules, String metadataKey) {
        for (String regularModule : regularModules) {
            mRegularMainlineModules.add(regularModule);
            mMainlineModuleToDeclaredMetadataMap.put(regularModule, metadataKey);
        }
    }

    private void setupApexModulesWithManagedUser(String... apexPackageNames) {
        setupApexModulesWithMetadata(apexPackageNames, REQUIRED_APP_MANAGED_USER);
    }

    private void setupApexModulesWithManagedDevice(String... apexPackageNames) {
        setupApexModulesWithMetadata(apexPackageNames, REQUIRED_APP_MANAGED_DEVICE);
    }

    private void setupApexModulesWithManagedProfile(String... apexPackageNames) {
        setupApexModulesWithMetadata(apexPackageNames, REQUIRED_APP_MANAGED_PROFILE);
    }

    private void setupApexModulesWithNoMetadata(String... apexPackageNames) {
        for (String apexPackageName : apexPackageNames) {
            when(mInjector.getActiveApexPackageNameContainingPackage(eq(apexPackageName)))
                    .thenReturn("apex");
        }
    }

    private void setupApexModulesWithMetadata(String[] apexPackageNames, String metadataKey) {
        for (String apexPackageName : apexPackageNames) {
            when(mInjector.getActiveApexPackageNameContainingPackage(eq(apexPackageName)))
                    .thenReturn("apex");
            mMainlineModuleToDeclaredMetadataMap.put(apexPackageName, metadataKey);
        }
    }

    private ArrayList<String> getStringArrayInRealResources(int id) {
        return new ArrayList<>(Arrays.asList(mRealResources.getStringArray(id)));
    }
@@ -383,5 +481,29 @@ public class OverlayPackagesProviderTest {
            }
            return result;
        }

        @NonNull
        @Override
        public PackageInfo getPackageInfo(String packageName, int flags) {
            final PackageInfo packageInfo = new PackageInfo();
            final ApplicationInfo applicationInfo = new ApplicationInfo();
            applicationInfo.metaData = new Bundle();
            if (mMainlineModuleToDeclaredMetadataMap.containsKey(packageName)) {
                applicationInfo.metaData.putBoolean(
                        mMainlineModuleToDeclaredMetadataMap.get(packageName), true);
            }
            packageInfo.applicationInfo = applicationInfo;
            return packageInfo;
        }

        @NonNull
        @Override
        public ModuleInfo getModuleInfo(@NonNull String packageName, int flags)
                throws NameNotFoundException {
            if (!mRegularMainlineModules.contains(packageName)) {
                throw new NameNotFoundException("package does not exist");
            }
            return new ModuleInfo().setName(packageName);
        }
    }
}