1 /*
2  * Copyright (C) 2015 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.packageinstaller.admin.cts;
17 
18 import android.app.PendingIntent;
19 import android.app.admin.DevicePolicyManager;
20 import android.content.BroadcastReceiver;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.IntentSender;
26 import android.content.pm.PackageInfo;
27 import android.content.pm.PackageInstaller;
28 import android.content.pm.PackageManager;
29 import android.os.ParcelFileDescriptor;
30 import android.os.Process;
31 import android.support.test.uiautomator.UiDevice;
32 import android.test.InstrumentationTestCase;
33 
34 import java.io.BufferedReader;
35 import java.io.File;
36 import java.io.FileInputStream;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.io.OutputStream;
40 import java.util.ArrayList;
41 
42 /**
43  * Base test case for testing PackageInstaller.
44  */
45 public class BasePackageInstallTest extends InstrumentationTestCase {
46     protected static final String TEST_APP_LOCATION =
47             "/data/local/tmp/cts/packageinstaller/CtsEmptyTestApp.apk";
48     protected static final String TEST_APP_PKG = "android.packageinstaller.emptytestapp.cts";
49     protected static final int PACKAGE_INSTALLER_TIMEOUT_MS = 60000; // 60 seconds
50     private static final String ACTION_INSTALL_COMMIT =
51             "com.android.cts.deviceowner.INTENT_PACKAGE_INSTALL_COMMIT";
52     protected static final int PACKAGE_INSTALLER_STATUS_UNDEFINED = -1000;
53     public static final String PACKAGE_NAME = SilentPackageInstallTest.class.getPackage().getName();
54 
55     protected Context mContext;
56     protected UiDevice mDevice;
57     protected DevicePolicyManager mDevicePolicyManager;
58     protected PackageManager mPackageManager;
59     private PackageInstaller mPackageInstaller;
60     private PackageInstaller.Session mSession;
61     protected boolean mCallbackReceived;
62     protected int mCallbackStatus;
63     protected Intent mCallbackIntent;
64 
65     protected boolean mHasFeature;
66 
67     protected final Object mPackageInstallerTimeoutLock = new Object();
68 
69     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
70         @Override
71         public void onReceive(Context context, Intent intent) {
72             synchronized (mPackageInstallerTimeoutLock) {
73                 mCallbackStatus = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
74                         PACKAGE_INSTALLER_STATUS_UNDEFINED);
75                 if (mCallbackStatus == PackageInstaller.STATUS_SUCCESS) {
76                     mContext.unregisterReceiver(this);
77                     assertEquals(TEST_APP_PKG, intent.getStringExtra(
78                             PackageInstaller.EXTRA_PACKAGE_NAME));
79                 } else if (mCallbackStatus == PackageInstaller.STATUS_PENDING_USER_ACTION) {
80                     mCallbackIntent = (Intent) intent.getExtras().get(Intent.EXTRA_INTENT);
81                 }
82                 mCallbackReceived = true;
83                 mPackageInstallerTimeoutLock.notify();
84             }
85         }
86     };
87 
88     @Override
setUp()89     protected void setUp() throws Exception {
90         super.setUp();
91         mContext = getInstrumentation().getContext();
92         mDevice = UiDevice.getInstance(getInstrumentation());
93         mDevicePolicyManager = (DevicePolicyManager)
94                 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
95         mPackageManager = mContext.getPackageManager();
96         mPackageInstaller = mPackageManager.getPackageInstaller();
97         assertNotNull(mPackageInstaller);
98 
99         mHasFeature = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
100 
101         if (mHasFeature) {
102             forceUninstall();
103             // check that app is not already installed
104             assertFalse(isPackageInstalled(TEST_APP_PKG));
105         }
106     }
107 
108     @Override
tearDown()109     protected void tearDown() throws Exception {
110         if (mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME) ||
111                 mDevicePolicyManager.isProfileOwnerApp(PACKAGE_NAME)) {
112             mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
113         }
114         try {
115             mContext.unregisterReceiver(mBroadcastReceiver);
116         } catch (IllegalArgumentException e) {
117             // ignore
118         }
119         if (mSession != null) {
120             mSession.abandon();
121         }
122 
123         super.tearDown();
124     }
125 
getWho()126     protected static ComponentName getWho() {
127         return new ComponentName(PACKAGE_NAME, BasicAdminReceiver.class.getName());
128     }
129 
assertInstallPackage()130     protected void assertInstallPackage() throws Exception {
131         assertFalse(isPackageInstalled(TEST_APP_PKG));
132         synchronized (mPackageInstallerTimeoutLock) {
133             mCallbackReceived = false;
134             mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
135         }
136         installPackage(TEST_APP_LOCATION);
137         synchronized (mPackageInstallerTimeoutLock) {
138             try {
139                 mPackageInstallerTimeoutLock.wait(PACKAGE_INSTALLER_TIMEOUT_MS);
140             } catch (InterruptedException e) {
141             }
142             assertTrue(mCallbackReceived);
143             assertEquals(PackageInstaller.STATUS_SUCCESS, mCallbackStatus);
144         }
145         assertTrue(isPackageInstalled(TEST_APP_PKG));
146     }
147 
tryUninstallPackage()148     protected boolean tryUninstallPackage() throws Exception {
149         assertTrue(isPackageInstalled(TEST_APP_PKG));
150         synchronized (mPackageInstallerTimeoutLock) {
151             mCallbackReceived = false;
152             mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
153         }
154         mPackageInstaller.uninstall(TEST_APP_PKG, getCommitCallback(0));
155         synchronized (mPackageInstallerTimeoutLock) {
156             try {
157                 mPackageInstallerTimeoutLock.wait(PACKAGE_INSTALLER_TIMEOUT_MS);
158             } catch (InterruptedException e) {
159             }
160             assertTrue(mCallbackReceived);
161             return mCallbackStatus == PackageInstaller.STATUS_SUCCESS;
162         }
163     }
164 
installPackage(String packageLocation)165     protected void installPackage(String packageLocation) throws Exception {
166         PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
167                 PackageInstaller.SessionParams.MODE_FULL_INSTALL);
168         params.setAppPackageName(TEST_APP_PKG);
169         int sessionId = mPackageInstaller.createSession(params);
170         mSession = mPackageInstaller.openSession(sessionId);
171 
172         File file = new File(packageLocation);
173         InputStream in = new FileInputStream(file);
174         OutputStream out = mSession.openWrite("SilentPackageInstallerTest", 0, file.length());
175         byte[] buffer = new byte[65536];
176         int c;
177         while ((c = in.read(buffer)) != -1) {
178             out.write(buffer, 0, c);
179         }
180         mSession.fsync(out);
181         out.close();
182         mSession.commit(getCommitCallback(sessionId));
183         mSession.close();
184     }
185 
getCommitCallback(int sessionId)186     private IntentSender getCommitCallback(int sessionId) {
187         // Create an intent-filter and register the receiver
188         String action = ACTION_INSTALL_COMMIT + "." + sessionId;
189         IntentFilter intentFilter = new IntentFilter();
190         intentFilter.addAction(action);
191         mContext.registerReceiver(mBroadcastReceiver, intentFilter);
192 
193         // Create a PendingIntent and use it to generate the IntentSender
194         Intent broadcastIntent = new Intent(action);
195         PendingIntent pendingIntent = PendingIntent.getBroadcast(
196                 mContext,
197                 sessionId,
198                 broadcastIntent,
199                 PendingIntent.FLAG_UPDATE_CURRENT);
200         return pendingIntent.getIntentSender();
201     }
202 
isPackageInstalled(String packageName)203     protected boolean isPackageInstalled(String packageName) {
204         try {
205             PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
206             return pi != null;
207         } catch (PackageManager.NameNotFoundException e) {
208             return false;
209         }
210     }
211 
getInstallReason(String packageName)212     protected int getInstallReason(String packageName) {
213         return mPackageManager.getInstallReason(packageName, Process.myUserHandle());
214     }
215 
forceUninstall()216     protected void forceUninstall() throws Exception {
217         runShellCommand("pm uninstall " + TEST_APP_PKG);
218     }
219 
runShellCommand(String command)220     public ArrayList<String> runShellCommand(String command) throws Exception {
221         ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
222                 .executeShellCommand(command);
223 
224         ArrayList<String> ret = new ArrayList<>();
225         // Read the input stream fully.
226         try (BufferedReader r = new BufferedReader(
227                 new InputStreamReader(new ParcelFileDescriptor.AutoCloseInputStream(pfd)))) {
228             String line;
229             while ((line = r.readLine()) != null) {
230                 ret.add(line);
231             }
232         }
233         return ret;
234     }
235 }
236