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.annotation.Nullable;
20import android.content.pm.ApplicationInfo;
21import android.content.pm.IPackageManager;
22import android.content.pm.PackageManager;
23import android.content.res.Resources;
24import android.os.RemoteException;
25import android.telephony.TelephonyManager;
26import android.util.Slog;
27
28import com.android.internal.annotations.VisibleForTesting;
29
30import java.util.ArrayList;
31import java.util.List;
32
33/**
34 * Utilities for handling carrier applications.
35 * @hide
36 */
37public final class CarrierAppUtils {
38    private static final String TAG = "CarrierAppUtils";
39
40    private static final boolean DEBUG = false; // STOPSHIP if true
41
42    private CarrierAppUtils() {}
43
44    /**
45     * Handle preinstalled carrier apps which should be disabled until a matching SIM is inserted.
46     *
47     * Evaluates the list of applications in config_disabledUntilUsedPreinstalledCarrierApps. We
48     * want to disable each such application which is present on the system image until the user
49     * inserts a SIM which causes that application to gain carrier privilege (indicating a "match"),
50     * without interfering with the user if they opt to enable/disable the app explicitly.
51     *
52     * So, for each such app, we either disable until used IFF the app is not carrier privileged AND
53     * in the default state (e.g. not explicitly DISABLED/DISABLED_BY_USER/ENABLED), or we enable if
54     * the app is carrier privileged and in either the default state or DISABLED_UNTIL_USED.
55     *
56     * When enabling a carrier app we also grant it default permissions.
57     *
58     * This method is idempotent and is safe to be called at any time; it should be called once at
59     * system startup prior to any application running, as well as any time the set of carrier
60     * privileged apps may have changed.
61     */
62    public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
63            IPackageManager packageManager, TelephonyManager telephonyManager, int userId) {
64        if (DEBUG) {
65            Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
66        }
67        String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
68                com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
69        disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager, userId,
70                systemCarrierAppsDisabledUntilUsed);
71    }
72
73    /**
74     * Like {@link #disableCarrierAppsUntilPrivileged(String, IPackageManager, TelephonyManager,
75     * int)}, but assumes that no carrier apps have carrier privileges.
76     *
77     * This prevents a potential race condition on first boot - since the app's default state is
78     * enabled, we will initially disable it when the telephony stack is first initialized as it has
79     * not yet read the carrier privilege rules. However, since telephony is initialized later on
80     * late in boot, the app being disabled may have already been started in response to certain
81     * broadcasts. The app will continue to run (briefly) after being disabled, before the Package
82     * Manager can kill it, and this can lead to crashes as the app is in an unexpected state.
83     */
84    public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
85            IPackageManager packageManager, int userId) {
86        if (DEBUG) {
87            Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
88        }
89        String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
90                com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
91        disableCarrierAppsUntilPrivileged(callingPackage, packageManager,
92                null /* telephonyManager */, userId, systemCarrierAppsDisabledUntilUsed);
93    }
94
95    // Must be public b/c framework unit tests can't access package-private methods.
96    @VisibleForTesting
97    public static void disableCarrierAppsUntilPrivileged(String callingPackage,
98            IPackageManager packageManager, @Nullable TelephonyManager telephonyManager, int userId,
99            String[] systemCarrierAppsDisabledUntilUsed) {
100        List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
101                userId, systemCarrierAppsDisabledUntilUsed);
102        if (candidates == null || candidates.isEmpty()) {
103            return;
104        }
105
106        List<String> enabledCarrierPackages = new ArrayList<>();
107
108        try {
109            for (ApplicationInfo ai : candidates) {
110                String packageName = ai.packageName;
111                boolean hasPrivileges = telephonyManager != null &&
112                        telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
113                                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
114
115                // Only update enabled state for the app on /system. Once it has been updated we
116                // shouldn't touch it.
117                if (!ai.isUpdatedSystemApp()) {
118                    if (hasPrivileges
119                            && (ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
120                            || ai.enabledSetting ==
121                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
122                        Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
123                                + userId);
124                        packageManager.setApplicationEnabledSetting(packageName,
125                                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
126                                PackageManager.DONT_KILL_APP, userId, callingPackage);
127                    } else if (!hasPrivileges
128                            && ai.enabledSetting ==
129                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
130                        Slog.i(TAG, "Update state(" + packageName
131                                + "): DISABLED_UNTIL_USED for user " + userId);
132                        packageManager.setApplicationEnabledSetting(packageName,
133                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0,
134                                userId, callingPackage);
135                    }
136                }
137
138                // Always re-grant default permissions to carrier apps w/ privileges.
139                if (hasPrivileges) {
140                    enabledCarrierPackages.add(ai.packageName);
141                }
142            }
143
144            if (!enabledCarrierPackages.isEmpty()) {
145                // Since we enabled at least one app, ensure we grant default permissions to those
146                // apps.
147                String[] packageNames = new String[enabledCarrierPackages.size()];
148                enabledCarrierPackages.toArray(packageNames);
149                packageManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId);
150            }
151        } catch (RemoteException e) {
152            Slog.w(TAG, "Could not reach PackageManager", e);
153        }
154    }
155
156    /**
157     * Returns the list of "default" carrier apps.
158     *
159     * This is the subset of apps returned by
160     * {@link #getDefaultCarrierAppCandidates(IPackageManager, int)} which currently have carrier
161     * privileges per the SIM(s) inserted in the device.
162     */
163    public static List<ApplicationInfo> getDefaultCarrierApps(IPackageManager packageManager,
164            TelephonyManager telephonyManager, int userId) {
165        // Get all system apps from the default list.
166        List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(packageManager, userId);
167        if (candidates == null || candidates.isEmpty()) {
168            return null;
169        }
170
171        // Filter out apps without carrier privileges.
172        // Iterate from the end to avoid creating an Iterator object and because we will be removing
173        // elements from the list as we pass through it.
174        for (int i = candidates.size() - 1; i >= 0; i--) {
175            ApplicationInfo ai = candidates.get(i);
176            String packageName = ai.packageName;
177            boolean hasPrivileges =
178                    telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
179                            TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
180            if (!hasPrivileges) {
181                candidates.remove(i);
182            }
183        }
184
185        return candidates;
186    }
187
188    /**
189     * Returns the list of "default" carrier app candidates.
190     *
191     * These are the apps subject to the hiding/showing logic in
192     * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, IPackageManager,
193     * TelephonyManager, int)}, as well as the apps which should have default permissions granted,
194     * when a matching SIM is inserted.
195     *
196     * Whether or not the app is actually considered a default app depends on whether the app has
197     * carrier privileges as determined by the SIMs in the device.
198     */
199    public static List<ApplicationInfo> getDefaultCarrierAppCandidates(
200            IPackageManager packageManager, int userId) {
201        String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
202                com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
203        return getDefaultCarrierAppCandidatesHelper(packageManager, userId,
204                systemCarrierAppsDisabledUntilUsed);
205    }
206
207    private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper(
208            IPackageManager packageManager, int userId,
209            String[] systemCarrierAppsDisabledUntilUsed) {
210        if (systemCarrierAppsDisabledUntilUsed == null
211                || systemCarrierAppsDisabledUntilUsed.length == 0) {
212            return null;
213        }
214        List<ApplicationInfo> apps = null;
215        try {
216            apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length);
217            for (String packageName : systemCarrierAppsDisabledUntilUsed) {
218                ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
219                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
220                if (ai == null) {
221                    // No app found for packageName
222                    continue;
223                }
224                if (!ai.isSystemApp()) {
225                    continue;
226                }
227                apps.add(ai);
228            }
229        } catch (RemoteException e) {
230            Slog.w(TAG, "Could not reach PackageManager", e);
231        }
232        return apps;
233    }
234}
235