1 /* 2 * Copyright (C) 2023 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.adservices.service.common.compat; 18 19 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PACKAGE_NAME_NOT_FOUND_EXCEPTION; 20 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__COMMON; 21 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.PackageInfo; 26 import android.content.pm.PackageManager; 27 import android.os.Build; 28 import android.util.Pair; 29 30 import androidx.annotation.NonNull; 31 32 import com.android.adservices.AdServicesCommon; 33 import com.android.adservices.LogUtil; 34 import com.android.adservices.errorlogging.ErrorLogUtil; 35 import com.android.modules.utils.build.SdkLevel; 36 37 import com.google.common.collect.ImmutableList; 38 39 import java.util.List; 40 import java.util.Objects; 41 42 /** Utility class for compatibility of PackageManager APIs with Android S and earlier. */ 43 public final class PackageManagerCompatUtils { 44 PackageManagerCompatUtils()45 private PackageManagerCompatUtils() { 46 // Prevent instantiation 47 } 48 49 // This list is the same as the list declared in the AdExtServicesManifest, where the 50 // activities need need to be enabled/disabled based on flag settings and SDK version. 51 // TODO(b/263904312): Remove after max_sdk_version is implemented. 52 // TODO(b/272737642) scan activities instead of hardcode 53 // LINT.IfChange(activities_and_services) 54 public static final ImmutableList<String> CONSENT_ACTIVITIES_CLASSES = 55 ImmutableList.of( 56 "com.android.adservices.ui.settings.activities." 57 + "AdServicesSettingsMainActivity", 58 "com.android.adservices.ui.settings.activities.TopicsActivity", 59 "com.android.adservices.ui.settings.activities.BlockedTopicsActivity", 60 "com.android.adservices.ui.settings.activities.AppsActivity", 61 "com.android.adservices.ui.settings.activities.BlockedAppsActivity", 62 "com.android.adservices.ui.settings.activities.MeasurementActivity", 63 "com.android.adservices.ui.notifications.ConsentNotificationActivity"); 64 65 // This list is the same as the list declared in the AdExtServicesManifest, where the 66 // services with intent filters need to be enabled/disabled based on flag settings and SDK 67 // version. The list is a collection of pairs where the first value is the name of the service, 68 // and the second value is the min SDK version for which the service is supported. 69 // TODO(b/263904312): Remove after max_sdk_version is implemented. 70 // TODO(b/272737642) scan services instead of hardcode 71 public static final ImmutableList<Pair<String, Integer>> 72 SERVICE_CLASSES_AND_MIN_SDK_SUPPORT_PAIRS = 73 ImmutableList.of( 74 new Pair<>( 75 /* service= */ "com.android.adservices.adid.AdIdService", 76 /* minSdkSupport= */ Build.VERSION_CODES.R), 77 new Pair<>( 78 /* service= */ "com.android.adservices.measurement.MeasurementService", 79 /* minSdkSupport= */ Build.VERSION_CODES.R), 80 new Pair<>( 81 /* service= */ "com.android.adservices.common.AdServicesCommonService", 82 /* minSdkSupport= */ Build.VERSION_CODES.R), 83 new Pair<>( 84 /* service= */ "com.android.adservices.adselection.AdSelectionService", 85 /* minSdkSupport= */ Build.VERSION_CODES.S), 86 new Pair<>( 87 /* service= */ "com.android.adservices.customaudience.CustomAudienceService", 88 /* minSdkSupport= */ Build.VERSION_CODES.S), 89 new Pair<>( 90 /* service= */ "android.adservices.signals.ProtectedSignalsService", 91 /* minSdkSupport= */ Build.VERSION_CODES.S), 92 new Pair<>( 93 /* service= */ "com.android.adservices.topics.TopicsService", 94 /* minSdkSupport= */ Build.VERSION_CODES.S), 95 new Pair<>( 96 /* service= */ "com.android.adservices.appsetid.AppSetIdService", 97 /* minSdkSupport= */ Build.VERSION_CODES.S)); 98 99 // LINT.ThenChange() 100 101 /** 102 * Invokes the appropriate overload of {@code getInstalledPackages} on {@link PackageManager} 103 * depending on the SDK version. 104 * 105 * <p>{@code PackageInfoFlags.of()} actually takes a {@code long} as input whereas the earlier 106 * overload takes an {@code int}. For backward-compatibility, we're limited to the {@code int} 107 * range, so using {@code int} as a parameter to this method. 108 * 109 * @param packageManager the package manager instance to query 110 * @param flags the flags to be used for querying package manager 111 * @return the list of installed packages returned from the query to {@link PackageManager} 112 */ 113 @NonNull getInstalledPackages( @onNull PackageManager packageManager, int flags)114 public static List<PackageInfo> getInstalledPackages( 115 @NonNull PackageManager packageManager, int flags) { 116 Objects.requireNonNull(packageManager); 117 return SdkLevel.isAtLeastT() 118 ? packageManager.getInstalledPackages(PackageManager.PackageInfoFlags.of(flags)) 119 : packageManager.getInstalledPackages(flags); 120 } 121 122 /** 123 * Invokes the appropriate overload of {@code getInstalledApplications} on {@link 124 * PackageManager} depending on the SDK version. 125 * 126 * <p>{@code ApplicationInfoFlags.of()} actually takes a {@code long} as input whereas the 127 * earlier overload takes an {@code int}. For backward-compatibility, we're limited to the 128 * {@code int} range, so using {@code int} as a parameter to this method. 129 * 130 * @param packageManager the package manager instance to query 131 * @param flags the flags to be used for querying package manager 132 * @return the list of installed applications returned from the query to {@link PackageManager} 133 */ 134 @NonNull getInstalledApplications( @onNull PackageManager packageManager, int flags)135 public static List<ApplicationInfo> getInstalledApplications( 136 @NonNull PackageManager packageManager, int flags) { 137 Objects.requireNonNull(packageManager); 138 return SdkLevel.isAtLeastT() 139 ? packageManager.getInstalledApplications( 140 PackageManager.ApplicationInfoFlags.of(flags)) 141 : packageManager.getInstalledApplications(flags); 142 } 143 144 /** 145 * Invokes the appropriate overload of {@code getApplicationInfo} on {@link PackageManager} 146 * depending on the SDK version. 147 * 148 * <p>{@code ApplicationInfoFlags.of()} actually takes a {@code long} as input whereas the 149 * earlier overload takes an {@code int}. For backward-compatibility, we're limited to the 150 * {@code int} range, so using {@code int} as a parameter to this method. 151 * 152 * @param packageManager the package manager instance to query 153 * @param flags the flags to be used for querying package manager 154 * @param packageName the name of the package for which the ApplicationInfo should be retrieved 155 * @return the application info returned from the query to {@link PackageManager} 156 */ 157 @NonNull getApplicationInfo( @onNull PackageManager packageManager, @NonNull String packageName, int flags)158 public static ApplicationInfo getApplicationInfo( 159 @NonNull PackageManager packageManager, @NonNull String packageName, int flags) 160 throws PackageManager.NameNotFoundException { 161 Objects.requireNonNull(packageManager); 162 Objects.requireNonNull(packageName); 163 return SdkLevel.isAtLeastT() 164 ? packageManager.getApplicationInfo( 165 packageName, PackageManager.ApplicationInfoFlags.of(flags)) 166 : packageManager.getApplicationInfo(packageName, flags); 167 } 168 169 /** 170 * Invokes the appropriate overload of {@code getPackageUid} on {@link PackageManager} depending 171 * on the SDK version. 172 * 173 * <p>{@code PackageInfoFlags.of()} actually takes a {@code long} as input whereas the earlier 174 * overload takes an {@code int}. For backward-compatibility, we're limited to the {@code int} 175 * range, so using {@code int} as a parameter to this method. 176 * 177 * @param packageManager the packageManager instance to query 178 * @param packageName the name of the package for which the uid needs to be returned 179 * @param flags the flags to be used for querying the packageManager 180 * @return the uid of the package with the specified name 181 * @throws PackageManager.NameNotFoundException if the package was not found 182 */ getPackageUid( @onNull PackageManager packageManager, @NonNull String packageName, int flags)183 public static int getPackageUid( 184 @NonNull PackageManager packageManager, @NonNull String packageName, int flags) 185 throws PackageManager.NameNotFoundException { 186 Objects.requireNonNull(packageManager); 187 Objects.requireNonNull(packageName); 188 return SdkLevel.isAtLeastT() 189 ? packageManager.getPackageUid( 190 packageName, PackageManager.PackageInfoFlags.of(flags)) 191 : packageManager.getPackageUid(packageName, flags); 192 } 193 194 /** 195 * Check whether the activities for user consent and control are enabled 196 * 197 * @param context the context 198 * @return true if AdServices activities are enabled, otherwise false 199 */ 200 @NonNull isAdServicesActivityEnabled(@onNull Context context)201 public static boolean isAdServicesActivityEnabled(@NonNull Context context) { 202 Objects.requireNonNull(context); 203 String packageName = context.getPackageName(); 204 if (packageName == null) { 205 return false; 206 } 207 208 // Activities are enabled by default in AdServices package 209 if (packageName.endsWith(AdServicesCommon.ADSERVICES_APK_PACKAGE_NAME_SUFFIX)) { 210 return true; 211 } 212 PackageManager packageManager = context.getPackageManager(); 213 try { 214 PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0); 215 for (String activity : CONSENT_ACTIVITIES_CLASSES) { 216 int componentEnabledState = 217 packageManager.getComponentEnabledSetting( 218 new ComponentName(packageInfo.packageName, activity)); 219 // Activities are disabled by default in ExtServices package 220 if (componentEnabledState != PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 221 return false; 222 } 223 } 224 } catch (PackageManager.NameNotFoundException e) { 225 LogUtil.e("Error when checking if activities are enabled: " + e.getMessage()); 226 ErrorLogUtil.e( 227 e, 228 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PACKAGE_NAME_NOT_FOUND_EXCEPTION, 229 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__COMMON); 230 return false; 231 } 232 return true; 233 } 234 } 235