• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.framework.tests;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 
23 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
24 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
25 import com.android.tradefed.device.DeviceNotAvailableException;
26 import com.android.tradefed.device.IFileEntry;
27 import com.android.tradefed.device.ITestDevice;
28 import com.android.tradefed.log.LogUtil.CLog;
29 import com.android.tradefed.result.CollectingTestListener;
30 
31 import java.io.File;
32 import java.util.Map;
33 import java.util.Map.Entry;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36 
37 /** Set of tests that verify host side install cases */
38 public class PackageManagerHostTestUtils {
39     private ITestDevice mDevice = null;
40     private boolean mEmulatedExternalStorage = false;
41 
42     // TODO: get this value from Android Environment instead of hard coding
43     public static final String JB_APP_PRIVATE_PATH = "/mnt/asec/";
44     public static final String DEVICE_APP_PATH = "/data/app/";
45     public static final String SDCARD_APP_PATH = "/mnt/asec/";
46 
47     private static String mAppPrivatePath = JB_APP_PRIVATE_PATH;
48 
49     private static final int MAX_WAIT_FOR_DEVICE_TIME = 120 * 1000;
50 
51     // Install preference on the device-side
52     public static enum InstallLocPreference {
53         AUTO,
54         INTERNAL,
55         EXTERNAL
56     }
57 
58     // Actual install location
59     public static enum InstallLocation {
60         DEVICE,
61         SDCARD
62     }
63 
64     /**
65      * Constructor.
66      *
67      * @param device the {@link ITestDevice} to use when performing operations.
68      * @throws DeviceNotAvailableException
69      */
PackageManagerHostTestUtils(ITestDevice device)70     public PackageManagerHostTestUtils(ITestDevice device) throws DeviceNotAvailableException {
71         mDevice = device;
72         determineExternalStorageEmulation();
73     }
74 
75     /**
76      * Returns the path on the device of forward-locked apps.
77      *
78      * @return path of forward-locked apps on the device
79      */
getAppPrivatePath()80     public static String getAppPrivatePath() {
81         return mAppPrivatePath;
82     }
83 
setAppPrivatePath(String path)84     public static void setAppPrivatePath(String path) {
85         mAppPrivatePath = path;
86     }
87 
88     /**
89      * Returns the path on the device of normal apps.
90      *
91      * @return path of forward-locked apps on the device
92      */
getDeviceAppPath()93     public static String getDeviceAppPath() {
94         return DEVICE_APP_PATH;
95     }
96 
97     /**
98      * Returns the path of apps installed on the SD card.
99      *
100      * @return path of forward-locked apps on the device
101      */
getSDCardAppPath()102     public static String getSDCardAppPath() {
103         return SDCARD_APP_PATH;
104     }
105 
106     /**
107      * Helper method to run tests and return the listener that collected the results. For the
108      * optional params, pass null to use the default values.
109      *
110      * @param pkgName Android application package for tests
111      * @param className (optional) The class containing the method to test
112      * @param methodName (optional) The method in the class of which to test
113      * @param runnerName (optional) The name of the TestRunner of the test on the device to be run
114      * @param params (optional) Any additional parameters to pass into the Test Runner
115      * @return the {@link CollectingTestListener}
116      * @throws DeviceNotAvailableException
117      */
doRunTests( String pkgName, String className, String methodName, String runnerName, Map<String, String> params)118     private CollectingTestListener doRunTests(
119             String pkgName,
120             String className,
121             String methodName,
122             String runnerName,
123             Map<String, String> params)
124             throws DeviceNotAvailableException {
125         IRemoteAndroidTestRunner testRunner =
126                 new RemoteAndroidTestRunner(pkgName, runnerName, mDevice.getIDevice());
127 
128         if (className != null && methodName != null) {
129             testRunner.setMethodName(className, methodName);
130         }
131 
132         // Add in any additional args to pass into the test
133         if (params != null) {
134             for (Entry<String, String> argPair : params.entrySet()) {
135                 testRunner.addInstrumentationArg(argPair.getKey(), argPair.getValue());
136             }
137         }
138 
139         CollectingTestListener listener = new CollectingTestListener();
140         mDevice.runInstrumentationTests(testRunner, listener);
141         return listener;
142     }
143 
144     /**
145      * Runs the specified packages tests, and returns whether all tests passed or not.
146      *
147      * @param pkgName Android application package for tests
148      * @param className The class containing the method to test
149      * @param methodName The method in the class of which to test
150      * @param runnerName The name of the TestRunner of the test on the device to be run
151      * @param params Any additional parameters to pass into the Test Runner
152      * @return true if test passed, false otherwise.
153      * @throws DeviceNotAvailableException
154      */
runDeviceTestsDidAllTestsPass( String pkgName, String className, String methodName, String runnerName, Map<String, String> params)155     public boolean runDeviceTestsDidAllTestsPass(
156             String pkgName,
157             String className,
158             String methodName,
159             String runnerName,
160             Map<String, String> params)
161             throws DeviceNotAvailableException {
162         CollectingTestListener listener =
163                 doRunTests(pkgName, className, methodName, runnerName, params);
164         return !listener.hasFailedTests();
165     }
166 
167     /**
168      * Runs the specified packages tests, and returns whether all tests passed or not.
169      *
170      * @param pkgName Android application package for tests
171      * @return true if every test passed, false otherwise.
172      * @throws DeviceNotAvailableException
173      */
runDeviceTestsDidAllTestsPass(String pkgName)174     public boolean runDeviceTestsDidAllTestsPass(String pkgName)
175             throws DeviceNotAvailableException {
176         CollectingTestListener listener = doRunTests(pkgName, null, null, null, null);
177         return !listener.hasFailedTests();
178     }
179 
180     /**
181      * Helper method to install a file
182      *
183      * @param localFile the {@link File} to install
184      * @param replace set to <code>true</code> if re-install of app should be performed
185      * @throws DeviceNotAvailableException
186      */
installFile(final File localFile, final boolean replace)187     public void installFile(final File localFile, final boolean replace)
188             throws DeviceNotAvailableException {
189         String result = mDevice.installPackage(localFile, replace);
190         assertEquals(null, result);
191     }
192 
193     /**
194      * Helper method to install a file to device as forward locked.
195      *
196      * @param apkFile the {@link File} to install
197      * @param replace set to <code>true</code> if re-install of app should be performed
198      * @throws DeviceNotAvailableException if communication with device is lost
199      */
installFileForwardLocked(final File apkFile, final boolean replace)200     public String installFileForwardLocked(final File apkFile, final boolean replace)
201             throws DeviceNotAvailableException {
202         return mDevice.installPackage(apkFile, replace, "-l");
203     }
204 
205     /**
206      * Helper method to determine if file exists on the device containing a given string.
207      *
208      * @param destPath the absolute path of the file
209      * @return <code>true</code> if file exists containing given string, <code>false</code>
210      *     otherwise.
211      * @throws DeviceNotAvailableException
212      */
doesRemoteFileExistContainingString(String destPath, String searchString)213     public boolean doesRemoteFileExistContainingString(String destPath, String searchString)
214             throws DeviceNotAvailableException {
215         String lsResult = mDevice.executeShellCommand(String.format("ls %s", destPath));
216         return lsResult.contains(searchString);
217     }
218 
219     /**
220      * Helper method to determine if package on device exists.
221      *
222      * @param packageName the Android manifest package to check.
223      * @return <code>true</code> if package exists, <code>false</code> otherwise
224      * @throws DeviceNotAvailableException
225      */
doesPackageExist(String packageName)226     public boolean doesPackageExist(String packageName) throws DeviceNotAvailableException {
227         String pkgGrep = mDevice.executeShellCommand(String.format("pm path %s", packageName));
228         return pkgGrep.contains("package:");
229     }
230 
231     /**
232      * Determines if app was installed on device.
233      *
234      * @param packageName package name to check for
235      * @return <code>true</code> if file exists, <code>false</code> otherwise.
236      * @throws DeviceNotAvailableException
237      */
doesAppExistOnDevice(String packageName)238     public boolean doesAppExistOnDevice(String packageName) throws DeviceNotAvailableException {
239         return doesRemoteFileExistContainingString(DEVICE_APP_PATH, packageName);
240     }
241 
242     /**
243      * Determines if app was installed on SD card.
244      *
245      * @param packageName package name to check for
246      * @return <code>true</code> if file exists, <code>false</code> otherwise.
247      * @throws DeviceNotAvailableException
248      */
doesAppExistOnSDCard(String packageName)249     public boolean doesAppExistOnSDCard(String packageName) throws DeviceNotAvailableException {
250 
251         // if we're using emulated storage, the SDcard path is actually the
252         // device's normal app path
253         if (getIsExternalStorageEmulated()) {
254             return doesRemoteFileExistContainingString(DEVICE_APP_PATH, packageName);
255         } else {
256             return doesRemoteFileExistContainingString(SDCARD_APP_PATH, packageName);
257         }
258     }
259 
260     /**
261      * Helper method to determine if app was installed as forward locked.
262      *
263      * @param packageName package name to check for
264      * @return <code>true</code> if file exists, <code>false</code> otherwise.
265      * @throws DeviceNotAvailableException
266      */
doesAppExistAsForwardLocked(String packageName)267     public boolean doesAppExistAsForwardLocked(String packageName)
268             throws DeviceNotAvailableException {
269         return doesRemoteFileExistContainingString(mAppPrivatePath, packageName);
270     }
271 
272     /**
273      * Waits for device's package manager to respond.
274      *
275      * @throws DeviceNotAvailableException
276      */
waitForPackageManager()277     public void waitForPackageManager() throws DeviceNotAvailableException {
278         CLog.i("waiting for device");
279         mDevice.waitForDeviceAvailable(MAX_WAIT_FOR_DEVICE_TIME);
280     }
281 
282     /**
283      * Helper method for installing an app to wherever is specified in its manifest, and then
284      * verifying the app was installed onto SD Card.
285      *
286      * <p>Assumes adb is running as root in device under test.
287      *
288      * @param apkPath the path of the apk to install
289      * @param pkgName the name of the package
290      * @param overwrite <code>true</code> if the app should be overwritten, <code>false</code>
291      *     otherwise
292      * @throws DeviceNotAvailableException
293      */
installAppAndVerifyExistsOnSDCard(File apkPath, String pkgName, boolean overwrite)294     public void installAppAndVerifyExistsOnSDCard(File apkPath, String pkgName, boolean overwrite)
295             throws DeviceNotAvailableException {
296         // Start with a clean slate if we're not overwriting
297         if (!overwrite) {
298             // cleanup test app just in case it already exists
299             mDevice.uninstallPackage(pkgName);
300             // grep for package to make sure its not installed
301             assertFalse(doesPackageExist(pkgName));
302         }
303 
304         installFile(apkPath, overwrite);
305         assertTrue(doesAppExistOnSDCard(pkgName));
306         // TODO: is this necessary?
307         waitForPackageManager();
308 
309         // grep for package to make sure it is installed
310         assertTrue(doesPackageExist(pkgName));
311     }
312 
313     /**
314      * Helper method for installing an app to wherever is specified in its manifest, and then
315      * verifying the app was installed onto device.
316      *
317      * <p>Assumes adb is running as root in device under test.
318      *
319      * @param apkFile the {@link File} of the apk to install
320      * @param pkgName the name of the package
321      * @param overwrite <code>true</code> if the app should be overwritten, <code>false</code>
322      *     otherwise
323      * @throws DeviceNotAvailableException
324      */
installAppAndVerifyExistsOnDevice(File apkFile, String pkgName, boolean overwrite)325     public void installAppAndVerifyExistsOnDevice(File apkFile, String pkgName, boolean overwrite)
326             throws DeviceNotAvailableException {
327         // Start with a clean slate if we're not overwriting
328         if (!overwrite) {
329             // cleanup test app just in case it already exists
330             mDevice.uninstallPackage(pkgName);
331             // grep for package to make sure its not installed
332             assertFalse(doesPackageExist(pkgName));
333         }
334 
335         installFile(apkFile, overwrite);
336         assertTrue(doesAppExistOnDevice(pkgName));
337         // TODO: is this necessary?
338         waitForPackageManager();
339 
340         // grep for package to make sure it is installed
341         assertTrue(doesPackageExist(pkgName));
342     }
343 
344     /**
345      * Helper method for installing an app as forward-locked, and then verifying the app was
346      * installed in the proper forward-locked location.
347      *
348      * <p>Assumes adb is running as root in device under test.
349      *
350      * @param apkFile the {@link File} of the apk to install
351      * @param pkgName the name of the package
352      * @param overwrite <code>true</code> if the app should be overwritten, <code>false</code>
353      *     otherwise
354      * @throws Exception if failed to install app
355      */
installFwdLockedAppAndVerifyExists(File apkFile, String pkgName, boolean overwrite)356     public void installFwdLockedAppAndVerifyExists(File apkFile, String pkgName, boolean overwrite)
357             throws Exception {
358         // Start with a clean slate if we're not overwriting
359         if (!overwrite) {
360             // cleanup test app just in case it already exists
361             mDevice.uninstallPackage(pkgName);
362             // grep for package to make sure its not installed
363             assertFalse(doesPackageExist(pkgName));
364         }
365 
366         String result = installFileForwardLocked(apkFile, overwrite);
367         assertEquals(null, result);
368         assertTrue(doesAppExistAsForwardLocked(pkgName));
369         waitForPackageManager();
370 
371         // grep for package to make sure it is installed
372         assertTrue(doesPackageExist(pkgName));
373     }
374 
375     /**
376      * Helper method for uninstalling an app.
377      *
378      * <p>Assumes adb is running as root in device under test.
379      *
380      * @param pkgName package name to uninstall
381      * @throws DeviceNotAvailableException
382      */
uninstallApp(String pkgName)383     public void uninstallApp(String pkgName) throws DeviceNotAvailableException {
384         mDevice.uninstallPackage(pkgName);
385         waitForPackageManager();
386         // make sure its not installed anymore
387         assertFalse(doesPackageExist(pkgName));
388     }
389 
390     /**
391      * Sets the device's install location preference.
392      *
393      * <p>Assumes adb is running as root in device under test.
394      *
395      * @throws DeviceNotAvailableException
396      */
setDevicePreferredInstallLocation(InstallLocPreference pref)397     public void setDevicePreferredInstallLocation(InstallLocPreference pref)
398             throws DeviceNotAvailableException {
399         String command = "pm set-install-location %d";
400         int locValue = 0;
401         switch (pref) {
402             case INTERNAL:
403                 locValue = 1;
404                 break;
405             case EXTERNAL:
406                 locValue = 2;
407                 break;
408             default: // AUTO
409                 locValue = 0;
410                 break;
411         }
412         mDevice.executeShellCommand(String.format(command, locValue));
413     }
414 
415     /**
416      * Gets the device's install location preference.
417      *
418      * <p>Assumes adb is running as root in device under test.
419      *
420      * @throws DeviceNotAvailableException
421      */
getDevicePreferredInstallLocation()422     public InstallLocPreference getDevicePreferredInstallLocation()
423             throws DeviceNotAvailableException {
424         String result = mDevice.executeShellCommand("pm get-install-location");
425         if (result.indexOf('0') != -1) {
426             return InstallLocPreference.AUTO;
427         } else if (result.indexOf('1') != -1) {
428             return InstallLocPreference.INTERNAL;
429         } else {
430             return InstallLocPreference.EXTERNAL;
431         }
432     }
433 
434     /**
435      * Determines whether the device is using emulated external storage.
436      *
437      * <p>Sets mEmulatedExternalStorage based on the result Assumes adb is running as root in device
438      * under test.
439      *
440      * @throws DeviceNotAvailableException
441      */
determineExternalStorageEmulation()442     private void determineExternalStorageEmulation() throws DeviceNotAvailableException {
443         String result = mDevice.executeShellCommand("sm get-primary-storage-uuid");
444         if (result.trim().equalsIgnoreCase("null")) {
445             CLog.i("Device is using emulated external storage.");
446             mEmulatedExternalStorage = true;
447         } else if (result.equals("primary_physical")) {
448             CLog.i("Device is using actual external storage.");
449             mEmulatedExternalStorage = false;
450         } else {
451             // older devices will not have mEmulated flag in the output
452             CLog.i("Unable to precisely determine external storage emulation; assuming false.");
453             mEmulatedExternalStorage = false;
454         }
455     }
456 
457     /**
458      * Determine the location of the app private path.
459      *
460      * @param apkFile the {@link File} of test apk to determine packages' install path.
461      * @param pkgName the {@link String} pkgName of the test apk.
462      * @throws DeviceNotAvailableException
463      */
determinePrivateAppPath(File apkFile, String pkgName)464     public void determinePrivateAppPath(File apkFile, String pkgName)
465             throws DeviceNotAvailableException {
466         setAppPrivatePath(JB_APP_PRIVATE_PATH);
467     }
468 
469     /**
470      * Returns whether the external storage is emulated or not.
471      *
472      * @return <code>true</code> if external storage is emulated, <code>false</code> otherwise.
473      */
getIsExternalStorageEmulated()474     public boolean getIsExternalStorageEmulated() {
475         return mEmulatedExternalStorage;
476     }
477 
478     /**
479      * Connect device to wifi.
480      *
481      * @param device
482      * @param wifiNetwork
483      * @param wifiPsk
484      * @param connectionAttempts
485      * @return true if able to connect to wifi.
486      * @throws DeviceNotAvailableException
487      */
connectToWifi( ITestDevice device, String wifiNetwork, String wifiPsk, int connectionAttempts)488     public static boolean connectToWifi(
489             ITestDevice device, String wifiNetwork, String wifiPsk, int connectionAttempts)
490             throws DeviceNotAvailableException {
491         if (wifiNetwork != null) {
492             for (int i = 0; i < connectionAttempts; i++) {
493                 device.disconnectFromWifi();
494                 if (device.connectToWifiNetwork(wifiNetwork, wifiPsk)) {
495                     CLog.i("Connected to wifi network %s", wifiNetwork);
496                     return true;
497                 }
498             }
499         }
500         return false;
501     }
502 
503     /**
504      * Ensure that the file's permissions matches expectation.
505      *
506      * @param remoteFilePath {@link String} the remote path for the file to check.
507      * @param expectedPerms {@link String} expected permissions.
508      * @return true if the permissions for a given file matches, false otherwise.
509      * @throws DeviceNotAvailableException
510      */
checkFilePermissions(String remoteFilePath, String expectedPerms)511     public boolean checkFilePermissions(String remoteFilePath, String expectedPerms)
512             throws DeviceNotAvailableException {
513         IFileEntry file = mDevice.getFileEntry(remoteFilePath);
514         return file.getPermissions().equals(expectedPerms);
515     }
516 
517     /**
518      * Ensure that the file's owner matches expectation.
519      *
520      * @param remoteFilePath {@link String} the remote path for the file to check.
521      * @param expectedOwner {@link String} the expected owner.
522      * @return true if the owner for a given file matches, false otherwise.
523      * @throws DeviceNotAvailableException
524      */
checkFileOwnerName(String remoteFilePath, String expectedOwner)525     public boolean checkFileOwnerName(String remoteFilePath, String expectedOwner)
526             throws DeviceNotAvailableException {
527         // TODO: uncomment this, when we have support from ddmlib.
528         // IFileEntry file = mDevice.getFileEntry(remoteFilePath);
529         // return file.getOwner().equals(expectedOwner)
530         return true;
531     }
532 
533     /**
534      * Ensure that the file's group matches expectation
535      *
536      * @param remoteFilePath {@link String} the remote path for the file to check.
537      * @param expectedGroup {@link String} the expected group.
538      * @return true if the group for a given file matches, false otherwise.
539      * @throws DeviceNotAvailableException
540      */
checkFileGroupName(String remoteFilePath, String expectedGroup)541     public boolean checkFileGroupName(String remoteFilePath, String expectedGroup)
542             throws DeviceNotAvailableException {
543         // TODO: uncomment this, when we have support from ddmlib.
544         // IFileEntry file = mDevice.getFileEntry(remoteFilePath);
545         // return file.getGroup().equals(expectedOwner)
546         return true;
547     }
548 
549     /**
550      * Returns the uid of the installed package.
551      *
552      * @param pkgName package name of the test apk.
553      * @return uid of the installed package
554      * @throws DeviceNotAvailableException
555      */
getUid(String pkgName)556     public Integer getUid(String pkgName) throws DeviceNotAvailableException {
557         String out = mDevice.executeShellCommand(String.format("dumpsys package %s", pkgName));
558         Matcher m = Pattern.compile("userId=(\\d+)").matcher(out);
559         assertTrue(m.find());
560 
561         Integer uid = Integer.parseInt(m.group(1));
562         CLog.v("package %s has uid %d", pkgName, uid);
563         return uid;
564     }
565 
getAbi(String pkgName)566     public String getAbi(String pkgName) throws DeviceNotAvailableException {
567         String out = mDevice.executeShellCommand(String.format("dumpsys package %s", pkgName));
568         Matcher m = Pattern.compile("primaryCpuAbi=(.+)").matcher(out);
569         assertTrue(m.find());
570 
571         String abi = m.group(1);
572         CLog.i("package %s has abi %s", pkgName, abi);
573         return abi;
574     }
575 }
576