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.cts.appcloning; 18 19 import com.android.modules.utils.build.testing.DeviceSdkLevel; 20 import com.android.tradefed.device.DeviceNotAvailableException; 21 import com.android.tradefed.device.ITestDevice; 22 import com.android.tradefed.device.NativeDevice; 23 import com.android.tradefed.log.LogUtil.CLog; 24 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 25 import com.android.tradefed.util.CommandResult; 26 import com.android.tradefed.util.CommandStatus; 27 28 import java.util.function.BooleanSupplier; 29 30 31 abstract class BaseHostTestCase extends BaseHostJUnit4Test { 32 private int mCurrentUserId = NativeDevice.INVALID_USER_ID; 33 private static final String ERROR_MESSAGE_TAG = "[ERROR]"; 34 protected ITestDevice mDevice = null; 35 setDevice()36 protected void setDevice() { 37 mDevice = getDevice(); 38 } 39 executeShellCommand(String cmd, Object... args)40 protected String executeShellCommand(String cmd, Object... args) throws Exception { 41 return mDevice.executeShellCommand(String.format(cmd, args)); 42 } 43 executeShellV2Command(String cmd, Object... args)44 protected CommandResult executeShellV2Command(String cmd, Object... args) throws Exception { 45 return mDevice.executeShellV2Command(String.format(cmd, args)); 46 } 47 isPackageInstalled(String packageName, String userId)48 protected boolean isPackageInstalled(String packageName, String userId) throws Exception { 49 return mDevice.isPackageInstalled(packageName, userId); 50 } 51 52 // TODO (b/174775905) remove after exposing the check from ITestDevice. isHeadlessSystemUserMode()53 protected boolean isHeadlessSystemUserMode() throws DeviceNotAvailableException { 54 String result = mDevice 55 .executeShellCommand("getprop ro.fw.mu.headless_system_user").trim(); 56 return "true".equalsIgnoreCase(result); 57 } 58 supportsMultipleUsers()59 protected boolean supportsMultipleUsers() throws DeviceNotAvailableException { 60 return mDevice.getMaxNumberOfUsersSupported() > 1; 61 } 62 isAtLeastS()63 protected boolean isAtLeastS() throws DeviceNotAvailableException { 64 DeviceSdkLevel deviceSdkLevel = new DeviceSdkLevel(mDevice); 65 return deviceSdkLevel.isDeviceAtLeastS(); 66 } 67 isAtLeastT()68 protected boolean isAtLeastT() throws DeviceNotAvailableException { 69 DeviceSdkLevel deviceSdkLevel = new DeviceSdkLevel(mDevice); 70 return deviceSdkLevel.isDeviceAtLeastT(); 71 } 72 throwExceptionIfTimeout(long start, long timeoutMillis, Throwable e)73 protected static void throwExceptionIfTimeout(long start, long timeoutMillis, Throwable e) { 74 if (System.currentTimeMillis() - start < timeoutMillis) { 75 try { 76 Thread.sleep(100); 77 } catch (InterruptedException ignored) { 78 throw new RuntimeException(e); 79 } 80 } else { 81 throw new RuntimeException(e); 82 } 83 } 84 eventually(ThrowingRunnable r, long timeoutMillis)85 protected static void eventually(ThrowingRunnable r, long timeoutMillis) { 86 long start = System.currentTimeMillis(); 87 88 while (true) { 89 try { 90 r.run(); 91 return; 92 } catch (Throwable e) { 93 throwExceptionIfTimeout(start, timeoutMillis, e); 94 } 95 } 96 } 97 eventually(ThrowingBooleanSupplier booleanSupplier, long timeoutMillis, String failureMessage)98 protected static void eventually(ThrowingBooleanSupplier booleanSupplier, 99 long timeoutMillis, String failureMessage) { 100 long start = System.currentTimeMillis(); 101 102 while (true) { 103 try { 104 if (booleanSupplier.getAsBoolean()) { 105 return; 106 } 107 108 throw new RuntimeException(failureMessage); 109 } catch (Throwable e) { 110 throwExceptionIfTimeout(start, timeoutMillis, e); 111 } 112 } 113 } 114 getCurrentUserId()115 protected int getCurrentUserId() throws Exception { 116 setCurrentUserId(); 117 118 return mCurrentUserId; 119 } 120 isSuccessful(CommandResult result)121 protected boolean isSuccessful(CommandResult result) { 122 if (!CommandStatus.SUCCESS.equals(result.getStatus())) { 123 return false; 124 } 125 String stdout = result.getStdout(); 126 if (stdout.contains(ERROR_MESSAGE_TAG)) { 127 return false; 128 } 129 String stderr = result.getStderr(); 130 return (stderr == null || stderr.trim().isEmpty()); 131 } 132 setCurrentUserId()133 private void setCurrentUserId() throws Exception { 134 if (mCurrentUserId != NativeDevice.INVALID_USER_ID) return; 135 136 mCurrentUserId = mDevice.getCurrentUser(); 137 CLog.i("Current user: %d"); 138 } 139 140 protected interface ThrowingRunnable { 141 /** 142 * Similar to {@link Runnable#run} but has {@code throws Exception}. 143 */ run()144 void run() throws Exception; 145 } 146 147 protected interface ThrowingBooleanSupplier { 148 /** 149 * Similar to {@link BooleanSupplier#getAsBoolean} but has {@code throws Exception}. 150 */ getAsBoolean()151 boolean getAsBoolean() throws Exception; 152 } 153 } 154