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 android.ondevicepersonalization.test.scenario.ondevicepersonalization; 17 18 import android.os.SystemClock; 19 20 import androidx.test.platform.app.InstrumentationRegistry; 21 import androidx.test.uiautomator.UiDevice; 22 23 import org.junit.Assert; 24 25 import java.io.IOException; 26 import java.util.List; 27 28 /** Helper class for interacting with download flow. */ 29 public class DownloadHelper { 30 private static UiDevice sUiDevice; 31 private static final String MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID = "1003"; 32 private static final String DOWNLOAD_PROCESSING_TASK_JOB_ID = "1004"; 33 private static final String MAINTENANCE_TASK_JOB_ID = "1005"; 34 private static final String DOWNLOAD_JOB_SUCCESS_LOG = 35 "MddJobService: MddJobService.MddHandleTask succeeded!"; 36 private static final String FILTER_AND_STORE_DATA_SUCCESS_LOG = 37 "DownloadFlow: " 38 + "filter and store data completed, transaction successful: true"; 39 private static final String FILTER_AND_STORE_NOT_NEW_LOG = 40 "DownloadFlow: syncToken is not newer than existing token."; 41 private static final long DOWNLOAD_JOB_COMPLETION_TIMEOUT = 120_000; 42 private static final long DOWNLOAD_PROCESSING_JOB_COMPLETION_TIMEOUT = 120_000; 43 44 /** Commands to prepare the device and odp module before testing. */ initialize()45 public static void initialize() throws IOException { 46 executeShellCommand( 47 "device_config set_sync_disabled_for_tests persistent"); 48 executeShellCommand( 49 "device_config put on_device_personalization global_kill_switch false"); 50 executeShellCommand( 51 "device_config put on_device_personalization " 52 + "enable_ondevicepersonalization_apis true"); 53 executeShellCommand( 54 "device_config put on_device_personalization " 55 + "enable_personalization_status_override true"); 56 executeShellCommand( 57 "device_config put on_device_personalization " 58 + "personalization_status_override_value true"); 59 executeShellCommand("setprop log.tag.ondevicepersonalization VERBOSE"); 60 executeShellCommand( 61 "am broadcast -a android.intent.action.BOOT_COMPLETED -p " 62 + "com.google.android.ondevicepersonalization.services"); 63 executeShellCommand( 64 "cmd jobscheduler run -f " 65 + "com.google.android.ondevicepersonalization.services 1000"); 66 SystemClock.sleep(5000); 67 executeShellCommand( 68 "cmd jobscheduler run -f " 69 + "com.google.android.ondevicepersonalization.services 1006"); 70 SystemClock.sleep(5000); 71 } 72 73 /** Kill running processes to get performance measurement under cold start */ killRunningProcess()74 public static void killRunningProcess() throws IOException { 75 executeShellCommand("am kill com.google.android.ondevicepersonalization.services"); 76 executeShellCommand("am kill com.google.android.ondevicepersonalization.services:" 77 + "com.android.ondevicepersonalization." 78 + "libraries.plugin.internal.PluginExecutorService"); 79 executeShellCommand("am kill com.google.android.ondevicepersonalization.services:" 80 + "plugin_disable_art_image_:" 81 + "com.android.ondevicepersonalization." 82 + "libraries.plugin.internal.PluginExecutorService"); 83 SystemClock.sleep(2000); 84 } pressHome()85 public static void pressHome() { 86 getUiDevice().pressHome(); 87 } 88 cleanupDatabase()89 public void cleanupDatabase() throws IOException { 90 executeShellCommand( 91 "cmd jobscheduler run -f com.google.android.ondevicepersonalization.services " 92 + MAINTENANCE_TASK_JOB_ID); 93 SystemClock.sleep(5000); 94 } 95 cleanupDownloadedMetadata()96 public void cleanupDownloadedMetadata() throws IOException { 97 executeShellCommand( 98 "cmd jobscheduler run -f com.google.android.ondevicepersonalization.services " 99 + MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID); 100 SystemClock.sleep(5000); 101 } 102 downloadVendorData()103 public void downloadVendorData() throws IOException { 104 executeShellCommand("logcat -c"); // Cleans the log buffer 105 executeShellCommand("logcat -G 32M"); // Set log buffer to 32MB 106 executeShellCommand( 107 "cmd jobscheduler run -f com.google.android.ondevicepersonalization.services " 108 + MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID); 109 110 boolean foundDownloadJobSuccessLog = findLog( 111 DOWNLOAD_JOB_SUCCESS_LOG, 112 DOWNLOAD_JOB_COMPLETION_TIMEOUT, 113 5000); 114 115 if (!foundDownloadJobSuccessLog) { 116 Assert.fail(String.format( 117 "Failed to find download job success log %s within test window %d ms", 118 DOWNLOAD_JOB_SUCCESS_LOG, 119 DOWNLOAD_JOB_COMPLETION_TIMEOUT)); 120 } 121 } 122 123 /** 124 * Process downloaded vendor data assuming it is new data. 125 */ processDownloadedVendorData()126 public void processDownloadedVendorData() throws IOException { 127 processDownloadVendorData(true); 128 } 129 130 /** 131 * Process downloaded vendor data, ignoring whether it is new or existing downloaded data. 132 */ processExistingOrNewDownloadedVendorData()133 public void processExistingOrNewDownloadedVendorData() throws IOException { 134 processDownloadVendorData(false); 135 } 136 processDownloadVendorData(boolean newDownload)137 private void processDownloadVendorData(boolean newDownload) throws IOException { 138 executeShellCommand( 139 "cmd jobscheduler run -f com.google.android.ondevicepersonalization.services " 140 + DOWNLOAD_PROCESSING_TASK_JOB_ID); 141 142 if (newDownload) { 143 boolean foundFilterAndStoreDataSuccessLog = findLog( 144 FILTER_AND_STORE_DATA_SUCCESS_LOG, 145 DOWNLOAD_PROCESSING_JOB_COMPLETION_TIMEOUT, 146 5000); 147 148 if (!foundFilterAndStoreDataSuccessLog) { 149 Assert.fail(String.format( 150 "Failed to find filter and store data success log %s within test window " 151 + "%d ms", 152 foundFilterAndStoreDataSuccessLog, 153 DOWNLOAD_PROCESSING_JOB_COMPLETION_TIMEOUT)); 154 } 155 } else { 156 boolean foundFilterAndStoreDataSuccessLog = findLog( 157 List.of(FILTER_AND_STORE_DATA_SUCCESS_LOG, FILTER_AND_STORE_NOT_NEW_LOG), 158 DOWNLOAD_PROCESSING_JOB_COMPLETION_TIMEOUT, 159 5000); 160 161 if (!foundFilterAndStoreDataSuccessLog) { 162 Assert.fail(String.format( 163 "Failed to find filter and store data success log %s within test window " 164 + "%d ms", 165 foundFilterAndStoreDataSuccessLog, 166 DOWNLOAD_PROCESSING_JOB_COMPLETION_TIMEOUT)); 167 } 168 } 169 } 170 171 /** Attempt to find a specific log entry within the timeout window */ findLog(final String targetLog, long timeoutMillis, long queryIntervalMillis)172 private boolean findLog(final String targetLog, long timeoutMillis, 173 long queryIntervalMillis) throws IOException { 174 return findLog(List.of(targetLog), timeoutMillis, queryIntervalMillis); 175 } 176 177 /** Attempt to find a one of specific log entries within the timeout window */ findLog(final List<String> targetLogs, long timeoutMillis, long queryIntervalMillis)178 private boolean findLog(final List<String> targetLogs, long timeoutMillis, 179 long queryIntervalMillis) throws IOException { 180 181 long startTime = System.currentTimeMillis(); 182 while (System.currentTimeMillis() - startTime < timeoutMillis) { 183 String logcat = getUiDevice().executeShellCommand("logcat -d"); 184 if (targetLogs.stream().anyMatch(logcat::contains)) { 185 return true; 186 } 187 SystemClock.sleep(queryIntervalMillis); 188 } 189 return false; 190 } 191 executeShellCommand(String cmd)192 private static void executeShellCommand(String cmd) { 193 try { 194 getUiDevice().executeShellCommand(cmd); 195 } catch (IOException e) { 196 Assert.fail("Failed to execute shell command: " + cmd + ". error: " + e); 197 } 198 } 199 getUiDevice()200 private static UiDevice getUiDevice() { 201 if (sUiDevice == null) { 202 sUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 203 } 204 return sUiDevice; 205 } 206 207 /** Commands to return device to original state */ wrapUp()208 public static void wrapUp() throws IOException { 209 executeShellCommand( 210 "device_config set_sync_disabled_for_tests none"); 211 } 212 213 } 214