1 /*
2  * Copyright (C) 2016 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 
17 package com.android.settings.applications;
18 
19 import android.Manifest;
20 import android.app.admin.DevicePolicyManager;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.ActivityInfo;
25 import android.content.pm.ComponentInfo;
26 import android.content.pm.IPackageManager;
27 import android.content.pm.PackageManager;
28 import android.content.pm.ResolveInfo;
29 import android.content.pm.ServiceInfo;
30 import android.content.pm.UserInfo;
31 import android.location.LocationManager;
32 import android.os.RemoteException;
33 import android.os.UserManager;
34 import android.service.euicc.EuiccService;
35 import android.telecom.DefaultDialerManager;
36 import android.text.TextUtils;
37 import android.util.ArraySet;
38 import android.util.Log;
39 
40 import androidx.annotation.VisibleForTesting;
41 
42 import com.android.internal.telephony.SmsApplication;
43 import com.android.settings.R;
44 
45 import java.util.ArrayList;
46 import java.util.List;
47 import java.util.Set;
48 
49 public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvider {
50     private static final String TAG = "AppFeatureProviderImpl";
51 
52     protected final Context mContext;
53     private final PackageManager mPm;
54     private final IPackageManager mPms;
55     private final DevicePolicyManager mDpm;
56     private final UserManager mUm;
57     /** Flags to use when querying PackageManager for Euicc component implementations. */
58     private static final int EUICC_QUERY_FLAGS =
59             PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
60                 | PackageManager.GET_RESOLVED_FILTER;
61 
ApplicationFeatureProviderImpl(Context context, PackageManager pm, IPackageManager pms, DevicePolicyManager dpm)62     public ApplicationFeatureProviderImpl(Context context, PackageManager pm,
63             IPackageManager pms, DevicePolicyManager dpm) {
64         mContext = context.getApplicationContext();
65         mPm = pm;
66         mPms = pms;
67         mDpm = dpm;
68         mUm = UserManager.get(mContext);
69     }
70 
71     @Override
calculateNumberOfPolicyInstalledApps(boolean async, NumberOfAppsCallback callback)72     public void calculateNumberOfPolicyInstalledApps(boolean async, NumberOfAppsCallback callback) {
73         final CurrentUserAndManagedProfilePolicyInstalledAppCounter counter =
74                 new CurrentUserAndManagedProfilePolicyInstalledAppCounter(mContext, mPm, callback);
75         if (async) {
76             counter.execute();
77         } else {
78             counter.executeInForeground();
79         }
80     }
81 
82     @Override
listPolicyInstalledApps(ListOfAppsCallback callback)83     public void listPolicyInstalledApps(ListOfAppsCallback callback) {
84         final CurrentUserPolicyInstalledAppLister lister =
85                 new CurrentUserPolicyInstalledAppLister(mPm, mUm, callback);
86         lister.execute();
87     }
88 
89     @Override
calculateNumberOfAppsWithAdminGrantedPermissions(String[] permissions, boolean async, NumberOfAppsCallback callback)90     public void calculateNumberOfAppsWithAdminGrantedPermissions(String[] permissions,
91             boolean async, NumberOfAppsCallback callback) {
92         final CurrentUserAndManagedProfileAppWithAdminGrantedPermissionsCounter counter =
93                 new CurrentUserAndManagedProfileAppWithAdminGrantedPermissionsCounter(mContext,
94                         permissions, mPm, mPms, mDpm, callback);
95         if (async) {
96             counter.execute();
97         } else {
98             counter.executeInForeground();
99         }
100     }
101 
102     @Override
listAppsWithAdminGrantedPermissions(String[] permissions, ListOfAppsCallback callback)103     public void listAppsWithAdminGrantedPermissions(String[] permissions,
104             ListOfAppsCallback callback) {
105         final CurrentUserAppWithAdminGrantedPermissionsLister lister =
106                 new CurrentUserAppWithAdminGrantedPermissionsLister(permissions, mPm, mPms, mDpm,
107                         mUm, callback);
108         lister.execute();
109     }
110 
111     @Override
findPersistentPreferredActivities(int userId, Intent[] intents)112     public List<UserAppInfo> findPersistentPreferredActivities(int userId, Intent[] intents) {
113         final List<UserAppInfo> preferredActivities = new ArrayList<>();
114         final Set<UserAppInfo> uniqueApps = new ArraySet<>();
115         final UserInfo userInfo = mUm.getUserInfo(userId);
116         for (final Intent intent : intents) {
117             try {
118                 final ResolveInfo resolveInfo =
119                         mPms.findPersistentPreferredActivity(intent, userId);
120                 if (resolveInfo != null) {
121                     ComponentInfo componentInfo = null;
122                     if (resolveInfo.activityInfo != null) {
123                         componentInfo = resolveInfo.activityInfo;
124                     } else if (resolveInfo.serviceInfo != null) {
125                         componentInfo = resolveInfo.serviceInfo;
126                     } else if (resolveInfo.providerInfo != null) {
127                         componentInfo = resolveInfo.providerInfo;
128                     }
129                     if (componentInfo != null) {
130                         UserAppInfo info = new UserAppInfo(userInfo, componentInfo.applicationInfo);
131                         if (uniqueApps.add(info)) {
132                             preferredActivities.add(info);
133                         }
134                     }
135                 }
136             } catch (RemoteException exception) {
137             }
138         }
139         return preferredActivities;
140     }
141 
142     @Override
getKeepEnabledPackages()143     public Set<String> getKeepEnabledPackages() {
144         // Find current default phone/sms app. We should keep them enabled.
145         final Set<String> keepEnabledPackages = new ArraySet<>();
146         final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mContext);
147         if (!TextUtils.isEmpty(defaultDialer)) {
148             keepEnabledPackages.add(defaultDialer);
149         }
150         final ComponentName defaultSms = SmsApplication.getDefaultSmsApplication(
151                 mContext, true /* updateIfNeeded */);
152         if (defaultSms != null) {
153             keepEnabledPackages.add(defaultSms.getPackageName());
154         }
155 
156         // Keep Euicc Service enabled.
157         final ComponentInfo euicc = findEuiccService(mPm);
158         if (euicc != null) {
159             keepEnabledPackages.add(euicc.packageName);
160         }
161 
162         keepEnabledPackages.addAll(getEnabledPackageAllowlist());
163 
164         final LocationManager locationManager =
165                 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
166         final String locationHistoryPackage = locationManager.getExtraLocationControllerPackage();
167         if (locationHistoryPackage != null) {
168             keepEnabledPackages.add(locationHistoryPackage);
169         }
170         return keepEnabledPackages;
171     }
172 
getEnabledPackageAllowlist()173     private Set<String> getEnabledPackageAllowlist() {
174         final Set<String> keepEnabledPackages = new ArraySet<>();
175 
176         // Keep Settings intelligence enabled, otherwise search feature will be disabled.
177         keepEnabledPackages.add(
178                 mContext.getString(R.string.config_settingsintelligence_package_name));
179 
180         // Keep Package Installer enabled.
181         keepEnabledPackages.add(mContext.getString(R.string.config_package_installer_package_name));
182 
183         if (mPm.getWellbeingPackageName() != null) {
184             keepEnabledPackages.add(mPm.getWellbeingPackageName());
185         }
186         return keepEnabledPackages;
187     }
188 
189     private static class CurrentUserAndManagedProfilePolicyInstalledAppCounter
190             extends InstalledAppCounter {
191         private NumberOfAppsCallback mCallback;
192 
CurrentUserAndManagedProfilePolicyInstalledAppCounter(Context context, PackageManager packageManager, NumberOfAppsCallback callback)193         CurrentUserAndManagedProfilePolicyInstalledAppCounter(Context context,
194                 PackageManager packageManager, NumberOfAppsCallback callback) {
195             super(context, PackageManager.INSTALL_REASON_POLICY, packageManager);
196             mCallback = callback;
197         }
198 
199         @Override
onCountComplete(int num)200         protected void onCountComplete(int num) {
201             mCallback.onNumberOfAppsResult(num);
202         }
203     }
204 
205     private static class CurrentUserAndManagedProfileAppWithAdminGrantedPermissionsCounter
206             extends AppWithAdminGrantedPermissionsCounter {
207         private NumberOfAppsCallback mCallback;
208 
CurrentUserAndManagedProfileAppWithAdminGrantedPermissionsCounter(Context context, String[] permissions, PackageManager packageManager, IPackageManager packageManagerService, DevicePolicyManager devicePolicyManager, NumberOfAppsCallback callback)209         CurrentUserAndManagedProfileAppWithAdminGrantedPermissionsCounter(Context context,
210                 String[] permissions, PackageManager packageManager,
211                 IPackageManager packageManagerService,
212                 DevicePolicyManager devicePolicyManager, NumberOfAppsCallback callback) {
213             super(context, permissions, packageManager, packageManagerService, devicePolicyManager);
214             mCallback = callback;
215         }
216 
217         @Override
onCountComplete(int num)218         protected void onCountComplete(int num) {
219             mCallback.onNumberOfAppsResult(num);
220         }
221     }
222 
223     private static class CurrentUserPolicyInstalledAppLister extends InstalledAppLister {
224         private ListOfAppsCallback mCallback;
225 
CurrentUserPolicyInstalledAppLister(PackageManager packageManager, UserManager userManager, ListOfAppsCallback callback)226         CurrentUserPolicyInstalledAppLister(PackageManager packageManager,
227                 UserManager userManager, ListOfAppsCallback callback) {
228             super(packageManager, userManager);
229             mCallback = callback;
230         }
231 
232         @Override
onAppListBuilt(List<UserAppInfo> list)233         protected void onAppListBuilt(List<UserAppInfo> list) {
234             mCallback.onListOfAppsResult(list);
235         }
236     }
237 
238     private static class CurrentUserAppWithAdminGrantedPermissionsLister extends
239             AppWithAdminGrantedPermissionsLister {
240         private ListOfAppsCallback mCallback;
241 
CurrentUserAppWithAdminGrantedPermissionsLister(String[] permissions, PackageManager packageManager, IPackageManager packageManagerService, DevicePolicyManager devicePolicyManager, UserManager userManager, ListOfAppsCallback callback)242         CurrentUserAppWithAdminGrantedPermissionsLister(String[] permissions,
243                 PackageManager packageManager, IPackageManager packageManagerService,
244                 DevicePolicyManager devicePolicyManager, UserManager userManager,
245                 ListOfAppsCallback callback) {
246             super(permissions, packageManager, packageManagerService, devicePolicyManager,
247                     userManager);
248             mCallback = callback;
249         }
250 
251         @Override
onAppListBuilt(List<UserAppInfo> list)252         protected void onAppListBuilt(List<UserAppInfo> list) {
253             mCallback.onListOfAppsResult(list);
254         }
255     }
256 
257     /**
258      * Return the component info of the EuiccService to bind to, or null if none were found.
259      */
260     @VisibleForTesting
findEuiccService(PackageManager packageManager)261     ComponentInfo findEuiccService(PackageManager packageManager) {
262         final Intent intent = new Intent(EuiccService.EUICC_SERVICE_INTERFACE);
263         final List<ResolveInfo> resolveInfoList =
264                 packageManager.queryIntentServices(intent, EUICC_QUERY_FLAGS);
265         final ComponentInfo bestComponent = findEuiccService(packageManager, resolveInfoList);
266         if (bestComponent == null) {
267             Log.w(TAG, "No valid EuiccService implementation found");
268         }
269         return bestComponent;
270     }
271 
findEuiccService( PackageManager packageManager, List<ResolveInfo> resolveInfoList)272     private ComponentInfo findEuiccService(
273             PackageManager packageManager, List<ResolveInfo> resolveInfoList) {
274         int bestPriority = Integer.MIN_VALUE;
275         ComponentInfo bestComponent = null;
276         if (resolveInfoList != null) {
277             for (ResolveInfo resolveInfo : resolveInfoList) {
278                 if (!isValidEuiccComponent(packageManager, resolveInfo)) {
279                     continue;
280                 }
281 
282                 if (resolveInfo.filter.getPriority() > bestPriority) {
283                     bestPriority = resolveInfo.filter.getPriority();
284                     bestComponent = getComponentInfo(resolveInfo);
285                 }
286             }
287         }
288 
289         return bestComponent;
290     }
291 
isValidEuiccComponent( PackageManager packageManager, ResolveInfo resolveInfo)292     private boolean isValidEuiccComponent(
293             PackageManager packageManager, ResolveInfo resolveInfo) {
294         final ComponentInfo componentInfo = getComponentInfo(resolveInfo);
295         final String packageName = componentInfo.packageName;
296 
297         // Verify that the app is privileged (via granting of a privileged permission).
298         if (packageManager.checkPermission(
299                 Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, packageName)
300                 != PackageManager.PERMISSION_GRANTED) {
301             Log.e(TAG, "Package " + packageName
302                     + " does not declare WRITE_EMBEDDED_SUBSCRIPTIONS");
303             return false;
304         }
305 
306         // Verify that only the system can access the component.
307         final String permission;
308         if (componentInfo instanceof ServiceInfo) {
309             permission = ((ServiceInfo) componentInfo).permission;
310         } else if (componentInfo instanceof ActivityInfo) {
311             permission = ((ActivityInfo) componentInfo).permission;
312         } else {
313             throw new IllegalArgumentException("Can only verify services/activities");
314         }
315         if (!TextUtils.equals(permission, Manifest.permission.BIND_EUICC_SERVICE)) {
316             Log.e(TAG, "Package " + packageName
317                     + " does not require the BIND_EUICC_SERVICE permission");
318             return false;
319         }
320 
321         // Verify that the component declares a priority.
322         if (resolveInfo.filter == null || resolveInfo.filter.getPriority() == 0) {
323             Log.e(TAG, "Package " + packageName + " does not specify a priority");
324             return false;
325         }
326         return true;
327     }
328 
getComponentInfo(ResolveInfo resolveInfo)329     private ComponentInfo getComponentInfo(ResolveInfo resolveInfo) {
330         if (resolveInfo.activityInfo != null) {
331             return resolveInfo.activityInfo;
332         }
333         if (resolveInfo.serviceInfo != null) {
334             return resolveInfo.serviceInfo;
335         }
336         if (resolveInfo.providerInfo != null) {
337             return resolveInfo.providerInfo;
338         }
339         throw new IllegalStateException("Missing ComponentInfo!");
340     }
341 }
342