CarrierAppUtils.java revision b7e26fb1ad1802025cc3a01eeba6acfbc8f3f444
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.internal.telephony;
18
19import android.content.pm.ApplicationInfo;
20import android.content.pm.IPackageManager;
21import android.content.pm.PackageManager;
22import android.content.res.Resources;
23import android.os.RemoteException;
24import android.telephony.TelephonyManager;
25import android.util.Slog;
26
27import com.android.internal.annotations.VisibleForTesting;
28
29import java.util.ArrayList;
30import java.util.List;
31
32/**
33 * Utilities for handling carrier applications.
34 * @hide
35 */
36public final class CarrierAppUtils {
37    private static final String TAG = "CarrierAppUtils";
38
39    private static final boolean DEBUG = false; // STOPSHIP if true
40
41    private CarrierAppUtils() {}
42
43    /**
44     * Handle preinstalled carrier apps which should be disabled until a matching SIM is inserted.
45     *
46     * Evaluates the list of applications in config_disabledUntilUsedPreinstalledCarrierApps. We
47     * want to disable each such application which is present on the system image until the user
48     * inserts a SIM which causes that application to gain carrier privilege (indicating a "match"),
49     * without interfering with the user if they opt to enable/disable the app explicitly.
50     *
51     * So, for each such app, we either disable until used IFF the app is not carrier privileged AND
52     * in the default state (e.g. not explicitly DISABLED/DISABLED_BY_USER/ENABLED), or we enable if
53     * the app is carrier privileged and in either the default state or DISABLED_UNTIL_USED.
54     *
55     * When enabling a carrier app we also grant it default permissions.
56     *
57     * This method is idempotent and is safe to be called at any time; it should be called once at
58     * system startup prior to any application running, as well as any time the set of carrier
59     * privileged apps may have changed.
60     */
61    public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
62            IPackageManager packageManager, TelephonyManager telephonyManager, int userId) {
63        if (DEBUG) {
64            Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
65        }
66        String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
67                com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
68        disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager, userId,
69                systemCarrierAppsDisabledUntilUsed);
70    }
71
72    // Must be public b/c framework unit tests can't access package-private methods.
73    @VisibleForTesting
74    public static void disableCarrierAppsUntilPrivileged(String callingPackage,
75            IPackageManager packageManager, TelephonyManager telephonyManager, int userId,
76            String[] systemCarrierAppsDisabledUntilUsed) {
77        List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
78                userId, systemCarrierAppsDisabledUntilUsed);
79        if (candidates == null || candidates.isEmpty()) {
80            return;
81        }
82
83        List<String> enabledCarrierPackages = new ArrayList<>();
84
85        try {
86            for (ApplicationInfo ai : candidates) {
87                String packageName = ai.packageName;
88                boolean hasPrivileges =
89                        telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
90                                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
91
92                // Only update enabled state for the app on /system. Once it has been updated we
93                // shouldn't touch it.
94                if (!ai.isUpdatedSystemApp()) {
95                    if (hasPrivileges
96                            && (ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
97                            || ai.enabledSetting ==
98                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
99                        Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
100                                + userId);
101                        packageManager.setApplicationEnabledSetting(packageName,
102                                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
103                                PackageManager.DONT_KILL_APP, userId, callingPackage);
104                    } else if (!hasPrivileges
105                            && ai.enabledSetting ==
106                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
107                        Slog.i(TAG, "Update state(" + packageName
108                                + "): DISABLED_UNTIL_USED for user " + userId);
109                        packageManager.setApplicationEnabledSetting(packageName,
110                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0,
111                                userId, callingPackage);
112                    }
113                }
114
115                // Always re-grant default permissions to carrier apps w/ privileges.
116                if (hasPrivileges) {
117                    enabledCarrierPackages.add(ai.packageName);
118                }
119            }
120
121            if (!enabledCarrierPackages.isEmpty()) {
122                // Since we enabled at least one app, ensure we grant default permissions to those
123                // apps.
124                String[] packageNames = new String[enabledCarrierPackages.size()];
125                enabledCarrierPackages.toArray(packageNames);
126                packageManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId);
127            }
128        } catch (RemoteException e) {
129            Slog.w(TAG, "Could not reach PackageManager", e);
130        }
131    }
132
133    /**
134     * Returns the list of "default" carrier apps.
135     *
136     * This is the subset of apps returned by
137     * {@link #getDefaultCarrierAppCandidates(IPackageManager, int)} which currently have carrier
138     * privileges per the SIM(s) inserted in the device.
139     */
140    public static List<ApplicationInfo> getDefaultCarrierApps(IPackageManager packageManager,
141            TelephonyManager telephonyManager, int userId) {
142        // Get all system apps from the default list.
143        List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(packageManager, userId);
144        if (candidates == null || candidates.isEmpty()) {
145            return null;
146        }
147
148        // Filter out apps without carrier privileges.
149        // Iterate from the end to avoid creating an Iterator object and because we will be removing
150        // elements from the list as we pass through it.
151        for (int i = candidates.size() - 1; i >= 0; i--) {
152            ApplicationInfo ai = candidates.get(i);
153            String packageName = ai.packageName;
154            boolean hasPrivileges =
155                    telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
156                            TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
157            if (!hasPrivileges) {
158                candidates.remove(i);
159            }
160        }
161
162        return candidates;
163    }
164
165    /**
166     * Returns the list of "default" carrier app candidates.
167     *
168     * These are the apps subject to the hiding/showing logic in
169     * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, IPackageManager,
170     * TelephonyManager, int)}, as well as the apps which should have default permissions granted,
171     * when a matching SIM is inserted.
172     *
173     * Whether or not the app is actually considered a default app depends on whether the app has
174     * carrier privileges as determined by the SIMs in the device.
175     */
176    public static List<ApplicationInfo> getDefaultCarrierAppCandidates(
177            IPackageManager packageManager, int userId) {
178        String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
179                com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
180        return getDefaultCarrierAppCandidatesHelper(packageManager, userId,
181                systemCarrierAppsDisabledUntilUsed);
182    }
183
184    private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper(
185            IPackageManager packageManager, int userId,
186            String[] systemCarrierAppsDisabledUntilUsed) {
187        if (systemCarrierAppsDisabledUntilUsed == null
188                || systemCarrierAppsDisabledUntilUsed.length == 0) {
189            return null;
190        }
191        List<ApplicationInfo> apps = null;
192        try {
193            apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length);
194            for (String packageName : systemCarrierAppsDisabledUntilUsed) {
195                ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
196                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
197                if (ai == null) {
198                    // No app found for packageName
199                    continue;
200                }
201                if (!ai.isSystemApp()) {
202                    continue;
203                }
204                apps.add(ai);
205            }
206        } catch (RemoteException e) {
207            Slog.w(TAG, "Could not reach PackageManager", e);
208        }
209        return apps;
210    }
211}
212