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 android.appenumeration.cts; 18 19 import static com.android.compatibility.common.util.ShellUtils.runShellCommand; 20 21 import static com.google.common.truth.Truth.assertThat; 22 import static com.google.common.truth.Truth.assertWithMessage; 23 24 import android.content.Context; 25 import android.content.pm.PackageInfo; 26 import android.content.pm.PackageInstaller; 27 import android.content.pm.PackageManager; 28 import android.content.pm.PackageManager.NameNotFoundException; 29 import android.content.pm.PackageManager.PackageInfoFlags; 30 import android.os.Bundle; 31 32 import androidx.annotation.Nullable; 33 import androidx.test.platform.app.InstrumentationRegistry; 34 35 import com.android.bedstead.nene.users.UserReference; 36 import com.android.cts.install.lib.InstallUtils; 37 import com.android.cts.install.lib.LocalIntentSender; 38 39 import org.junit.Assert; 40 41 import java.io.File; 42 import java.util.List; 43 44 public class Utils { 45 46 private static Context sContext; 47 private static PackageManager sPm; 48 49 interface Result { await()50 Bundle await() throws Exception; 51 } 52 53 interface ThrowingBiFunction<T, U, R> { apply(T arg1, U arg2)54 R apply(T arg1, U arg2) throws Exception; 55 } 56 57 interface ThrowingFunction<T, R> { apply(T arg1)58 R apply(T arg1) throws Exception; 59 } 60 getContext()61 private static Context getContext() { 62 if (sContext == null) { 63 sContext = InstrumentationRegistry.getInstrumentation().getContext(); 64 } 65 return sContext; 66 } 67 getPackageManager()68 private static PackageManager getPackageManager() { 69 if (sPm == null) { 70 sPm = getContext().getPackageManager(); 71 } 72 return sPm; 73 } 74 75 /** 76 * Install the APK on all users. 77 **/ installPackage(String apkPath)78 static void installPackage(String apkPath) { 79 installPackageForUser(apkPath, null /* user */, null /* installerPackageName */); 80 } 81 82 /** 83 * Install the APK on all users with specific installer. 84 **/ installPackage(String apkPath, String installerPackageName)85 static void installPackage(String apkPath, String installerPackageName) { 86 installPackageForUser(apkPath, null /* user */, installerPackageName); 87 } 88 89 /** 90 * Install the APK on the given user. 91 **/ installPackageForUser(String apkPath, UserReference user)92 static void installPackageForUser(String apkPath, UserReference user) { 93 installPackageForUser(apkPath, user, getContext().getPackageName()); 94 } 95 96 /** 97 * Install the APK on the given user with specific installer. 98 **/ installPackageForUser(String apkPath, UserReference user, String installerPackageName)99 private static void installPackageForUser(String apkPath, UserReference user, 100 String installerPackageName) { 101 assertWithMessage(apkPath).that(new File(apkPath).exists()).isTrue(); 102 final StringBuilder cmd = new StringBuilder("pm install "); 103 if (user != null) { 104 cmd.append("--user ").append(user.id()).append(" "); 105 } 106 if (installerPackageName != null) { 107 cmd.append("-i ").append(installerPackageName).append(" "); 108 } 109 cmd.append(apkPath); 110 final String result = runShellCommand(cmd.toString()).trim(); 111 assertWithMessage(result).that(result).contains("Success"); 112 } 113 114 /** 115 * Install the existing package for the APK on the given user. 116 **/ installExistPackageForUser(String apkPath, UserReference user)117 static void installExistPackageForUser(String apkPath, UserReference user) { 118 final StringBuilder cmd = new StringBuilder("pm install-existing "); 119 // If the user reference is null, it only effects on the current user. 120 if (user != null) { 121 cmd.append("--user ").append(user.id()).append(" "); 122 } 123 cmd.append(apkPath); 124 final String result = runShellCommand(cmd.toString()); 125 assertThat(result.trim()).contains("installed"); 126 } 127 128 /** 129 * Uninstall the package on all users. 130 **/ uninstallPackage(String packageName)131 static void uninstallPackage(String packageName) { 132 uninstallPackageForUser(packageName, null /* user */); 133 } 134 135 /** 136 * Uninstall the package on the given user. 137 **/ uninstallPackageForUser(String packageName, UserReference user)138 static void uninstallPackageForUser(String packageName, UserReference user) { 139 final StringBuilder cmd = new StringBuilder("pm uninstall "); 140 // If the user reference is null, it effects on all users. 141 if (user != null) { 142 cmd.append("--user ").append(user.id()).append(" "); 143 } 144 cmd.append(packageName); 145 runShellCommand(cmd.toString()); 146 } 147 148 /** 149 * Force stopping the processes of the package on all users. 150 **/ forceStopPackage(String packageName)151 static void forceStopPackage(String packageName) { 152 forceStopPackageForUser(packageName, null /* user */); 153 } 154 155 /** 156 * Force stopping the processes of the package on the given user. 157 **/ forceStopPackageForUser(String packageName, UserReference user)158 static void forceStopPackageForUser(String packageName, UserReference user) { 159 final StringBuilder cmd = new StringBuilder("am force-stop "); 160 // If the user reference is null, it effects on all users. 161 if (user != null) { 162 cmd.append("--user ").append(user.id()).append(" "); 163 } 164 cmd.append(packageName); 165 runShellCommand(cmd.toString()); 166 } 167 168 /** 169 * Clear app data of the given package on the given user. 170 **/ clearAppDataForUser(String packageName, UserReference user)171 static void clearAppDataForUser(String packageName, UserReference user) { 172 final StringBuilder cmd = new StringBuilder("pm clear "); 173 // If the user reference is null, it only effects on the system user. 174 if (user != null) { 175 cmd.append("--user ").append(user.id()).append(" "); 176 } 177 cmd.append(packageName); 178 runShellCommand(cmd.toString()); 179 } 180 181 /** 182 * Suspend/Unsuspend the packages on the current user. 183 **/ suspendPackages(boolean suspend, List<String> packages)184 static void suspendPackages(boolean suspend, List<String> packages) { 185 suspendPackagesForUser(suspend, packages, UserReference.of(getContext().getUser()), 186 false /* extraPersistableBundle */); 187 } 188 189 /** 190 * Suspend/Unsuspend the packages on the given user. 191 **/ suspendPackagesForUser(boolean suspend, List<String> packages, UserReference user, boolean extraPersistableBundle)192 static void suspendPackagesForUser(boolean suspend, List<String> packages, 193 UserReference user, boolean extraPersistableBundle) { 194 final StringBuilder cmd = new StringBuilder("pm "); 195 if (suspend) { 196 cmd.append("suspend").append(" "); 197 } else { 198 cmd.append("unsuspend").append(" "); 199 } 200 // If the user reference is null, it only effects on the system user. 201 if (user != null) { 202 cmd.append("--user ").append(user.id()).append(" "); 203 } 204 if (extraPersistableBundle) { 205 cmd.append("--les foo bar").append(" "); 206 } 207 packages.stream().forEach(p -> cmd.append(p).append(" ")); 208 runShellCommand(cmd.toString()); 209 } 210 211 /** 212 * Ensure the given package is installed; otherwise install via the APK. 213 */ ensurePackageIsInstalled(String packageName, String apkPath)214 static void ensurePackageIsInstalled(String packageName, String apkPath) { 215 runShellCommand("pm install -R " + apkPath); 216 PackageInfo info = null; 217 try { 218 info = getPackageManager().getPackageInfo(packageName, PackageInfoFlags.of(0)); 219 } catch (NameNotFoundException e) { 220 // Ignore 221 } 222 Assert.assertNotNull(packageName + " should be installed", info); 223 } 224 225 /** 226 * Ensure the given package isn't install; otherwise uninstall it. 227 */ ensurePackageIsNotInstalled(String packageName)228 static void ensurePackageIsNotInstalled(String packageName) { 229 uninstallPackage(packageName); 230 PackageInfo info = null; 231 try { 232 info = getPackageManager().getPackageInfo(packageName, PackageInfoFlags.of(0)); 233 } catch (NameNotFoundException e) { 234 // Expected 235 } 236 Assert.assertNull(packageName + " shouldn't be installed", info); 237 } 238 239 /** 240 * Adopt the permission identity of the shell UID only for the provided permissions. 241 * @param permissions The permissions to adopt or <code>null</code> to adopt all. 242 */ adoptShellPermissions(@ullable String... permissions)243 static void adoptShellPermissions(@Nullable String... permissions) { 244 InstrumentationRegistry 245 .getInstrumentation() 246 .getUiAutomation() 247 .adoptShellPermissionIdentity(permissions); 248 } 249 250 /** 251 * Drop the shell permission identity adopted. 252 */ dropShellPermissions()253 static void dropShellPermissions() { 254 InstrumentationRegistry 255 .getInstrumentation() 256 .getUiAutomation() 257 .dropShellPermissionIdentity(); 258 } 259 260 /** 261 * Attempt to commit everything staged in this session. 262 */ commitSession(int sessionId)263 static void commitSession(int sessionId) throws Exception { 264 final PackageInstaller.Session session = 265 InstallUtils.openPackageInstallerSession(sessionId); 266 final LocalIntentSender sender = new LocalIntentSender(); 267 session.commit(sender.getIntentSender()); 268 InstallUtils.assertStatusSuccess(sender.getResult()); 269 } 270 271 /** 272 * Abandon all the sessions owned by you, destroying all staged data and rendering them invalid. 273 */ cleanUpMySessions()274 static void cleanUpMySessions() { 275 InstallUtils.getPackageInstaller().getMySessions().forEach(info -> { 276 try { 277 InstallUtils.getPackageInstaller().abandonSession(info.getSessionId()); 278 } catch (Exception e) { 279 // Ignore 280 } 281 }); 282 } 283 284 /** 285 * Grants access to APIs marked as {@code @TestApi}. 286 */ allowTestApiAccess(String pgkName)287 static void allowTestApiAccess(String pgkName) { 288 final StringBuilder cmd = new StringBuilder("am compat enable ALLOW_TEST_API_ACCESS "); 289 cmd.append(pgkName); 290 final String result = runShellCommand(cmd.toString()).trim(); 291 assertWithMessage(result).that(result).startsWith("Enabled change"); 292 } 293 294 /** 295 * Resets access to APIs marked as {@code @TestApi}. 296 */ resetTestApiAccess(String pgkName)297 static void resetTestApiAccess(String pgkName) { 298 final StringBuilder cmd = new StringBuilder("am compat reset ALLOW_TEST_API_ACCESS "); 299 cmd.append(pgkName); 300 final String result = runShellCommand(cmd.toString()).trim(); 301 assertWithMessage(result).that(result).startsWith("Reset change"); 302 } 303 } 304