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