1 /* 2 * Copyright (C) 2022 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.tests.permissions; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.assertThrows; 22 23 import android.adservices.adselection.AdSelectionConfig; 24 import android.adservices.adselection.AdSelectionConfigFixture; 25 import android.adservices.adselection.ReportImpressionRequest; 26 import android.adservices.clients.adselection.AdSelectionClient; 27 import android.adservices.clients.customaudience.AdvertisingCustomAudienceClient; 28 import android.adservices.clients.topics.AdvertisingTopicsClient; 29 import android.adservices.common.AdTechIdentifier; 30 import android.adservices.customaudience.CustomAudience; 31 import android.adservices.topics.GetTopicsResponse; 32 import android.content.Context; 33 import android.net.Uri; 34 35 import androidx.test.core.app.ApplicationProvider; 36 import androidx.test.ext.junit.runners.AndroidJUnit4; 37 38 import com.android.adservices.common.AdservicesTestHelper; 39 import com.android.adservices.common.CompatAdServicesTestUtils; 40 import com.android.adservices.service.js.JSScriptEngine; 41 import com.android.compatibility.common.util.ShellUtils; 42 import com.android.modules.utils.build.SdkLevel; 43 44 import org.junit.After; 45 import org.junit.Assume; 46 import org.junit.Before; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 50 import java.util.concurrent.ExecutionException; 51 import java.util.concurrent.Executor; 52 import java.util.concurrent.Executors; 53 54 @RunWith(AndroidJUnit4.class) 55 // TODO: Add tests for measurement (b/238194122). 56 public class PermissionsValidTest { 57 private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool(); 58 private static final Context sContext = ApplicationProvider.getApplicationContext(); 59 private static final String PERMISSION_NOT_REQUESTED = 60 "Caller is not authorized to call this API. Permission was not requested."; 61 62 private String mPreviousAppAllowList; 63 64 @Before setup()65 public void setup() { 66 // Skip the test if it runs on unsupported platforms 67 Assume.assumeTrue(AdservicesTestHelper.isDeviceSupported()); 68 69 if (!SdkLevel.isAtLeastT()) { 70 mPreviousAppAllowList = 71 CompatAdServicesTestUtils.getAndOverridePpapiAppAllowList( 72 sContext.getPackageName()); 73 CompatAdServicesTestUtils.setFlags(); 74 // TODO: Remove after EngProd figures out why setprop commands from AndroidTest 75 // .ExtServices.xml are not executing in post-submit (b/276909363) 76 setAdditionalFlags(); 77 } 78 } 79 80 @After tearDown()81 public void tearDown() throws Exception { 82 if (!AdservicesTestHelper.isDeviceSupported()) { 83 return; 84 } 85 86 if (!SdkLevel.isAtLeastT()) { 87 CompatAdServicesTestUtils.setPpapiAppAllowList(mPreviousAppAllowList); 88 CompatAdServicesTestUtils.resetFlagsToDefault(); 89 // TODO: Remove after EngProd figures out why setprop commands from AndroidTest 90 // .ExtServices.xml are not executing in post-submit (b/276909363) 91 resetAdditionalFlags(); 92 } 93 } 94 setAdditionalFlags()95 private void setAdditionalFlags() { 96 ShellUtils.runShellCommand("setprop debug.adservices.consent_manager_debug_mode true"); 97 ShellUtils.runShellCommand("setprop debug.adservices.disable_fledge_enrollment_check true"); 98 ShellUtils.runShellCommand("setprop debug.adservices.disable_topics_enrollment_check true"); 99 // TODO: Investigate why this is needed (b/276916172) 100 ShellUtils.runShellCommand("device_config put adservices ppapi_app_signature_allow_list *"); 101 } 102 resetAdditionalFlags()103 private void resetAdditionalFlags() { 104 ShellUtils.runShellCommand("setprop debug.adservices.consent_manager_debug_mode null"); 105 ShellUtils.runShellCommand("setprop debug.adservices.disable_fledge_enrollment_check null"); 106 ShellUtils.runShellCommand("setprop debug.adservices.disable_topics_enrollment_check null"); 107 ShellUtils.runShellCommand( 108 "device_config put adservices ppapi_app_signature_allow_list null"); 109 } 110 111 @Test testValidPermissions_topics()112 public void testValidPermissions_topics() throws Exception { 113 AdvertisingTopicsClient advertisingTopicsClient1 = 114 new AdvertisingTopicsClient.Builder() 115 .setContext(sContext) 116 .setSdkName("sdk1") 117 .setExecutor(CALLBACK_EXECUTOR) 118 .build(); 119 120 GetTopicsResponse sdk1Result = advertisingTopicsClient1.getTopics().get(); 121 // Not getting an error here indicates that permissions are valid. The valid case is also 122 // tested in TopicsManagerTest. 123 assertThat(sdk1Result.getTopics()).isEmpty(); 124 } 125 126 @Test testValidPermissions_fledgeJoinCustomAudience()127 public void testValidPermissions_fledgeJoinCustomAudience() 128 throws ExecutionException, InterruptedException { 129 AdvertisingCustomAudienceClient customAudienceClient = 130 new AdvertisingCustomAudienceClient.Builder() 131 .setContext(sContext) 132 .setExecutor(CALLBACK_EXECUTOR) 133 .build(); 134 135 CustomAudience customAudience = 136 new CustomAudience.Builder() 137 .setBuyer(AdTechIdentifier.fromString("test.com")) 138 .setName("exampleCustomAudience") 139 .setDailyUpdateUri(Uri.parse("https://test.com/daily-update")) 140 .setBiddingLogicUri(Uri.parse("https://test.com/bidding-logic")) 141 .build(); 142 143 customAudienceClient.joinCustomAudience(customAudience).get(); 144 } 145 146 @Test testValidPermissions_selectAds_adSelectionConfig()147 public void testValidPermissions_selectAds_adSelectionConfig() { 148 Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); 149 AdSelectionConfig adSelectionConfig = AdSelectionConfigFixture.anAdSelectionConfig(); 150 151 AdSelectionClient mAdSelectionClient = 152 new AdSelectionClient.Builder() 153 .setContext(sContext) 154 .setExecutor(CALLBACK_EXECUTOR) 155 .build(); 156 157 ExecutionException exception = 158 assertThrows( 159 ExecutionException.class, 160 () -> mAdSelectionClient.selectAds(adSelectionConfig).get()); 161 // We only need to get past the permissions check for this test to be valid 162 assertThat(exception.getMessage()).isNotEqualTo(PERMISSION_NOT_REQUESTED); 163 } 164 165 @Test testValidPermissions_reportImpression()166 public void testValidPermissions_reportImpression() { 167 Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); 168 AdSelectionConfig adSelectionConfig = AdSelectionConfigFixture.anAdSelectionConfig(); 169 170 long adSelectionId = 1; 171 172 AdSelectionClient mAdSelectionClient = 173 new AdSelectionClient.Builder() 174 .setContext(sContext) 175 .setExecutor(CALLBACK_EXECUTOR) 176 .build(); 177 178 ReportImpressionRequest request = 179 new ReportImpressionRequest(adSelectionId, adSelectionConfig); 180 181 ExecutionException exception = 182 assertThrows( 183 ExecutionException.class, 184 () -> mAdSelectionClient.reportImpression(request).get()); 185 // We only need to get past the permissions check for this test to be valid 186 assertThat(exception.getMessage()).isNotEqualTo(PERMISSION_NOT_REQUESTED); 187 } 188 // TODO(b/274723533): Uncomment after un-hiding the API 189 /* 190 @Test 191 public void testValidPermissions_reportInteraction() { 192 long adSelectionId = 1; 193 String interactionKey = "click"; 194 String interactionData = "{\"key\":\"value\"}"; 195 196 AdSelectionClient mAdSelectionClient = 197 new AdSelectionClient.Builder() 198 .setContext(sContext) 199 .setExecutor(CALLBACK_EXECUTOR) 200 .build(); 201 202 ReportInteractionRequest request = 203 new ReportInteractionRequest( 204 adSelectionId, 205 interactionKey, 206 interactionData, 207 ReportInteractionRequest.FLAG_REPORTING_DESTINATION_BUYER 208 | ReportInteractionRequest.FLAG_REPORTING_DESTINATION_SELLER); 209 210 ExecutionException exception = 211 assertThrows( 212 ExecutionException.class, 213 () -> mAdSelectionClient.reportInteraction(request).get()); 214 // We only need to get past the permissions check for this test to be valid 215 assertThat(exception.getMessage()).isNotEqualTo(PERMISSION_NOT_REQUESTED); 216 } 217 */ 218 219 // TODO(b/221876775): Unhide for frequency cap mainline promotion 220 /* 221 @Test 222 public void testValidPermissions_updateAdCounterHistogram() { 223 long adSelectionId = 1; 224 225 AdSelectionClient mAdSelectionClient = 226 new AdSelectionClient.Builder() 227 .setContext(sContext) 228 .setExecutor(CALLBACK_EXECUTOR) 229 .build(); 230 231 UpdateAdCounterHistogramRequest request = 232 new UpdateAdCounterHistogramRequest.Builder() 233 .setAdSelectionId(adSelectionId) 234 .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_IMPRESSION) 235 .setCallerAdTech(AdTechIdentifier.fromString("test.com")) 236 .build(); 237 ExecutionException exception = 238 assertThrows( 239 ExecutionException.class, 240 () -> mAdSelectionClient.updateAdCounterHistogram(request).get()); 241 242 // We only need to get past the permissions check for this test to be valid 243 assertThat(exception.getMessage()).isNotEqualTo(PERMISSION_NOT_REQUESTED); 244 } 245 */ 246 247 @Test testValidPermissions_fledgeLeaveCustomAudience()248 public void testValidPermissions_fledgeLeaveCustomAudience() 249 throws ExecutionException, InterruptedException { 250 AdvertisingCustomAudienceClient customAudienceClient = 251 new AdvertisingCustomAudienceClient.Builder() 252 .setContext(sContext) 253 .setExecutor(CALLBACK_EXECUTOR) 254 .build(); 255 256 customAudienceClient 257 .leaveCustomAudience( 258 AdTechIdentifier.fromString("test.com"), "exampleCustomAudience") 259 .get(); 260 } 261 } 262