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