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 package com.android.adservices.common; 17 18 import static com.android.adservices.common.AbstractAdServicesSystemPropertiesDumperRule.SYSTEM_PROPERTY_FOR_DEBUGGING_PREFIX; 19 import static com.android.adservices.service.FlagsConstants.KEY_ADID_KILL_SWITCH; 20 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_CUSTOM_AUDIENCE_SERVICE_KILL_SWITCH; 21 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_SCHEDULE_CUSTOM_AUDIENCE_UPDATE_ENABLED; 22 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_SELECT_ADS_KILL_SWITCH; 23 import static com.android.adservices.service.FlagsConstants.KEY_MEASUREMENT_KILL_SWITCH; 24 import static com.android.adservices.service.FlagsConstants.NAMESPACE_ADSERVICES; 25 26 import com.android.adservices.common.annotations.DisableGlobalKillSwitch; 27 import com.android.adservices.common.annotations.EnableAllApis; 28 import com.android.adservices.common.annotations.SetAllLogcatTags; 29 import com.android.adservices.common.annotations.SetCompatModeFlags; 30 import com.android.adservices.common.annotations.SetDefaultLogcatTags; 31 import com.android.adservices.common.annotations.SetMsmtApiAppAllowList; 32 import com.android.adservices.common.annotations.SetMsmtWebContextClientAppAllowList; 33 import com.android.adservices.common.annotations.SetPasAppAllowList; 34 import com.android.adservices.common.annotations.SetPpapiAppAllowList; 35 import com.android.adservices.service.FlagsConstants; 36 import com.android.adservices.shared.testing.AbstractFlagsSetterRule; 37 import com.android.adservices.shared.testing.DeviceConfigHelper; 38 import com.android.adservices.shared.testing.Logger.LogLevel; 39 import com.android.adservices.shared.testing.Logger.RealLogger; 40 import com.android.adservices.shared.testing.NameValuePair.Matcher; 41 import com.android.adservices.shared.testing.NameValuePairSetter; 42 import com.android.adservices.shared.testing.SystemPropertiesHelper; 43 44 import org.junit.runner.Description; 45 46 import java.lang.annotation.Annotation; 47 import java.util.Arrays; 48 49 // TODO(b/294423183): add unit tests for the most relevant / less repetitive stuff (don't need to 50 // test all setters / getters, for example) 51 /** 52 * Rule used to properly set AdService flags - it will take care of permissions, restoring values at 53 * the end, setting {@link android.provider.DeviceConfig} or {@link android.os.SystemProperties}, 54 * etc... 55 */ 56 //////////////////////////////////////////////////////////////////////////////////////////////////// 57 // NOTE: DO NOT add new setXyz() methods, unless they need non-trivial logic. Instead, let your // 58 // test call setFlags(flagName) (statically import FlagsConstant.flagName), which will make it // 59 // easier to transition the test to an annotated-base approach. // 60 //////////////////////////////////////////////////////////////////////////////////////////////////// 61 public abstract class AbstractAdServicesFlagsSetterRule< 62 R extends AbstractAdServicesFlagsSetterRule<R>> 63 extends AbstractFlagsSetterRule<R> { 64 65 // TODO(b/295321663): move these constants (and those from LogFactory) to AdServicesCommon 66 protected static final String LOGCAT_TAG_ADSERVICES = "adservices"; 67 protected static final String LOGCAT_TAG_ADSERVICES_SERVICE = LOGCAT_TAG_ADSERVICES + "-system"; 68 protected static final String LOGCAT_TAG_TOPICS = LOGCAT_TAG_ADSERVICES + ".topics"; 69 protected static final String LOGCAT_TAG_FLEDGE = LOGCAT_TAG_ADSERVICES + ".fledge"; 70 protected static final String LOGCAT_TAG_KANON = LOGCAT_TAG_ADSERVICES + ".kanon"; 71 protected static final String LOGCAT_TAG_MEASUREMENT = LOGCAT_TAG_ADSERVICES + ".measurement"; 72 protected static final String LOGCAT_TAG_UI = LOGCAT_TAG_ADSERVICES + ".ui"; 73 protected static final String LOGCAT_TAG_ADID = LOGCAT_TAG_ADSERVICES + ".adid"; 74 protected static final String LOGCAT_TAG_APPSETID = LOGCAT_TAG_ADSERVICES + ".appsetid"; 75 protected static final String LOGCAT_TAG_SHARED = "adservices-shared"; 76 77 // TODO(b/294423183): instead of hardcoding the SYSTEM_PROPERTY_FOR_LOGCAT_TAGS_PREFIX, we 78 // should dynamically calculate it based on setLogcatTag() calls 79 private static final Matcher PROPERTIES_PREFIX_MATCHER = 80 (prop) -> 81 prop.name.startsWith(SYSTEM_PROPERTY_FOR_DEBUGGING_PREFIX) 82 || prop.name.startsWith( 83 SYSTEM_PROPERTY_FOR_LOGCAT_TAGS_PREFIX + "adservices"); 84 85 private static final boolean USE_TEST_PACKAGE_AS_DEFAULT = true; 86 private static final boolean DONT_USE_TEST_PACKAGE_AS_DEFAULT = false; 87 AbstractAdServicesFlagsSetterRule( RealLogger logger, DeviceConfigHelper.InterfaceFactory deviceConfigInterfaceFactory, SystemPropertiesHelper.Interface systemPropertiesInterface)88 protected AbstractAdServicesFlagsSetterRule( 89 RealLogger logger, 90 DeviceConfigHelper.InterfaceFactory deviceConfigInterfaceFactory, 91 SystemPropertiesHelper.Interface systemPropertiesInterface) { 92 super( 93 logger, 94 NAMESPACE_ADSERVICES, 95 SYSTEM_PROPERTY_FOR_DEBUGGING_PREFIX, 96 PROPERTIES_PREFIX_MATCHER, 97 deviceConfigInterfaceFactory, 98 systemPropertiesInterface); 99 } 100 101 // Used for testing purposes only AbstractAdServicesFlagsSetterRule( RealLogger logger, NameValuePairSetter flagsSetter)102 protected AbstractAdServicesFlagsSetterRule( 103 RealLogger logger, NameValuePairSetter flagsSetter) { 104 super(logger, flagsSetter); 105 } 106 107 @Override isAnnotationSupported(Annotation annotation)108 protected boolean isAnnotationSupported(Annotation annotation) { 109 // NOTE: add annotations sorted by "most likely usage" 110 return annotation instanceof DisableGlobalKillSwitch 111 || annotation instanceof EnableAllApis 112 || annotation instanceof SetCompatModeFlags 113 || annotation instanceof SetPpapiAppAllowList 114 || annotation instanceof SetDefaultLogcatTags 115 || annotation instanceof SetAllLogcatTags 116 || annotation instanceof SetMsmtApiAppAllowList 117 || annotation instanceof SetMsmtWebContextClientAppAllowList 118 || annotation instanceof SetPasAppAllowList; 119 } 120 121 @Override processAnnotation(Description description, Annotation annotation)122 protected void processAnnotation(Description description, Annotation annotation) { 123 // NOTE: add annotations sorted by "most likely usage" 124 if (annotation instanceof DisableGlobalKillSwitch) { 125 setGlobalKillSwitch(false); 126 } else if (annotation instanceof EnableAllApis) { 127 enableAllApis(); 128 } else if (annotation instanceof SetCompatModeFlags) { 129 setCompatModeFlags(); 130 } else if (annotation instanceof SetPpapiAppAllowList) { 131 setPpapiAppAllowList( 132 ((SetPpapiAppAllowList) annotation).value(), USE_TEST_PACKAGE_AS_DEFAULT); 133 } else if (annotation instanceof SetDefaultLogcatTags) { 134 setDefaultLogcatTags(); 135 } else if (annotation instanceof SetAllLogcatTags) { 136 setAllLogcatTags(); 137 } else if (annotation instanceof SetMsmtApiAppAllowList) { 138 setMsmtApiAppAllowList( 139 ((SetMsmtApiAppAllowList) annotation).value(), USE_TEST_PACKAGE_AS_DEFAULT); 140 } else if (annotation instanceof SetMsmtWebContextClientAppAllowList) { 141 setMsmtWebContextClientAllowList( 142 ((SetMsmtWebContextClientAppAllowList) annotation).value(), 143 USE_TEST_PACKAGE_AS_DEFAULT); 144 } else if (annotation instanceof SetPasAppAllowList) { 145 setPasAppAllowList(((SetPasAppAllowList) annotation).value()); 146 } else { 147 // should not happen 148 throw new IllegalStateException( 149 "INTERNAL ERROR: processAnnotation() called with unsupported annotation: " 150 + annotation); 151 } 152 } 153 154 /** 155 * Gets the package name of the app running this test. 156 * 157 * <p>Used on annotations that applies to the test app by default (for example, for allowlist). 158 */ getTestPackageName()159 protected String getTestPackageName() { 160 // 161 throw new UnsupportedOperationException( 162 "Concrete rule (" 163 + getClass().getSimpleName() 164 + ") cannot infer the name of the test package (typically happens on" 165 + " host-side tests)"); 166 } 167 168 // Helper methods to set more commonly used flags such as kill switches. 169 // Less common flags can be set directly using setFlags methods. 170 171 /** 172 * Overrides the flag that sets the global AdServices kill switch. 173 * 174 * <p>NOTE: it's usually cleaner to use an annotation instead ({@link DisableGlobalKillSwitch} 175 * in this case), unless the test need to dynamically change the flags after it started. 176 */ setGlobalKillSwitch(boolean value)177 public final R setGlobalKillSwitch(boolean value) { 178 return setFlag(FlagsConstants.KEY_GLOBAL_KILL_SWITCH, value); 179 } 180 enableAllApis()181 final R enableAllApis() { 182 return setAllLogcatTags() 183 .setGlobalKillSwitch(false) 184 .setTopicsKillSwitch(false) 185 .setFlag(KEY_ADID_KILL_SWITCH, false) 186 .setFlag(KEY_MEASUREMENT_KILL_SWITCH, false) 187 .setFlag(KEY_FLEDGE_CUSTOM_AUDIENCE_SERVICE_KILL_SWITCH, false) 188 .setFlag(KEY_FLEDGE_SELECT_ADS_KILL_SWITCH, false) 189 .setFlag(KEY_FLEDGE_SCHEDULE_CUSTOM_AUDIENCE_UPDATE_ENABLED, true); 190 } 191 192 /** 193 * Overrides flag used by {@link com.android.adservices.service.PhFlags#getAdServicesEnabled}. 194 */ setAdServicesEnabled(boolean value)195 public final R setAdServicesEnabled(boolean value) { 196 return setFlag(FlagsConstants.KEY_ADSERVICES_ENABLED, value); 197 } 198 199 /** Overrides the flag that sets the Topics kill switch. */ setTopicsKillSwitch(boolean value)200 public final R setTopicsKillSwitch(boolean value) { 201 return setFlag(FlagsConstants.KEY_TOPICS_KILL_SWITCH, value); 202 } 203 204 /** Overrides the flag that sets the Topics Device Classifier kill switch. */ setTopicsOnDeviceClassifierKillSwitch(boolean value)205 public final R setTopicsOnDeviceClassifierKillSwitch(boolean value) { 206 return setFlag(FlagsConstants.KEY_TOPICS_ON_DEVICE_CLASSIFIER_KILL_SWITCH, value); 207 } 208 209 /** 210 * Overrides flag used by {@link com.android.adservices.service.PhFlags#getEnableBackCompat()}. 211 */ setEnableBackCompat(boolean value)212 public final R setEnableBackCompat(boolean value) { 213 return setFlag(FlagsConstants.KEY_ENABLE_BACK_COMPAT, value); 214 } 215 216 /** 217 * Overrides flag used by {@link 218 * com.android.adservices.service.PhFlags#getMeasurementRollbackDeletionAppSearchKillSwitch()}. 219 */ setMeasurementRollbackDeletionAppSearchKillSwitch(boolean value)220 public final R setMeasurementRollbackDeletionAppSearchKillSwitch(boolean value) { 221 return setFlag( 222 FlagsConstants.KEY_MEASUREMENT_ROLLBACK_DELETION_APP_SEARCH_KILL_SWITCH, value); 223 } 224 225 /** 226 * Overrides flag used by {@link com.android.adservices.service.PhFlags#getPpapiAppAllowList()}. 227 * 228 * <p>NOTE: it's usually cleaner to use an annotation instead ({@link SetPpapiAppAllowList} in 229 * this case), unless the test need to dynamically change the flags after it started. 230 */ setPpapiAppAllowList(String... value)231 public final R setPpapiAppAllowList(String... value) { 232 return setPpapiAppAllowList(value, DONT_USE_TEST_PACKAGE_AS_DEFAULT); 233 } 234 setPpapiAppAllowList(String[] value, boolean useTestPackageAsDefault)235 private R setPpapiAppAllowList(String[] value, boolean useTestPackageAsDefault) { 236 mLog.d( 237 "setPpapiAppAllowList(useTestPackageAsDefault=%b): %s", 238 useTestPackageAsDefault, Arrays.toString(value)); 239 return setAllowListFlag( 240 FlagsConstants.KEY_PPAPI_APP_ALLOW_LIST, value, useTestPackageAsDefault); 241 } 242 243 /** 244 * Overrides flag used by {@link 245 * com.android.adservices.service.PhFlags#getMsmtApiAppAllowList()}. 246 * 247 * <p>NOTE: it's usually cleaner to use an annotation instead ({@link SetMsmtApiAppAllowList} in 248 * this case), unless the test need to dynamically change the flags after it started. 249 */ setMsmtApiAppAllowList(String... value)250 public final R setMsmtApiAppAllowList(String... value) { 251 return setMsmtApiAppAllowList(value, DONT_USE_TEST_PACKAGE_AS_DEFAULT); 252 } 253 setMsmtApiAppAllowList(String[] value, boolean useTestPackageAsDefault)254 private R setMsmtApiAppAllowList(String[] value, boolean useTestPackageAsDefault) { 255 mLog.d( 256 "setMsmtApiAppAllowList(useTestPackageAsDefault=%b): %s", 257 useTestPackageAsDefault, Arrays.toString(value)); 258 return setAllowListFlag( 259 FlagsConstants.KEY_MSMT_API_APP_ALLOW_LIST, value, useTestPackageAsDefault); 260 } 261 262 /** 263 * Overrides flag used by {@link 264 * com.android.adservices.service.PhFlags#getWebContextClientAppAllowList()}. 265 * 266 * <p>NOTE: it's usually cleaner to use an annotation instead ({@link 267 * SetMsmtWebContextClientAppAllowList} in this case), unless the test need to dynamically 268 * change the flags after it started. 269 */ setMsmtWebContextClientAllowList(String... value)270 public final R setMsmtWebContextClientAllowList(String... value) { 271 return setMsmtWebContextClientAllowList(value, DONT_USE_TEST_PACKAGE_AS_DEFAULT); 272 } 273 setMsmtWebContextClientAllowList(String[] value, boolean useTestPackageAsDefault)274 private R setMsmtWebContextClientAllowList(String[] value, boolean useTestPackageAsDefault) { 275 mLog.d( 276 "setMsmtWebContextClientAllowList(useTestPackageAsDefault=%b): %s", 277 useTestPackageAsDefault, Arrays.toString(value)); 278 return setAllowListFlag( 279 FlagsConstants.KEY_WEB_CONTEXT_CLIENT_ALLOW_LIST, value, useTestPackageAsDefault); 280 } 281 282 /** 283 * Overrides flag used by {@link 284 * com.android.adservices.service.PhFlags#getMddBackgroundTaskKillSwitch()}. 285 */ setMddBackgroundTaskKillSwitch(boolean value)286 public final R setMddBackgroundTaskKillSwitch(boolean value) { 287 return setFlag(FlagsConstants.KEY_MDD_BACKGROUND_TASK_KILL_SWITCH, value); 288 } 289 290 /** 291 * Overrides flag used by {@link com.android.adservices.service.PhFlags#getPasAppAllowList()}. 292 */ setPasAppAllowList(String... value)293 public final R setPasAppAllowList(String... value) { 294 mLog.d("setPasAppAllowList(%s)", Arrays.toString(value)); 295 return setAllowListFlag( 296 FlagsConstants.KEY_PAS_APP_ALLOW_LIST, value, USE_TEST_PACKAGE_AS_DEFAULT); 297 } 298 299 //////////////////////////////////////////////////////////////////////////////////////////////// 300 // NOTE: DO NOT add new setXyz() methods, unless they need non-trivial logic. Instead, let // 301 // your test call setFlags(flagName) (statically import FlagsConstant.flagName), which will // 302 // make it easier to transition the test to an annotated-base approach. // 303 //////////////////////////////////////////////////////////////////////////////////////////////// 304 305 /** 306 * Sets all flags needed to enable compatibility mode, according to the Android version of the 307 * device running the test. 308 * 309 * <p>NOTE: it's usually cleaner to use an annotation instead ({@link SetCompatModeFlags} in 310 * this case), unless the test need to dynamically change the flags after it started. 311 */ setCompatModeFlags()312 public R setCompatModeFlags() { 313 return runOrCache( 314 "setCompatModeFlags()", 315 () -> { 316 if (isAtLeastT()) { 317 mLog.d("setCompatModeFlags(): ignored on SDK %d", getDeviceSdk()); 318 // Do nothing; this method is intended to set flags for Android S- only. 319 return; 320 } 321 322 if (isAtLeastS()) { 323 mLog.d("setCompatModeFlags(): setting flags for S+"); 324 setFlag(FlagsConstants.KEY_ENABLE_BACK_COMPAT, true); 325 setFlag( 326 FlagsConstants.KEY_BLOCKED_TOPICS_SOURCE_OF_TRUTH, 327 FlagsConstants.APPSEARCH_ONLY); 328 setFlag( 329 FlagsConstants.KEY_CONSENT_SOURCE_OF_TRUTH, 330 FlagsConstants.APPSEARCH_ONLY); 331 setFlag(FlagsConstants.KEY_ENABLE_APPSEARCH_CONSENT_DATA, true); 332 setFlag( 333 FlagsConstants 334 .KEY_MEASUREMENT_ROLLBACK_DELETION_APP_SEARCH_KILL_SWITCH, 335 false); 336 return; 337 } 338 mLog.d("setCompatModeFlags(): setting flags for R+"); 339 setFlag(FlagsConstants.KEY_ENABLE_BACK_COMPAT, true); 340 setFlag(FlagsConstants.KEY_ENABLE_ADEXT_DATA_SERVICE_DEBUG_PROXY, true); 341 }); 342 } 343 344 //////////////////////////////////////////////////////////////////////////////////////////////// 345 // NOTE: DO NOT add new setXyz() methods, unless they need non-trivial logic. Instead, let // 346 // your test call setFlags(flagName) (statically import FlagsConstant.flagName), which will // 347 // make it easier to transition the test to an annotated-base approach. // 348 //////////////////////////////////////////////////////////////////////////////////////////////// 349 350 /** 351 * Sets the common AdServices {@code logcat} tags. 352 * 353 * <p>This method is usually set automatically by the factory methods, but should be set again 354 * (on host-side tests) after reboot. 355 * 356 * <p>NOTE: it's usually cleaner to use an annotation instead ({@link SetDefaultLogcatTags} in 357 * this case), unless the test need to dynamically change the flags after it started. 358 */ 359 public R setDefaultLogcatTags() { 360 setInfraLogcatTags(); 361 setLogcatTag(LOGCAT_TAG_ADSERVICES, LogLevel.VERBOSE); 362 setLogcatTag(LOGCAT_TAG_SHARED, LogLevel.VERBOSE); 363 setLogcatTag(LOGCAT_TAG_ADSERVICES_SERVICE, LogLevel.VERBOSE); 364 return getThis(); 365 } 366 367 /** 368 * Sets all AdServices {@code logcat} tags. 369 * 370 * <p>This method is usually set automatically by the factory methods, but should be set again 371 * (on host-side tests) after reboot. 372 * 373 * <p>NOTE: it's usually cleaner to use an annotation instead ({@link SetAllLogcatTags} in this 374 * case), unless the test need to dynamically change the flags after it started. 375 */ 376 public R setAllLogcatTags() { 377 setDefaultLogcatTags(); 378 setLogcatTag(LOGCAT_TAG_TOPICS, LogLevel.VERBOSE); 379 setLogcatTag(LOGCAT_TAG_FLEDGE, LogLevel.VERBOSE); 380 setLogcatTag(LOGCAT_TAG_MEASUREMENT, LogLevel.VERBOSE); 381 setLogcatTag(LOGCAT_TAG_ADID, LogLevel.VERBOSE); 382 setLogcatTag(LOGCAT_TAG_APPSETID, LogLevel.VERBOSE); 383 setLogcatTag(LOGCAT_TAG_UI, LogLevel.VERBOSE); 384 setLogcatTag(LOGCAT_TAG_KANON, LogLevel.VERBOSE); 385 return getThis(); 386 } 387 388 /** 389 * Sets Measurement {@code logcat} tags. 390 * 391 * <p>This method is usually set automatically by the factory methods, but should be set again 392 * (on host-side tests) after reboot. 393 */ 394 public R setMeasurementTags() { 395 setLogcatTag(LOGCAT_TAG_MEASUREMENT, LogLevel.VERBOSE); 396 return getThis(); 397 } 398 399 //////////////////////////////////////////////////////////////////////////////////////////////// 400 // NOTE: DO NOT add new setXyz() methods, unless they need non-trivial logic. Instead, let // 401 // your test call setFlags(flagName) (statically import FlagsConstant.flagName), which will // 402 // make it easier to transition the test to an annotated-base approach. // 403 //////////////////////////////////////////////////////////////////////////////////////////////// 404 405 private R setAllowListFlag(String name, String[] values, boolean useTestPackageAsDefault) { 406 if (values.length == 0 && useTestPackageAsDefault) { 407 String testPkg = getTestPackageName(); 408 mLog.d( 409 "setAllowListUsingTestAppAsDefault(%s): package not set by annotation, using" 410 + " test package name %s", 411 name, testPkg); 412 values = new String[] {testPkg}; 413 } 414 return setArrayFlag(name, values); 415 } 416 } 417