• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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