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