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;
18 
19 import android.app.Instrumentation;
20 import android.content.Intent;
21 import android.content.pm.PackageManager;
22 import android.content.pm.ResolveInfo;
23 import android.content.pm.ServiceInfo;
24 import android.os.Build;
25 import android.util.Log;
26 
27 import androidx.core.os.BuildCompat;
28 import androidx.test.core.app.ApplicationProvider;
29 
30 import java.util.List;
31 import java.util.stream.Collectors;
32 
33 // TODO(b/299104530): replace device_config usage by AdServicesFlagSetterRule
34 public class TestUtil {
35     private Instrumentation mInstrumentation;
36     private String mTag;
37     // Used to get the package name. Copied over from com.android.adservices.AdServicesCommon
38     private static final String MEASUREMENT_SERVICE_NAME = "android.adservices.MEASUREMENT_SERVICE";
39     private static final String EXT_SERVICES_PACKAGE_NAME = "ext.adservices";
40     // The JobId of the Epoch Computation.
41     private static final int EPOCH_JOB_ID = 2;
42 
TestUtil(Instrumentation instrumentation, String tag)43     public TestUtil(Instrumentation instrumentation, String tag) {
44         mInstrumentation = instrumentation;
45         mTag = tag;
46     }
47     // Run shell command.
runShellCommand(String command)48     private void runShellCommand(String command) {
49         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
50             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
51                 mInstrumentation.getUiAutomation().executeShellCommand(command);
52             }
53         }
54     }
55 
overrideKillSwitches(boolean override)56     public void overrideKillSwitches(boolean override) {
57         if (override) {
58             runShellCommand("device_config put adservices global_kill_switch " + false);
59             runShellCommand("device_config put adservices topics_kill_switch " + false);
60         } else {
61             runShellCommand("device_config put adservices global_kill_switch " + null);
62             runShellCommand("device_config put adservices topics_kill_switch " + null);
63         }
64     }
65 
enableEnrollmentCheck(boolean enable)66     public void enableEnrollmentCheck(boolean enable) {
67         runShellCommand("device_config put adservices disable_topics_enrollment_check " + enable);
68     }
69 
70     // Override the Epoch Period to shorten the Epoch Length in the test.
overrideEpochPeriod(long overrideEpochPeriod)71     public void overrideEpochPeriod(long overrideEpochPeriod) {
72         runShellCommand(
73                 "device_config put adservices topics_epoch_job_period_ms " + overrideEpochPeriod);
74     }
75 
76     // Override the Percentage For Random Topic in the test.
overridePercentageForRandomTopic(long overridePercentage)77     public void overridePercentageForRandomTopic(long overridePercentage) {
78         runShellCommand(
79                 "device_config put adservices topics_percentage_for_random_topics "
80                         + overridePercentage);
81     }
82 
83     /** Forces JobScheduler to run the Epoch Computation job */
forceEpochComputationJob()84     public void forceEpochComputationJob() {
85         runShellCommand(
86                 "cmd jobscheduler run -f" + " " + getAdServicesPackageName() + " " + EPOCH_JOB_ID);
87     }
88 
overrideConsentManagerDebugMode(boolean override)89     public void overrideConsentManagerDebugMode(boolean override) {
90         String overrideStr = override ? "true" : "null";
91         runShellCommand("setprop debug.adservices.consent_manager_debug_mode " + overrideStr);
92     }
93 
overrideAllowlists(boolean override)94     public void overrideAllowlists(boolean override) {
95         String overrideStr = override ? "*" : "null";
96         runShellCommand("device_config put adservices ppapi_app_allow_list " + overrideStr);
97         runShellCommand("device_config put adservices msmt_api_app_allow_list " + overrideStr);
98         runShellCommand(
99                 "device_config put adservices ppapi_app_signature_allow_list " + overrideStr);
100         runShellCommand(
101                 "device_config put adservices web_context_client_allow_list " + overrideStr);
102     }
103 
overrideAdIdKillSwitch(boolean override)104     public void overrideAdIdKillSwitch(boolean override) {
105         if (override) {
106             runShellCommand("device_config put adservices adid_kill_switch " + false);
107         } else {
108             runShellCommand("device_config put adservices adid_kill_switch " + null);
109         }
110     }
111 
overrideAppSetIdKillSwitch(boolean override)112     public void overrideAppSetIdKillSwitch(boolean override) {
113         if (override) {
114             runShellCommand("device_config put adservices appsetid_kill_switch " + false);
115         } else {
116             runShellCommand("device_config put adservices appsetid_kill_switch " + null);
117         }
118     }
119 
120     // Override measurement related kill switch to ignore the effect of actual PH values.
121     // If isOverride = true, override measurement related kill switch to OFF to allow adservices
122     // If isOverride = false, override measurement related kill switch to meaningless value so that
123     // PhFlags will use the default value.
overrideMeasurementKillSwitches(boolean isOverride)124     public void overrideMeasurementKillSwitches(boolean isOverride) {
125         String overrideString = isOverride ? "false" : "null";
126         runShellCommand("device_config put adservices global_kill_switch " + overrideString);
127         runShellCommand("device_config put adservices measurement_kill_switch " + overrideString);
128         runShellCommand(
129                 "device_config put adservices measurement_api_register_source_kill_switch "
130                         + overrideString);
131         runShellCommand(
132                 "device_config put adservices measurement_api_register_trigger_kill_switch "
133                         + overrideString);
134         runShellCommand(
135                 "device_config put adservices measurement_api_register_web_source_kill_switch "
136                         + overrideString);
137         runShellCommand(
138                 "device_config put adservices measurement_api_register_web_trigger_kill_switch "
139                         + overrideString);
140         runShellCommand(
141                 "device_config put adservices measurement_api_delete_registrations_kill_switch "
142                         + overrideString);
143         runShellCommand(
144                 "device_config put adservices measurement_api_status_kill_switch "
145                         + overrideString);
146     }
147 
148     // Override the flag to disable Measurement enrollment check. Setting to 1 disables enforcement.
overrideDisableMeasurementEnrollmentCheck(String val)149     public void overrideDisableMeasurementEnrollmentCheck(String val) {
150         runShellCommand("device_config put adservices disable_measurement_enrollment_check " + val);
151     }
152 
resetOverrideDisableMeasurementEnrollmentCheck()153     public void resetOverrideDisableMeasurementEnrollmentCheck() {
154         runShellCommand("device_config put adservices disable_measurement_enrollment_check null");
155     }
156 
157     // Force using bundled files instead of using MDD downloaded files. This helps to make the test
158     // results deterministic.
shouldForceUseBundledFiles(boolean shouldUse)159     public void shouldForceUseBundledFiles(boolean shouldUse) {
160         if (shouldUse) {
161             runShellCommand("device_config put adservices classifier_force_use_bundled_files true");
162         } else {
163             runShellCommand("device_config delete adservices classifier_force_use_bundled_files");
164         }
165     }
166 
enableVerboseLogging()167     public void enableVerboseLogging() {
168         runShellCommand("setprop log.tag.adservices VERBOSE");
169     }
170 
overrideFledgeSelectAdsKillSwitch(boolean override)171     public void overrideFledgeSelectAdsKillSwitch(boolean override) {
172         if (override) {
173             runShellCommand("device_config put adservices fledge_select_ads_kill_switch " + false);
174         } else {
175             runShellCommand("device_config put adservices fledge_select_ads_kill_switch " + null);
176         }
177     }
178 
overrideFledgeCustomAudienceServiceKillSwitch(boolean override)179     public void overrideFledgeCustomAudienceServiceKillSwitch(boolean override) {
180         if (override) {
181             runShellCommand(
182                     "device_config put adservices fledge_custom_audience_service_kill_switch "
183                             + false);
184         } else {
185             runShellCommand(
186                     "device_config put adservices fledge_custom_audience_service_kill_switch "
187                             + null);
188         }
189     }
190 
overrideSdkRequestPermitsPerSecond(long maxRequests)191     public void overrideSdkRequestPermitsPerSecond(long maxRequests) {
192         runShellCommand(
193                 "device_config put adservices sdk_request_permits_per_second " + maxRequests);
194     }
195 
disableDeviceConfigSyncForTests(boolean disabled)196     public void disableDeviceConfigSyncForTests(boolean disabled) {
197         if (disabled) {
198             runShellCommand("device_config set_sync_disabled_for_tests persistent");
199         } else {
200             runShellCommand("device_config set_sync_disabled_for_tests none");
201         }
202     }
203 
disableFledgeEnrollmentCheck(boolean disabled)204     public void disableFledgeEnrollmentCheck(boolean disabled) {
205         if (disabled) {
206             runShellCommand("device_config put adservices disable_fledge_enrollment_check true");
207         } else {
208             runShellCommand("device_config put adservices disable_fledge_enrollment_check false");
209         }
210     }
211 
enableAdServiceSystemService(boolean enabled)212     public void enableAdServiceSystemService(boolean enabled) {
213         if (enabled) {
214             runShellCommand(
215                     "device_config put adservices adservice_system_service_enabled " + "\"true\"");
216         } else {
217             runShellCommand(
218                     "device_config put adservices adservice_system_service_enabled " + "\"false\"");
219         }
220     }
221 
enforceFledgeJsIsolateMaxHeapSize(boolean enforce)222     public void enforceFledgeJsIsolateMaxHeapSize(boolean enforce) {
223         if (enforce) {
224             runShellCommand(
225                     "device_config put adservices fledge_js_isolate_enforce_max_heap_size"
226                             + " true");
227         } else {
228             runShellCommand(
229                     "device_config put adservices fledge_js_isolate_enforce_max_heap_size"
230                             + " false");
231         }
232     }
233 
234     @SuppressWarnings("deprecation")
235     // Used to get the package name. Copied over from com.android.adservices.AndroidServiceBinder
getAdServicesPackageName()236     public String getAdServicesPackageName() {
237         final Intent intent = new Intent(MEASUREMENT_SERVICE_NAME);
238         List<ResolveInfo> resolveInfos =
239                 ApplicationProvider.getApplicationContext()
240                         .getPackageManager()
241                         .queryIntentServices(intent, PackageManager.MATCH_SYSTEM_ONLY);
242 
243         // TODO: b/271866693 avoid hardcoding package names
244         if (resolveInfos != null && BuildCompat.isAtLeastT()) {
245             resolveInfos =
246                     resolveInfos.stream()
247                             .filter(
248                                     info ->
249                                             !info.serviceInfo.packageName.contains(
250                                                     EXT_SERVICES_PACKAGE_NAME))
251                             .collect(Collectors.toList());
252         }
253 
254         if (resolveInfos == null || resolveInfos.isEmpty()) {
255             Log.d(
256                     mTag,
257                     "Failed to find resolveInfo for adServices service. Intent action: "
258                             + MEASUREMENT_SERVICE_NAME);
259             return null;
260         }
261 
262         if (resolveInfos.size() > 1) {
263             String str =
264                     String.format(
265                             "Found multiple services (%1$s) for the same intent action (%2$s)",
266                             MEASUREMENT_SERVICE_NAME, resolveInfos);
267             Log.d(mTag, str);
268             return null;
269         }
270 
271         final ServiceInfo serviceInfo = resolveInfos.get(0).serviceInfo;
272         if (serviceInfo == null) {
273             Log.d(mTag, "Failed to find serviceInfo for adServices service");
274             return null;
275         }
276 
277         return serviceInfo.packageName;
278     }
279 }
280