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