• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.common.CommonFixture;
31 import android.adservices.customaudience.CustomAudience;
32 import android.content.Context;
33 import android.net.Uri;
34 import android.util.Log;
35 
36 import androidx.test.core.app.ApplicationProvider;
37 import androidx.test.ext.junit.runners.AndroidJUnit4;
38 
39 import com.android.adservices.common.AdservicesTestHelper;
40 import com.android.adservices.common.CompatAdServicesTestUtils;
41 import com.android.adservices.service.PhFlagsFixture;
42 import com.android.adservices.service.js.JSScriptEngine;
43 import com.android.compatibility.common.util.ShellUtils;
44 import com.android.modules.utils.build.SdkLevel;
45 
46 import org.junit.After;
47 import org.junit.Assume;
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 
52 import java.util.concurrent.ExecutionException;
53 import java.util.concurrent.Executor;
54 import java.util.concurrent.Executors;
55 
56 /** In the ad_services_config.xml file, API access is revoked for all but a few, for this test. */
57 @RunWith(AndroidJUnit4.class)
58 // TODO: Add tests for measurement (b/238194122).
59 public class PermissionsAppOptOutTest {
60     private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
61     private static final Context sContext = ApplicationProvider.getApplicationContext();
62     private static final String CALLER_NOT_AUTHORIZED =
63             "java.lang.SecurityException: Caller is not authorized to call this API. "
64                     + "Caller is not allowed.";
65 
66     private String mPreviousAppAllowList;
67 
68     @Before
setup()69     public void setup() {
70         // Skip the test if it runs on unsupported platforms
71         Assume.assumeTrue(AdservicesTestHelper.isDeviceSupported());
72 
73         if (!SdkLevel.isAtLeastT()) {
74             overridePpapiAppAllowList();
75             CompatAdServicesTestUtils.setFlags();
76         }
77 
78         // TODO: Remove once b/277790129 has been resolved
79         final String flags = ShellUtils.runShellCommand("device_config list adservices");
80         Log.d("Adservices", flags);
81     }
82 
83     @After
tearDown()84     public void tearDown() throws Exception {
85         if (!AdservicesTestHelper.isDeviceSupported()) {
86             return;
87         }
88 
89         if (!SdkLevel.isAtLeastT()) {
90             setPpapiAppAllowList(mPreviousAppAllowList);
91             CompatAdServicesTestUtils.resetFlagsToDefault();
92         }
93         // TODO(b/266725238): Remove/modify once the API rate limit has been adjusted for FLEDGE
94         CommonFixture.doSleep(PhFlagsFixture.DEFAULT_API_RATE_LIMIT_SLEEP_MS);
95     }
96 
setPpapiAppAllowList(String allowList)97     private void setPpapiAppAllowList(String allowList) {
98         ShellUtils.runShellCommand(
99                 "device_config put adservices ppapi_app_allow_list " + allowList);
100     }
101 
overridePpapiAppAllowList()102     private void overridePpapiAppAllowList() {
103         mPreviousAppAllowList =
104                 ShellUtils.runShellCommand("device_config get adservices ppapi_app_allow_list");
105         setPpapiAppAllowList(mPreviousAppAllowList + "," + sContext.getPackageName());
106     }
107 
108     @Test
testAppOptOut_topics()109     public void testAppOptOut_topics() {
110         AdvertisingTopicsClient advertisingTopicsClient1 =
111                 new AdvertisingTopicsClient.Builder()
112                         .setContext(sContext)
113                         .setSdkName("sdk1")
114                         .setExecutor(CALLBACK_EXECUTOR)
115                         .build();
116 
117         ExecutionException exception =
118                 assertThrows(
119                         ExecutionException.class, () -> advertisingTopicsClient1.getTopics().get());
120         assertThat(exception.getMessage()).isEqualTo(CALLER_NOT_AUTHORIZED);
121     }
122 
123     @Test
testNoEnrollment_fledgeJoinCustomAudience()124     public void testNoEnrollment_fledgeJoinCustomAudience() {
125         AdvertisingCustomAudienceClient customAudienceClient =
126                 new AdvertisingCustomAudienceClient.Builder()
127                         .setContext(sContext)
128                         .setExecutor(CALLBACK_EXECUTOR)
129                         .build();
130 
131         CustomAudience customAudience =
132                 new CustomAudience.Builder()
133                         .setBuyer(AdTechIdentifier.fromString("buyer.example.com"))
134                         .setName("exampleCustomAudience")
135                         .setDailyUpdateUri(Uri.parse("https://buyer.example.com/daily-update"))
136                         .setBiddingLogicUri(Uri.parse("https://buyer.example.com/bidding-logic"))
137                         .build();
138 
139         ExecutionException exception =
140                 assertThrows(
141                         ExecutionException.class,
142                         () -> customAudienceClient.joinCustomAudience(customAudience).get());
143         assertThat(exception.getMessage()).isEqualTo(CALLER_NOT_AUTHORIZED);
144     }
145 
146     @Test
testWithEnrollment_fledgeJoinCustomAudience()147     public void testWithEnrollment_fledgeJoinCustomAudience()
148             throws ExecutionException, InterruptedException {
149         AdvertisingCustomAudienceClient customAudienceClient =
150                 new AdvertisingCustomAudienceClient.Builder()
151                         .setContext(sContext)
152                         .setExecutor(CALLBACK_EXECUTOR)
153                         .build();
154 
155         // The "test.com" buyer is a pre-seeded enrolled ad tech
156         CustomAudience customAudience =
157                 new CustomAudience.Builder()
158                         .setBuyer(AdTechIdentifier.fromString("test.com"))
159                         .setName("exampleCustomAudience")
160                         .setDailyUpdateUri(Uri.parse("https://test.com/daily-update"))
161                         .setBiddingLogicUri(Uri.parse("https://test.com/bidding-logic"))
162                         .build();
163 
164         // When the ad tech is properly enrolled, just verify that no error is thrown
165         customAudienceClient.joinCustomAudience(customAudience).get();
166     }
167 
168     @Test
testNoEnrollment_fledgeLeaveCustomAudience()169     public void testNoEnrollment_fledgeLeaveCustomAudience() {
170         AdvertisingCustomAudienceClient customAudienceClient =
171                 new AdvertisingCustomAudienceClient.Builder()
172                         .setContext(sContext)
173                         .setExecutor(CALLBACK_EXECUTOR)
174                         .build();
175 
176         ExecutionException exception =
177                 assertThrows(
178                         ExecutionException.class,
179                         () ->
180                                 customAudienceClient
181                                         .leaveCustomAudience(
182                                                 AdTechIdentifier.fromString("buyer.example.com"),
183                                                 "exampleCustomAudience")
184                                         .get());
185         assertThat(exception.getMessage()).isEqualTo(CALLER_NOT_AUTHORIZED);
186     }
187 
188     @Test
testWithEnrollment_fledgeLeaveCustomAudience()189     public void testWithEnrollment_fledgeLeaveCustomAudience()
190             throws ExecutionException, InterruptedException {
191         AdvertisingCustomAudienceClient customAudienceClient =
192                 new AdvertisingCustomAudienceClient.Builder()
193                         .setContext(sContext)
194                         .setExecutor(CALLBACK_EXECUTOR)
195                         .build();
196 
197         // The "test.com" buyer is a pre-seeded enrolled ad tech
198         // When the ad tech is properly enrolled, just verify that no error is thrown
199         customAudienceClient
200                 .leaveCustomAudience(
201                         AdTechIdentifier.fromString("test.com"), "exampleCustomAudience")
202                 .get();
203     }
204 
205     @Test
testNoEnrollment_selectAds_adSelectionConfig()206     public void testNoEnrollment_selectAds_adSelectionConfig() {
207         Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable());
208         AdSelectionConfig adSelectionConfig =
209                 AdSelectionConfigFixture.anAdSelectionConfig(
210                         AdTechIdentifier.fromString("seller.example.com"));
211 
212         AdSelectionClient mAdSelectionClient =
213                 new AdSelectionClient.Builder()
214                         .setContext(sContext)
215                         .setExecutor(CALLBACK_EXECUTOR)
216                         .build();
217 
218         ExecutionException exception =
219                 assertThrows(
220                         ExecutionException.class,
221                         () -> mAdSelectionClient.selectAds(adSelectionConfig).get());
222         assertThat(exception.getMessage()).isEqualTo(CALLER_NOT_AUTHORIZED);
223     }
224 
225     @Test
testWithEnrollment_selectAds_adSelectionConfig()226     public void testWithEnrollment_selectAds_adSelectionConfig() {
227         Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable());
228         // The "test.com" buyer is a pre-seeded enrolled ad tech
229         AdSelectionConfig adSelectionConfig =
230                 AdSelectionConfigFixture.anAdSelectionConfig(
231                         AdTechIdentifier.fromString("test.com"));
232 
233         AdSelectionClient mAdSelectionClient =
234                 new AdSelectionClient.Builder()
235                         .setContext(sContext)
236                         .setExecutor(CALLBACK_EXECUTOR)
237                         .build();
238 
239         // When the ad tech is properly enrolled, just verify that the error thrown is not due to
240         // enrollment
241         ExecutionException exception =
242                 assertThrows(
243                         ExecutionException.class,
244                         () -> mAdSelectionClient.selectAds(adSelectionConfig).get());
245         assertThat(exception.getMessage()).isNotEqualTo(CALLER_NOT_AUTHORIZED);
246     }
247 
248     @Test
testNoEnrollment_reportImpression()249     public void testNoEnrollment_reportImpression() {
250         Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable());
251         AdSelectionConfig adSelectionConfig =
252                 AdSelectionConfigFixture.anAdSelectionConfig(
253                         AdTechIdentifier.fromString("seller.example.com"));
254 
255         long adSelectionId = 1;
256 
257         AdSelectionClient mAdSelectionClient =
258                 new AdSelectionClient.Builder()
259                         .setContext(sContext)
260                         .setExecutor(CALLBACK_EXECUTOR)
261                         .build();
262 
263         ReportImpressionRequest request =
264                 new ReportImpressionRequest(adSelectionId, adSelectionConfig);
265 
266         ExecutionException exception =
267                 assertThrows(
268                         ExecutionException.class,
269                         () -> mAdSelectionClient.reportImpression(request).get());
270         assertThat(exception.getMessage()).isEqualTo(CALLER_NOT_AUTHORIZED);
271     }
272 
273     @Test
testWithEnrollment_reportImpression()274     public void testWithEnrollment_reportImpression() {
275         Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable());
276         // The "test.com" buyer is a pre-seeded enrolled ad tech
277         AdSelectionConfig adSelectionConfig =
278                 AdSelectionConfigFixture.anAdSelectionConfig(
279                         AdTechIdentifier.fromString("test.com"));
280 
281         long adSelectionId = 1;
282 
283         AdSelectionClient mAdSelectionClient =
284                 new AdSelectionClient.Builder()
285                         .setContext(sContext)
286                         .setExecutor(CALLBACK_EXECUTOR)
287                         .build();
288 
289         ReportImpressionRequest request =
290                 new ReportImpressionRequest(adSelectionId, adSelectionConfig);
291 
292         // When the ad tech is properly enrolled, just verify that the error thrown is not due to
293         // enrollment
294         ExecutionException exception =
295                 assertThrows(
296                         ExecutionException.class,
297                         () -> mAdSelectionClient.reportImpression(request).get());
298         assertThat(exception.getMessage()).isNotEqualTo(CALLER_NOT_AUTHORIZED);
299     }
300 
301     // TODO(b/221876775): Unhide for frequency cap mainline promotion
302     /*
303     @Test
304     public void testNoEnrollment_updateAdCounterHistogram() {
305         long adSelectionId = 1;
306 
307         AdSelectionClient mAdSelectionClient =
308                 new AdSelectionClient.Builder()
309                         .setContext(sContext)
310                         .setExecutor(CALLBACK_EXECUTOR)
311                         .build();
312 
313         UpdateAdCounterHistogramRequest request =
314                 new UpdateAdCounterHistogramRequest.Builder()
315                         .setAdSelectionId(adSelectionId)
316                         .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_VIEW)
317                         .setCallerAdTech(AdTechIdentifier.fromString("seller.example.com"))
318                         .build();
319 
320         ExecutionException exception =
321                 assertThrows(
322                         ExecutionException.class,
323                         () -> mAdSelectionClient.updateAdCounterHistogram(request).get());
324         assertThat(exception.getMessage()).isEqualTo(CALLER_NOT_AUTHORIZED);
325     }
326 
327     @Test
328     public void testWithEnrollment_updateAdCounterHistogram()
329             throws ExecutionException, InterruptedException {
330         long adSelectionId = 1;
331 
332         AdSelectionClient mAdSelectionClient =
333                 new AdSelectionClient.Builder()
334                         .setContext(sContext)
335                         .setExecutor(CALLBACK_EXECUTOR)
336                         .build();
337 
338         UpdateAdCounterHistogramRequest request =
339                 new UpdateAdCounterHistogramRequest.Builder()
340                         .setAdSelectionId(adSelectionId)
341                         .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_VIEW)
342                         .setCallerAdTech(AdTechIdentifier.fromString("test.com"))
343                         .build();
344 
345         mAdSelectionClient.updateAdCounterHistogram(request).get();
346     }
347     */
348 }
349