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

Commit 2862ed25 authored by Jeff Davidson's avatar Jeff Davidson Committed by android-build-merger
Browse files

Add support for carrier \\"associated\\" apps. am: 24b9d960

am: 19af77d2

Change-Id: I089db772e37b7d07a5423793aced78f2b3a9a1ae
parents ea072809 19af77d2
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -6232,6 +6232,20 @@ public final class Settings {
         */
        public static final int VR_DISPLAY_MODE_OFF = 1;

        /**
         * Whether CarrierAppUtils#disableCarrierAppsUntilPrivileged has been executed at least
         * once.
         *
         * <p>This is used to ensure that we only take one pass which will disable apps that are not
         * privileged (if any). From then on, we only want to enable apps (when a matching SIM is
         * inserted), to avoid disabling an app that the user might actively be using.
         *
         * <p>Will be set to 1 once executed.
         *
         * @hide
         */
        public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";

        /**
         * Whether parent user can access remote contact in managed profile.
         *
+31 −0
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Loads global system configuration info.
@@ -122,6 +124,11 @@ public class SystemConfig {
    // These are the permitted backup transport service components
    final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>();

    // These are the packages of carrier-associated apps which should be disabled until used until
    // a SIM is inserted which grants carrier privileges to that carrier app.
    final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps =
            new ArrayMap<>();

    public static SystemConfig getInstance() {
        synchronized (SystemConfig.class) {
            if (sInstance == null) {
@@ -183,6 +190,10 @@ public class SystemConfig {
        return mBackupTransportWhitelist;
    }

    public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() {
        return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
    }

    SystemConfig() {
        // Read configuration from system
        readPermissions(Environment.buildPath(
@@ -476,6 +487,26 @@ public class SystemConfig {
                        }
                    }
                    XmlUtils.skipCurrentTag(parser);
                } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name)
                        && allowAppConfigs) {
                    String pkgname = parser.getAttributeValue(null, "package");
                    String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage");
                    if (pkgname == null || carrierPkgname == null) {
                        Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app"
                                + " without package or carrierAppPackage in " + permFile + " at "
                                + parser.getPositionDescription());
                    } else {
                        List<String> associatedPkgs =
                                mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
                                        carrierPkgname);
                        if (associatedPkgs == null) {
                            associatedPkgs = new ArrayList<>();
                            mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
                                    carrierPkgname, associatedPkgs);
                        }
                        associatedPkgs.add(pkgname);
                    }
                    XmlUtils.skipCurrentTag(parser);
                } else {
                    XmlUtils.skipCurrentTag(parser);
                    continue;
+5 −4
Original line number Diff line number Diff line
@@ -1966,10 +1966,6 @@ public class PackageManagerService extends IPackageManager.Stub {
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        m.enableSystemUserPackages();
        // Disable any carrier apps. We do this very early in boot to prevent the apps from being
        // disabled after already being started.
        CarrierAppUtils.disableCarrierAppsUntilPrivileged(context.getOpPackageName(), m,
                UserHandle.USER_SYSTEM);
        ServiceManager.addService("package", m);
        return m;
    }
@@ -17941,6 +17937,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    public void systemReady() {
        mSystemReady = true;
        // Disable any carrier apps. We do this very early in boot to prevent the apps from being
        // disabled after already being started.
        CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
                mContext.getContentResolver(), UserHandle.USER_SYSTEM);
        // Read the compatibilty setting when the system is ready.
        boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
                mContext.getContentResolver(),
+166 −40
Original line number Diff line number Diff line
@@ -17,18 +17,23 @@
package com.android.internal.telephony;

import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.RemoteException;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemConfig;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Utilities for handling carrier applications.
@@ -53,6 +58,11 @@ public final class CarrierAppUtils {
     * in the default state (e.g. not explicitly DISABLED/DISABLED_BY_USER/ENABLED), or we enable if
     * the app is carrier privileged and in either the default state or DISABLED_UNTIL_USED.
     *
     * In addition, there is a list of carrier-associated applications in
     * {@link SystemConfig#getDisabledUntilUsedPreinstalledCarrierAssociatedApps}. Each app in this
     * list is associated with a carrier app. When the given carrier app is enabled/disabled per the
     * above, the associated applications are enabled/disabled to match.
     *
     * When enabling a carrier app we also grant it default permissions.
     *
     * This method is idempotent and is safe to be called at any time; it should be called once at
@@ -60,19 +70,24 @@ public final class CarrierAppUtils {
     * privileged apps may have changed.
     */
    public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
            IPackageManager packageManager, TelephonyManager telephonyManager, int userId) {
            IPackageManager packageManager, TelephonyManager telephonyManager,
            ContentResolver contentResolver, int userId) {
        if (DEBUG) {
            Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
        }
        SystemConfig config = SystemConfig.getInstance();
        String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
                com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
        disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager, userId,
                systemCarrierAppsDisabledUntilUsed);
        ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
                config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
        disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager,
                contentResolver, userId, systemCarrierAppsDisabledUntilUsed,
                systemCarrierAssociatedAppsDisabledUntilUsed);
    }

    /**
     * Like {@link #disableCarrierAppsUntilPrivileged(String, IPackageManager, TelephonyManager,
     * int)}, but assumes that no carrier apps have carrier privileges.
     * ContentResolver, int)}, but assumes that no carrier apps have carrier privileges.
     *
     * This prevents a potential race condition on first boot - since the app's default state is
     * enabled, we will initially disable it when the telephony stack is first initialized as it has
@@ -82,29 +97,43 @@ public final class CarrierAppUtils {
     * Manager can kill it, and this can lead to crashes as the app is in an unexpected state.
     */
    public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
            IPackageManager packageManager, int userId) {
            IPackageManager packageManager, ContentResolver contentResolver, int userId) {
        if (DEBUG) {
            Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
        }
        SystemConfig config = SystemConfig.getInstance();
        String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
                com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
        ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
                config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
        disableCarrierAppsUntilPrivileged(callingPackage, packageManager,
                null /* telephonyManager */, userId, systemCarrierAppsDisabledUntilUsed);
                null /* telephonyManager */, contentResolver, userId,
                systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed);
    }

    // Must be public b/c framework unit tests can't access package-private methods.
    @VisibleForTesting
    public static void disableCarrierAppsUntilPrivileged(String callingPackage,
            IPackageManager packageManager, @Nullable TelephonyManager telephonyManager, int userId,
            String[] systemCarrierAppsDisabledUntilUsed) {
            IPackageManager packageManager, @Nullable TelephonyManager telephonyManager,
            ContentResolver contentResolver, int userId,
            String[] systemCarrierAppsDisabledUntilUsed,
            ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
        List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
                userId, systemCarrierAppsDisabledUntilUsed);
        if (candidates == null || candidates.isEmpty()) {
            return;
        }

        Map<String, List<ApplicationInfo>> associatedApps = getDefaultCarrierAssociatedAppsHelper(
                packageManager,
                userId,
                systemCarrierAssociatedAppsDisabledUntilUsed);

        List<String> enabledCarrierPackages = new ArrayList<>();

        boolean hasRunOnce = Settings.Secure.getIntForUser(
                contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 0, userId) == 1;

        try {
            for (ApplicationInfo ai : candidates) {
                String packageName = ai.packageName;
@@ -112,35 +141,94 @@ public final class CarrierAppUtils {
                        telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
                                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;

                // Only update enabled state for the app on /system. Once it has been updated we
                // shouldn't touch it.
                if (!ai.isUpdatedSystemApp()) {
                    if (hasPrivileges
                            && (ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                if (hasPrivileges) {
                    // Only update enabled state for the app on /system. Once it has been
                    // updated we shouldn't touch it.
                    if (!ai.isUpdatedSystemApp()
                            && (ai.enabledSetting ==
                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                            || ai.enabledSetting ==
                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
                        Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
                                + userId);
                        packageManager.setApplicationEnabledSetting(packageName,
                        packageManager.setApplicationEnabledSetting(
                                packageName,
                                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                                PackageManager.DONT_KILL_APP,
                                userId,
                                callingPackage);
                    }

                    // Also enable any associated apps for this carrier app.
                    List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
                    if (associatedAppList != null) {
                        for (ApplicationInfo associatedApp : associatedAppList) {
                            if (associatedApp.enabledSetting ==
                                    PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                                    || associatedApp.enabledSetting ==
                                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                                Slog.i(TAG, "Update associated state(" + associatedApp.packageName
                                        + "): ENABLED for user " + userId);
                                packageManager.setApplicationEnabledSetting(
                                        associatedApp.packageName,
                                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                                PackageManager.DONT_KILL_APP, userId, callingPackage);
                    } else if (!hasPrivileges
                                        PackageManager.DONT_KILL_APP,
                                        userId,
                                        callingPackage);
                            }
                        }
                    }

                    // Always re-grant default permissions to carrier apps w/ privileges.
                    enabledCarrierPackages.add(ai.packageName);
                } else {  // No carrier privileges
                    // Only update enabled state for the app on /system. Once it has been
                    // updated we shouldn't touch it.
                    if (!ai.isUpdatedSystemApp()
                            && ai.enabledSetting ==
                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
                        Slog.i(TAG, "Update state(" + packageName
                                + "): DISABLED_UNTIL_USED for user " + userId);
                        packageManager.setApplicationEnabledSetting(packageName,
                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0,
                                userId, callingPackage);
                    }
                        packageManager.setApplicationEnabledSetting(
                                packageName,
                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
                                0,
                                userId,
                                callingPackage);
                    }

                // Always re-grant default permissions to carrier apps w/ privileges.
                if (hasPrivileges) {
                    enabledCarrierPackages.add(ai.packageName);
                    // Also disable any associated apps for this carrier app if this is the first
                    // run. We avoid doing this a second time because it is brittle to rely on the
                    // distinction between "default" and "enabled".
                    if (!hasRunOnce) {
                        List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
                        if (associatedAppList != null) {
                            for (ApplicationInfo associatedApp : associatedAppList) {
                                if (associatedApp.enabledSetting
                                        == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
                                    Slog.i(TAG,
                                            "Update associated state(" + associatedApp.packageName
                                                    + "): DISABLED_UNTIL_USED for user " + userId);
                                    packageManager.setApplicationEnabledSetting(
                                            associatedApp.packageName,
                                            PackageManager
                                                    .COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
                                            0,
                                            userId,
                                            callingPackage);
                                }
                            }
                        }
                    }
                }
            }

            // Mark the execution so we do not disable apps again.
            if (!hasRunOnce) {
                Settings.Secure.putIntForUser(
                        contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 1, userId);
            }

            if (!enabledCarrierPackages.isEmpty()) {
                // Since we enabled at least one app, ensure we grant default permissions to those
                // apps.
@@ -190,8 +278,8 @@ public final class CarrierAppUtils {
     *
     * These are the apps subject to the hiding/showing logic in
     * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, IPackageManager,
     * TelephonyManager, int)}, as well as the apps which should have default permissions granted,
     * when a matching SIM is inserted.
     * TelephonyManager, ContentResolver, int)}, as well as the apps which should have default
     * permissions granted, when a matching SIM is inserted.
     *
     * Whether or not the app is actually considered a default app depends on whether the app has
     * carrier privileges as determined by the SIMs in the device.
@@ -205,30 +293,68 @@ public final class CarrierAppUtils {
    }

    private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper(
            IPackageManager packageManager, int userId,
            IPackageManager packageManager,
            int userId,
            String[] systemCarrierAppsDisabledUntilUsed) {
        if (systemCarrierAppsDisabledUntilUsed == null
                || systemCarrierAppsDisabledUntilUsed.length == 0) {
            return null;
        }
        List<ApplicationInfo> apps = null;
        try {
            apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length);
            for (String packageName : systemCarrierAppsDisabledUntilUsed) {
                ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
                if (ai == null) {
                    // No app found for packageName
                    continue;
        List<ApplicationInfo> apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length);
        for (int i = 0; i < systemCarrierAppsDisabledUntilUsed.length; i++) {
            String packageName = systemCarrierAppsDisabledUntilUsed[i];
            ApplicationInfo ai =
                    getApplicationInfoIfSystemApp(packageManager, userId, packageName);
            if (ai != null) {
                apps.add(ai);
            }
                if (!ai.isSystemApp()) {
                    continue;
        }
                apps.add(ai);
        return apps;
    }

    private static Map<String, List<ApplicationInfo>> getDefaultCarrierAssociatedAppsHelper(
            IPackageManager packageManager,
            int userId,
            ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
        int size = systemCarrierAssociatedAppsDisabledUntilUsed.size();
        Map<String, List<ApplicationInfo>> associatedApps = new ArrayMap<>(size);
        for (int i = 0; i < size; i++) {
            String carrierAppPackage = systemCarrierAssociatedAppsDisabledUntilUsed.keyAt(i);
            List<String> associatedAppPackages =
                    systemCarrierAssociatedAppsDisabledUntilUsed.valueAt(i);
            for (int j = 0; j < associatedAppPackages.size(); j++) {
                ApplicationInfo ai =
                        getApplicationInfoIfSystemApp(
                                packageManager, userId, associatedAppPackages.get(j));
                // Only update enabled state for the app on /system. Once it has been updated we
                // shouldn't touch it.
                if (ai != null && !ai.isUpdatedSystemApp()) {
                    List<ApplicationInfo> appList = associatedApps.get(carrierAppPackage);
                    if (appList == null) {
                        appList = new ArrayList<>();
                        associatedApps.put(carrierAppPackage, appList);
                    }
                    appList.add(ai);
                }
            }
        }
        return associatedApps;
    }

    @Nullable
    private static ApplicationInfo getApplicationInfoIfSystemApp(
            IPackageManager packageManager,
            int userId,
            String packageName) {
        try {
            ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
                    PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId);
            if (ai != null && ai.isSystemApp()) {
                return ai;
            }
        } catch (RemoteException e) {
            Slog.w(TAG, "Could not reach PackageManager", e);
        }
        return apps;
        return null;
    }
}