1 /* 2 * Copyright (C) 2021 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.managedprovisioning.task; 18 19 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; 21 22 import static com.android.managedprovisioning.task.InstallPackageTask.ERROR_INSTALLATION_FAILED; 23 24 import static com.google.common.truth.Truth.assertThat; 25 26 import static org.junit.Assert.fail; 27 28 import android.app.Instrumentation; 29 import android.content.Context; 30 import android.os.UserHandle; 31 32 import androidx.test.InstrumentationRegistry; 33 import androidx.test.filters.SmallTest; 34 35 import com.android.bedstead.harrier.annotations.EnsureHasPermission; 36 import com.android.bedstead.testapp.TestApp; 37 import com.android.bedstead.testapp.TestAppProvider; 38 import com.android.compatibility.common.util.BlockingCallback; 39 import com.android.managedprovisioning.model.ProvisioningParams; 40 41 import org.junit.Before; 42 import org.junit.Ignore; 43 import org.junit.Test; 44 45 import java.io.File; 46 import java.io.IOException; 47 import java.io.PrintWriter; 48 49 50 @SmallTest 51 public class InstallPackageTaskTest { 52 53 private final static int RESULT_SUCCESS = -1; 54 private final static int USER_ID = 0; 55 private final static UserHandle USER_HANDLE = new UserHandle(USER_ID); 56 private final static Instrumentation sInstrumentation = 57 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation(); 58 private final static Context sContext = InstrumentationRegistry.getTargetContext(); 59 private final static String TEST_PACKAGE_NAME = "test.package.name"; 60 private static final String INVALID_FILE_CONTENTS = "invalid contents"; 61 private static final PackageLocationProvider FILE_NULL_PATH_PROVIDER = () -> null; 62 private static final PackageLocationProvider FILE_INVALID_PATH_PROVIDER = 63 () -> new File("invalid/path"); 64 private static final String TEST_APP = "android.EmptyTestApp"; 65 66 private InstallPackageBlockingCallback mInstallPackageBlockingCallback; 67 68 @Before setUp()69 public void setUp() { 70 mInstallPackageBlockingCallback = new InstallPackageBlockingCallback(); 71 } 72 73 @EnsureHasPermission(WRITE_EXTERNAL_STORAGE) 74 @Test run_success()75 public void run_success() throws IOException, InterruptedException { 76 File appToInstallFile = getAppToInstallFile(); 77 TestApp testApp = writeApkToInstall(appToInstallFile); 78 InstallPackageTask task = new InstallPackageTask( 79 () -> appToInstallFile, 80 sContext, 81 createProvisioningParams(testApp.packageName()), 82 mInstallPackageBlockingCallback); 83 int resultCode; 84 85 try { 86 sInstrumentation.runOnMainSync(() -> task.run(USER_ID)); 87 resultCode = mInstallPackageBlockingCallback.await(); 88 } finally { 89 // TODO(b/191277673): Use TestApp#uninstall(UserHandle) when available to use. 90 } 91 92 assertThat(resultCode).isEqualTo(RESULT_SUCCESS); 93 assertFileDeleted(appToInstallFile); 94 } 95 96 @Test run_fileIsNull_success()97 public void run_fileIsNull_success() throws InterruptedException { 98 InstallPackageTask task = new InstallPackageTask( 99 FILE_NULL_PATH_PROVIDER, 100 sContext, 101 createProvisioningParams(TEST_PACKAGE_NAME), 102 mInstallPackageBlockingCallback); 103 104 task.run(USER_ID); 105 int resultCode = mInstallPackageBlockingCallback.await(); 106 107 assertThat(resultCode).isEqualTo(RESULT_SUCCESS); 108 } 109 110 @Test run_fileDoesNotExist_fail()111 public void run_fileDoesNotExist_fail() throws InterruptedException { 112 InstallPackageTask task = new InstallPackageTask( 113 FILE_INVALID_PATH_PROVIDER, 114 sContext, 115 createProvisioningParams(TEST_PACKAGE_NAME), 116 mInstallPackageBlockingCallback); 117 118 sInstrumentation.runOnMainSync(() -> task.run(USER_ID)); 119 int resultCode = mInstallPackageBlockingCallback.await(); 120 121 assertThat(resultCode).isEqualTo(ERROR_INSTALLATION_FAILED); 122 } 123 124 @Ignore("b/191285670") 125 @EnsureHasPermission(WRITE_EXTERNAL_STORAGE) 126 @Test run_packageAlreadyInstalled_success()127 public void run_packageAlreadyInstalled_success() throws IOException, InterruptedException { 128 File appToInstallFile = getAppToInstallFile(); 129 TestApp testApp = writeApkToInstall(appToInstallFile); 130 testApp.install(USER_HANDLE); 131 InstallPackageTask task = new InstallPackageTask( 132 () -> appToInstallFile, 133 sContext, 134 createProvisioningParams(testApp.packageName()), 135 mInstallPackageBlockingCallback); 136 int resultCode; 137 138 try { 139 sInstrumentation.runOnMainSync(() -> task.run(USER_ID)); 140 resultCode = mInstallPackageBlockingCallback.await(); 141 } finally { 142 // TODO(b/191277673): Use TestApp#uninstall(UserHandle) when available to use. 143 } 144 145 assertThat(resultCode).isEqualTo(RESULT_SUCCESS); 146 assertFileDeleted(appToInstallFile); 147 } 148 149 @EnsureHasPermission(WRITE_EXTERNAL_STORAGE) 150 @Test run_invalidApkFile_error()151 public void run_invalidApkFile_error() throws IOException, InterruptedException { 152 File appToInstallFile = getAppToInstallFile(); 153 writeInvalidFile(appToInstallFile); 154 InstallPackageTask task = new InstallPackageTask( 155 () -> appToInstallFile, 156 sContext, 157 createProvisioningParams(TEST_PACKAGE_NAME), 158 mInstallPackageBlockingCallback); 159 int resultCode; 160 161 sInstrumentation.runOnMainSync(() -> task.run(USER_ID)); 162 resultCode = mInstallPackageBlockingCallback.await(); 163 164 assertThat(resultCode).isEqualTo(ERROR_INSTALLATION_FAILED); 165 assertFileDeleted(appToInstallFile); 166 } 167 assertFileDeleted(File appToInstallFile)168 private void assertFileDeleted(File appToInstallFile) { 169 if (appToInstallFile.exists()) { 170 appToInstallFile.delete(); 171 fail("File " + appToInstallFile.getAbsolutePath() + " was not deleted."); 172 } 173 } 174 writeInvalidFile(File appToInstallFile)175 private void writeInvalidFile(File appToInstallFile) throws IOException { 176 try (PrintWriter writer = new PrintWriter(appToInstallFile)) { 177 writer.println(INVALID_FILE_CONTENTS); 178 } 179 } 180 createProvisioningParams(String packageName)181 private static ProvisioningParams createProvisioningParams(String packageName) { 182 return new ProvisioningParams.Builder() 183 .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE) 184 .setDeviceAdminPackageName(packageName) 185 .build(); 186 } 187 writeApkToInstall(File appToInstallFile)188 private static TestApp writeApkToInstall(File appToInstallFile) throws IOException { 189 TestAppProvider testAppProvider = new TestAppProvider(); 190 TestApp testApp = testAppProvider 191 .query() 192 // TODO(b/192330233): We use this specific app as it does not have the testOnly flag 193 .wherePackageName().isEqualTo(TEST_APP) 194 .get(); 195 testApp.writeApkFile(appToInstallFile); 196 return testApp; 197 } 198 getAppToInstallFile()199 private static File getAppToInstallFile() throws IOException { 200 return File.createTempFile( 201 /* prefix= */ "test_app" + Math.random() * Integer.MAX_VALUE, 202 ".apk", 203 sContext.getCacheDir()); 204 } 205 206 private static class InstallPackageBlockingCallback extends BlockingCallback<Integer> 207 implements AbstractProvisioningTask.Callback { 208 @Override onSuccess(AbstractProvisioningTask task)209 public void onSuccess(AbstractProvisioningTask task) { 210 callbackTriggered(RESULT_SUCCESS); 211 } 212 213 @Override onError(AbstractProvisioningTask task, int errorCode)214 public void onError(AbstractProvisioningTask task, int errorCode) { 215 callbackTriggered(errorCode); 216 } 217 } 218 } 219