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.cts;
18 
19 import static com.android.adservices.service.DebugFlagsConstants.KEY_CONSENT_MANAGER_DEBUG_MODE;
20 import static com.android.adservices.service.FlagsConstants.KEY_ADSERVICES_ENABLED;
21 import static com.android.adservices.service.FlagsConstants.KEY_DISABLE_TOPICS_ENROLLMENT_CHECK;
22 import static com.android.adservices.service.FlagsConstants.KEY_GA_UX_FEATURE_ENABLED;
23 import static com.android.adservices.service.FlagsConstants.KEY_MDD_BACKGROUND_TASK_KILL_SWITCH;
24 import static com.android.adservices.service.FlagsConstants.KEY_TOPICS_KILL_SWITCH;
25 import static com.android.os.adservices.AdservicesExtensionAtoms.AD_SERVICES_SETTINGS_USAGE_REPORTED_FIELD_NUMBER;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static org.junit.Assert.assertNotNull;
30 
31 import android.cts.statsdatom.lib.ConfigUtils;
32 import android.cts.statsdatom.lib.ReportUtils;
33 
34 import com.android.adservices.common.AdServicesHostSideTestCase;
35 import com.android.adservices.shared.testing.BackgroundLogReceiver;
36 import com.android.adservices.shared.testing.annotations.EnableDebugFlag;
37 import com.android.adservices.shared.testing.annotations.SetFlagDisabled;
38 import com.android.adservices.shared.testing.annotations.SetFlagEnabled;
39 import com.android.internal.os.StatsdConfigProto.StatsdConfig;
40 import com.android.os.StatsLog.EventMetricData;
41 import com.android.os.adservices.AdServicesSettingsUsageReported;
42 import com.android.os.adservices.AdservicesExtensionAtoms;
43 import com.android.tradefed.device.DeviceNotAvailableException;
44 import com.android.tradefed.device.ITestDevice;
45 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
46 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics;
47 
48 import com.google.protobuf.ExtensionRegistry;
49 
50 import org.junit.After;
51 import org.junit.Before;
52 import org.junit.Rule;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 
56 import java.util.Arrays;
57 import java.util.List;
58 import java.util.function.Predicate;
59 
60 /**
61  * Test to check that Ui API logging to StatsD
62  *
63  * <p>The activity simply called Ui Settings Page which trigger the log event, and then check it in
64  * statsD.
65  */
66 @RunWith(DeviceJUnit4ClassRunner.class)
67 @SetFlagDisabled(KEY_TOPICS_KILL_SWITCH)
68 @SetFlagDisabled(KEY_MDD_BACKGROUND_TASK_KILL_SWITCH)
69 @SetFlagEnabled(KEY_ADSERVICES_ENABLED)
70 @SetFlagEnabled(KEY_DISABLE_TOPICS_ENROLLMENT_CHECK)
71 @SetFlagEnabled(KEY_GA_UX_FEATURE_ENABLED)
72 @EnableDebugFlag(KEY_CONSENT_MANAGER_DEBUG_MODE)
73 public final class UiApiLoggingHostTest extends AdServicesHostSideTestCase {
74     private static final String CLASS =
75             "com.android.adservices.ui.settings.activities.AdServicesSettingsMainActivity";
76     private static final String TARGET_PACKAGE_SUFFIX_TPLUS = "android.adservices.api";
77     private static final String TARGET_PACKAGE_SUFFIX_SMINUS = "android.ext.services";
78     private static final String LOGCAT_COMMAND = "logcat -s adservices";
79     private static final String LOG_FROM_BOOTCOMPLETE_RECEIVER =
80             "AdExtBootCompletedReceiver onReceive invoked";
81     public static final int WAIT_TIME_LONG = 2000;
82 
83     private static final String TARGET_EXT_ADSERVICES_PACKAGE =
84             "com.google.android.ext.adservices.api";
85     private static final String TARGET_EXT_ADSERVICES_PACKAGE_AOSP =
86             "com.android.ext.adservices.api";
87     private static final String LOW_RAM_DEVICE_CONFIG = "ro.config.low_ram";
88     private static final int PPAPI_AND_SYSTEM_SERVER_SOURCE_OF_TRUTH = 2;
89     private static final int APPSEARCH_ONLY = 3;
90     private int mApiLevel;
91 
92     private String mTargetPackage;
93 
94     @Rule(order = 10)
95     public TestMetrics metricsRule = new TestMetrics();
96 
97     @Before
setUp()98     public void setUp() throws Exception {
99         ConfigUtils.removeConfig(getDevice());
100         ReportUtils.clearReports(getDevice());
101 
102         // Set flags for test to run on devices with api level lower than 33 (S-)
103         String suffix =
104                 sdkLevel.isAtLeastT() ? TARGET_PACKAGE_SUFFIX_TPLUS : TARGET_PACKAGE_SUFFIX_SMINUS;
105         mTargetPackage = findPackageName(suffix);
106         assertThat(mTargetPackage).isNotNull();
107         restartAdservices(getDevice());
108     }
109     @After
tearDown()110     public void tearDown() throws Exception {
111         ConfigUtils.removeConfig(getDevice());
112         ReportUtils.clearReports(getDevice());
113     }
114 
115     @Test
testStartSettingMainActivityAndGetUiLog()116     public void testStartSettingMainActivityAndGetUiLog() throws Exception {
117         ITestDevice device = getDevice();
118         ExtensionRegistry registry = ExtensionRegistry.newInstance();
119         AdservicesExtensionAtoms.registerAllExtensions(registry);
120         assertNotNull("Device not set", device);
121 
122         rebootIfSMinus();
123         startSettingMainActivity(mTargetPackage, device);
124 
125         // Fetch a list of happened log events and their data
126         List<EventMetricData> data = ReportUtils.getEventMetricDataList(device, registry);
127 
128         // We trigger only one event from activity, should only see one event in the list
129         assertThat(data).hasSize(1);
130 
131         // Verify the log event data
132         AdServicesSettingsUsageReported adServicesSettingsUsageReported =
133                 data.get(0)
134                         .getAtom()
135                         .getExtension(AdservicesExtensionAtoms.adServicesSettingsUsageReported);
136         assertThat(adServicesSettingsUsageReported.getAction())
137                 .isEqualTo(
138                         AdServicesSettingsUsageReported.AdServiceSettingsName
139                                 .PRIVACY_SANDBOX_SETTINGS_PAGE_DISPLAYED);
140     }
141 
rebootIfSMinus()142     private void rebootIfSMinus() throws DeviceNotAvailableException, InterruptedException {
143         if (sdkLevel.isAtLeastT()) {
144             return;
145         }
146 
147         ITestDevice device = getDevice();
148         device.reboot();
149         device.waitForDeviceAvailable();
150 
151         // Start log collection, keep going until the boot complete receiver runs or times out.
152         // Wait for up to 5 minutes for AdBootCompletedReceiver execution
153         BackgroundLogReceiver logcatReceiver =
154                 new BackgroundLogReceiver.Builder()
155                         .setDevice(mDevice)
156                         .setLogCatCommand(LOGCAT_COMMAND)
157                         .setEarlyStopCondition(stopIfBootCompleteReceiverLogOccurs())
158                         .build();
159         logcatReceiver.collectLogs(/* timeoutMilliseconds= */ 5 * 60 * 1000);
160     }
161 
stopIfBootCompleteReceiverLogOccurs()162     private Predicate<String[]> stopIfBootCompleteReceiverLogOccurs() {
163         return (s) -> Arrays.stream(s).anyMatch(t -> t.contains(LOG_FROM_BOOTCOMPLETE_RECEIVER));
164     }
165 
startSettingMainActivity(String apiName, ITestDevice device)166     private void startSettingMainActivity(String apiName, ITestDevice device) throws Exception {
167         // Upload the config.
168         final StatsdConfig.Builder config = ConfigUtils.createConfigBuilder(apiName);
169 
170         ConfigUtils.addEventMetric(config, AD_SERVICES_SETTINGS_USAGE_REPORTED_FIELD_NUMBER);
171         ConfigUtils.uploadConfig(device, config);
172         // Start the ui main activity, it will make a ui log call
173         startUiMainActivity(device);
174         Thread.sleep(WAIT_TIME_LONG);
175     }
176 
startUiMainActivity(ITestDevice device)177     public void startUiMainActivity(ITestDevice device) throws DeviceNotAvailableException {
178         device.executeShellCommand("am start -n " + mTargetPackage + "/" + CLASS);
179     }
180 
findPackageName(String suffix)181     private String findPackageName(String suffix) throws DeviceNotAvailableException {
182         return mDevice.getInstalledPackageNames().stream()
183                 .filter(s -> s.endsWith(suffix))
184                 .findFirst()
185                 .orElse(null);
186     }
187 
restartAdservices(ITestDevice device)188     private void restartAdservices(ITestDevice device) throws DeviceNotAvailableException {
189         device.executeShellCommand("am force-stop com.google.android.adservices.api");
190         device.executeShellCommand("am force-stop com.android.adservices.api");
191         device.executeShellCommand("am force-stop com.google.android.ext.adservices.api");
192         device.executeShellCommand("am force-stop com.android.ext.adservices.api");
193     }
194 }
195