Home | History | Annotate | Download | only in pm
      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 android.content.pm;
     18 
     19 import com.android.ddmlib.AndroidDebugBridge;
     20 import com.android.ddmlib.IDevice;
     21 import com.android.ddmlib.IShellOutputReceiver;
     22 import com.android.ddmlib.Log;
     23 import com.android.ddmlib.MultiLineReceiver;
     24 import com.android.ddmlib.SyncService;
     25 import com.android.ddmlib.SyncService.ISyncProgressMonitor;
     26 import com.android.ddmlib.SyncService.SyncResult;
     27 import com.android.ddmlib.testrunner.ITestRunListener;
     28 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
     29 import com.android.ddmlib.testrunner.TestIdentifier;
     30 import com.android.hosttest.DeviceTestCase;
     31 import com.android.hosttest.DeviceTestSuite;
     32 
     33 import java.io.BufferedReader;
     34 import java.io.File;
     35 import java.io.InputStreamReader;
     36 import java.io.IOException;
     37 import java.io.StringReader;
     38 import java.lang.Runtime;
     39 import java.lang.Process;
     40 import java.util.Hashtable;
     41 import java.util.Map;
     42 import java.util.Map.Entry;
     43 import java.util.regex.Matcher;
     44 import java.util.regex.Pattern;
     45 
     46 import junit.framework.Assert;
     47 import com.android.hosttest.DeviceTestCase;
     48 
     49 /**
     50  * Set of tests that verify host side install cases
     51  */
     52 public class PackageManagerHostTestUtils extends Assert {
     53 
     54     private static final String LOG_TAG = "PackageManagerHostTests";
     55     private IDevice mDevice = null;
     56 
     57     // TODO: get this value from Android Environment instead of hardcoding
     58     private static final String APP_PRIVATE_PATH = "/data/app-private/";
     59     private static final String DEVICE_APP_PATH = "/data/app/";
     60     private static final String SDCARD_APP_PATH = "/mnt/secure/asec/";
     61 
     62     private static final int MAX_WAIT_FOR_DEVICE_TIME = 120 * 1000;
     63     private static final int WAIT_FOR_DEVICE_POLL_TIME = 10 * 1000;
     64     private static final int MAX_WAIT_FOR_APP_LAUNCH_TIME = 60 * 1000;
     65     private static final int WAIT_FOR_APP_LAUNCH_POLL_TIME = 5 * 1000;
     66 
     67     // Install preference on the device-side
     68     public static enum InstallLocPreference {
     69         AUTO,
     70         INTERNAL,
     71         EXTERNAL
     72     }
     73 
     74     // Actual install location
     75     public static enum InstallLocation {
     76         DEVICE,
     77         SDCARD
     78     }
     79 
     80     /**
     81      * Constructor takes the device to use
     82      * @param the device to use when performing operations
     83      */
     84     public PackageManagerHostTestUtils(IDevice device)
     85     {
     86           mDevice = device;
     87     }
     88 
     89     /**
     90      * Disable default constructor
     91      */
     92     private PackageManagerHostTestUtils() {}
     93 
     94     /**
     95      * Returns the path on the device of forward-locked apps.
     96      *
     97      * @return path of forward-locked apps on the device
     98      */
     99     public static String getAppPrivatePath() {
    100         return APP_PRIVATE_PATH;
    101     }
    102 
    103     /**
    104      * Returns the path on the device of normal apps.
    105      *
    106      * @return path of forward-locked apps on the device
    107      */
    108     public static String getDeviceAppPath() {
    109         return DEVICE_APP_PATH;
    110     }
    111 
    112     /**
    113      * Returns the path of apps installed on the SD card.
    114      *
    115      * @return path of forward-locked apps on the device
    116      */
    117     public static String getSDCardAppPath() {
    118         return SDCARD_APP_PATH;
    119     }
    120 
    121     /**
    122      * Helper method to run tests and return the listener that collected the results.
    123      *
    124      * For the optional params, pass null to use the default values.
    125 
    126      * @param pkgName Android application package for tests
    127      * @param className (optional) The class containing the method to test
    128      * @param methodName (optional) The method in the class of which to test
    129      * @param runnerName (optional) The name of the TestRunner of the test on the device to be run
    130      * @param params (optional) Any additional parameters to pass into the Test Runner
    131      * @return the {@link CollectingTestRunListener}
    132      */
    133     private CollectingTestRunListener doRunTests(String pkgName, String className, String
    134             methodName, String runnerName, Map<String, String> params) throws IOException {
    135 
    136         RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(pkgName, runnerName,
    137                 mDevice);
    138 
    139         if (className != null && methodName != null) {
    140             testRunner.setMethodName(className, methodName);
    141         }
    142 
    143         // Add in any additional args to pass into the test
    144         if (params != null) {
    145             for (Entry<String, String> argPair : params.entrySet()) {
    146                 testRunner.addInstrumentationArg(argPair.getKey(), argPair.getValue());
    147             }
    148         }
    149 
    150         CollectingTestRunListener listener = new CollectingTestRunListener();
    151         testRunner.run(listener);
    152         return listener;
    153     }
    154 
    155     /**
    156      * Runs the specified packages tests, and returns whether all tests passed or not.
    157      *
    158      * @param pkgName Android application package for tests
    159      * @param className The class containing the method to test
    160      * @param methodName The method in the class of which to test
    161      * @param runnerName The name of the TestRunner of the test on the device to be run
    162      * @param params Any additional parameters to pass into the Test Runner
    163      * @return true if test passed, false otherwise.
    164      */
    165     public boolean runDeviceTestsDidAllTestsPass(String pkgName, String className,
    166             String methodName, String runnerName, Map<String, String> params) throws IOException {
    167         CollectingTestRunListener listener = doRunTests(pkgName, className, methodName,
    168                 runnerName, params);
    169         return listener.didAllTestsPass();
    170     }
    171 
    172     /**
    173      * Runs the specified packages tests, and returns whether all tests passed or not.
    174      *
    175      * @param pkgName Android application package for tests
    176      * @return true if every test passed, false otherwise.
    177      */
    178     public boolean runDeviceTestsDidAllTestsPass(String pkgName) throws IOException {
    179         CollectingTestRunListener listener = doRunTests(pkgName, null, null, null, null);
    180         return listener.didAllTestsPass();
    181     }
    182 
    183     /**
    184      * Helper method to push a file to device
    185      * @param apkAppPrivatePath
    186      * @throws IOException
    187      */
    188     public void pushFile(final String localFilePath, final String destFilePath)
    189             throws IOException {
    190         SyncResult result = mDevice.getSyncService().pushFile(
    191                 localFilePath, destFilePath, new NullSyncProgressMonitor());
    192         assertEquals(SyncService.RESULT_OK, result.getCode());
    193     }
    194 
    195     /**
    196      * Helper method to install a file
    197      * @param localFilePath the absolute file system path to file on local host to install
    198      * @param reinstall set to <code>true</code> if re-install of app should be performed
    199      * @throws IOException
    200      */
    201     public void installFile(final String localFilePath, final boolean replace) throws IOException {
    202         String result = mDevice.installPackage(localFilePath, replace);
    203         assertEquals(null, result);
    204     }
    205 
    206     /**
    207      * Helper method to install a file that should not be install-able
    208      * @param localFilePath the absolute file system path to file on local host to install
    209      * @param reinstall set to <code>true</code> if re-install of app should be performed
    210      * @return the string output of the failed install attempt
    211      * @throws IOException
    212      */
    213     public String installFileFail(final String localFilePath, final boolean replace)
    214             throws IOException {
    215         String result = mDevice.installPackage(localFilePath, replace);
    216         assertNotNull(result);
    217         return result;
    218     }
    219 
    220     /**
    221      * Helper method to install a file to device as forward locked
    222      * @param localFilePath the absolute file system path to file on local host to install
    223      * @param reinstall set to <code>true</code> if re-install of app should be performed
    224      * @throws IOException
    225      */
    226     public String installFileForwardLocked(final String localFilePath, final boolean replace)
    227             throws IOException {
    228         String remoteFilePath = mDevice.syncPackageToDevice(localFilePath);
    229         InstallReceiver receiver = new InstallReceiver();
    230         String cmd = String.format(replace ? "pm install -r -l \"%1$s\"" :
    231                 "pm install -l \"%1$s\"", remoteFilePath);
    232         mDevice.executeShellCommand(cmd, receiver);
    233         mDevice.removeRemotePackage(remoteFilePath);
    234         return receiver.getErrorMessage();
    235     }
    236 
    237     /**
    238      * Helper method to determine if file on device exists.
    239      *
    240      * @param destPath the absolute path of file on device to check
    241      * @return <code>true</code> if file exists, <code>false</code> otherwise.
    242      * @throws IOException if adb shell command failed
    243      */
    244     public boolean doesRemoteFileExist(String destPath) throws IOException {
    245         String lsGrep = executeShellCommand(String.format("ls %s", destPath));
    246         return !lsGrep.contains("No such file or directory");
    247     }
    248 
    249     /**
    250      * Helper method to determine if file exists on the device containing a given string.
    251      *
    252      * @param destPath the absolute path of the file
    253      * @return <code>true</code> if file exists containing given string,
    254      *         <code>false</code> otherwise.
    255      * @throws IOException if adb shell command failed
    256      */
    257     public boolean doesRemoteFileExistContainingString(String destPath, String searchString)
    258             throws IOException {
    259         String lsResult = executeShellCommand(String.format("ls %s", destPath));
    260         return lsResult.contains(searchString);
    261     }
    262 
    263     /**
    264      * Helper method to determine if package on device exists.
    265      *
    266      * @param packageName the Android manifest package to check.
    267      * @return <code>true</code> if package exists, <code>false</code> otherwise
    268      * @throws IOException if adb shell command failed
    269      */
    270     public boolean doesPackageExist(String packageName) throws IOException {
    271         String pkgGrep = executeShellCommand(String.format("pm path %s", packageName));
    272         return pkgGrep.contains("package:");
    273     }
    274 
    275     /**
    276      * Determines if app was installed on device.
    277      *
    278      * @param packageName package name to check for
    279      * @return <code>true</code> if file exists, <code>false</code> otherwise.
    280      * @throws IOException if adb shell command failed
    281      */
    282     public boolean doesAppExistOnDevice(String packageName) throws IOException {
    283         return doesRemoteFileExistContainingString(DEVICE_APP_PATH, packageName);
    284     }
    285 
    286     /**
    287      * Determines if app was installed on SD card.
    288      *
    289      * @param packageName package name to check for
    290      * @return <code>true</code> if file exists, <code>false</code> otherwise.
    291      * @throws IOException if adb shell command failed
    292      */
    293     public boolean doesAppExistOnSDCard(String packageName) throws IOException {
    294         return doesRemoteFileExistContainingString(SDCARD_APP_PATH, packageName);
    295     }
    296 
    297     /**
    298      * Helper method to determine if app was installed on SD card.
    299      *
    300      * @param packageName package name to check for
    301      * @return <code>true</code> if file exists, <code>false</code> otherwise.
    302      * @throws IOException if adb shell command failed
    303      */
    304     public boolean doesAppExistAsForwardLocked(String packageName) throws IOException {
    305         return doesRemoteFileExistContainingString(APP_PRIVATE_PATH, packageName);
    306     }
    307 
    308     /**
    309      * Waits for device's package manager to respond.
    310      *
    311      * @throws InterruptedException
    312      * @throws IOException
    313      */
    314     public void waitForPackageManager() throws InterruptedException, IOException {
    315         Log.i(LOG_TAG, "waiting for device");
    316         int currentWaitTime = 0;
    317         // poll the package manager until it returns something for android
    318         while (!doesPackageExist("android")) {
    319             Thread.sleep(WAIT_FOR_DEVICE_POLL_TIME);
    320             currentWaitTime += WAIT_FOR_DEVICE_POLL_TIME;
    321             if (currentWaitTime > MAX_WAIT_FOR_DEVICE_TIME) {
    322                 Log.e(LOG_TAG, "time out waiting for device");
    323                 throw new InterruptedException();
    324             }
    325         }
    326     }
    327 
    328     /**
    329      * Helper to determine if the device is currently online and visible via ADB.
    330      *
    331      * @return true iff the device is currently available to ADB and online, false otherwise.
    332      */
    333     private boolean deviceIsOnline() {
    334         AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
    335         IDevice[] devices = bridge.getDevices();
    336 
    337         for (IDevice device : devices) {
    338             // only online if the device appears in the devices list, and its state is online
    339             if ((mDevice != null) &&
    340                     mDevice.getSerialNumber().equals(device.getSerialNumber()) &&
    341                     device.isOnline()) {
    342                 return true;
    343             }
    344         }
    345         return false;
    346     }
    347 
    348     /**
    349      * Waits for device to be online (visible to ADB) before returning, or times out if we've
    350      * waited too long. Note that this only means the device is visible via ADB, not that
    351      * PackageManager is fully up and running yet.
    352      *
    353      * @throws InterruptedException
    354      * @throws IOException
    355      */
    356     public void waitForDeviceToComeOnline() throws InterruptedException, IOException {
    357         Log.i(LOG_TAG, "waiting for device to be online");
    358         int currentWaitTime = 0;
    359 
    360         // poll ADB until we see the device is online
    361         while (!deviceIsOnline()) {
    362             Thread.sleep(WAIT_FOR_DEVICE_POLL_TIME);
    363             currentWaitTime += WAIT_FOR_DEVICE_POLL_TIME;
    364             if (currentWaitTime > MAX_WAIT_FOR_DEVICE_TIME) {
    365                 Log.e(LOG_TAG, "time out waiting for device");
    366                 throw new InterruptedException();
    367             }
    368         }
    369         // Note: if we try to access the device too quickly after it is "officially" online,
    370         // there are sometimes strange issues where it's actually not quite ready yet,
    371         // so we pause for a bit once more before actually returning.
    372         Thread.sleep(WAIT_FOR_DEVICE_POLL_TIME);
    373     }
    374 
    375     /**
    376      * Queries package manager and waits until a package is launched (or times out)
    377      *
    378      * @param packageName The name of the package to wait to load
    379      * @throws InterruptedException
    380      * @throws IOException
    381      */
    382     public void waitForApp(String packageName) throws InterruptedException, IOException {
    383         Log.i(LOG_TAG, "waiting for app to launch");
    384         int currentWaitTime = 0;
    385         // poll the package manager until it returns something for the package we're looking for
    386         while (!doesPackageExist(packageName)) {
    387             Thread.sleep(WAIT_FOR_APP_LAUNCH_POLL_TIME);
    388             currentWaitTime += WAIT_FOR_APP_LAUNCH_POLL_TIME;
    389             if (currentWaitTime > MAX_WAIT_FOR_APP_LAUNCH_TIME) {
    390                 Log.e(LOG_TAG, "time out waiting for app to launch: " + packageName);
    391                 throw new InterruptedException();
    392             }
    393         }
    394     }
    395 
    396     /**
    397      * Helper method which executes a adb shell command and returns output as a {@link String}
    398      * @return the output of the command
    399      * @throws IOException
    400      */
    401     public String executeShellCommand(String command) throws IOException {
    402         Log.i(LOG_TAG, String.format("adb shell %s", command));
    403         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
    404         mDevice.executeShellCommand(command, receiver);
    405         String output = receiver.getOutput();
    406         Log.i(LOG_TAG, String.format("Result: %s", output));
    407         return output;
    408     }
    409 
    410     /**
    411      * Helper method ensures we are in root mode on the host side. It returns only after
    412      * PackageManager is actually up and running.
    413      * @throws IOException
    414      */
    415     public void runAdbRoot() throws IOException, InterruptedException {
    416         Log.i(LOG_TAG, "adb root");
    417         Runtime runtime = Runtime.getRuntime();
    418         Process process = runtime.exec("adb root"); // adb should be in the path
    419         BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
    420 
    421         String nextLine = null;
    422         while (null != (nextLine = output.readLine())) {
    423             Log.i(LOG_TAG, nextLine);
    424         }
    425         process.waitFor();
    426         waitForDeviceToComeOnline();
    427         waitForPackageManager(); // now wait for package manager to actually load
    428     }
    429 
    430     /**
    431      * Helper method which reboots the device and returns once the device is online again
    432      * and package manager is up and running (note this function is synchronous to callers).
    433      * @throws IOException
    434      * @throws InterruptedException
    435      */
    436     public void rebootDevice() throws IOException, InterruptedException {
    437         String command = "reboot"; // no need for -s since mDevice is already tied to a device
    438         Log.i(LOG_TAG, command);
    439         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
    440         mDevice.executeShellCommand(command, receiver);
    441         String output = receiver.getOutput();
    442         Log.i(LOG_TAG, String.format("Result: %s", output));
    443         waitForDeviceToComeOnline(); // wait for device to come online
    444         runAdbRoot();
    445     }
    446 
    447     /**
    448      * A {@link IShellOutputReceiver} which collects the whole shell output into one {@link String}
    449      */
    450     private class CollectingOutputReceiver extends MultiLineReceiver {
    451 
    452         private StringBuffer mOutputBuffer = new StringBuffer();
    453 
    454         public String getOutput() {
    455             return mOutputBuffer.toString();
    456         }
    457 
    458         @Override
    459         public void processNewLines(String[] lines) {
    460             for (String line: lines) {
    461                 mOutputBuffer.append(line);
    462                 mOutputBuffer.append("\n");
    463             }
    464         }
    465 
    466         public boolean isCancelled() {
    467             return false;
    468         }
    469     }
    470 
    471     private class NullSyncProgressMonitor implements ISyncProgressMonitor {
    472         public void advance(int work) {
    473             // ignore
    474         }
    475 
    476         public boolean isCanceled() {
    477             // ignore
    478             return false;
    479         }
    480 
    481         public void start(int totalWork) {
    482             // ignore
    483 
    484         }
    485 
    486         public void startSubTask(String name) {
    487             // ignore
    488         }
    489 
    490         public void stop() {
    491             // ignore
    492         }
    493     }
    494 
    495     // For collecting results from running device tests
    496     public static class CollectingTestRunListener implements ITestRunListener {
    497 
    498         private boolean mAllTestsPassed = true;
    499         private String mTestRunErrorMessage = null;
    500 
    501         public void testEnded(TestIdentifier test) {
    502             // ignore
    503         }
    504 
    505         public void testFailed(TestFailure status, TestIdentifier test,
    506                 String trace) {
    507             Log.w(LOG_TAG, String.format("%s#%s failed: %s", test.getClassName(),
    508                     test.getTestName(), trace));
    509             mAllTestsPassed = false;
    510         }
    511 
    512         public void testRunEnded(long elapsedTime) {
    513             // ignore
    514         }
    515 
    516         public void testRunFailed(String errorMessage) {
    517             Log.w(LOG_TAG, String.format("test run failed: %s", errorMessage));
    518             mAllTestsPassed = false;
    519             mTestRunErrorMessage = errorMessage;
    520         }
    521 
    522         public void testRunStarted(int testCount) {
    523             // ignore
    524         }
    525 
    526         public void testRunStopped(long elapsedTime) {
    527             // ignore
    528         }
    529 
    530         public void testStarted(TestIdentifier test) {
    531             // ignore
    532         }
    533 
    534         boolean didAllTestsPass() {
    535             return mAllTestsPassed;
    536         }
    537 
    538         /**
    539          * Get the test run failure error message.
    540          * @return the test run failure error message or <code>null</code> if test run completed.
    541          */
    542         String getTestRunErrorMessage() {
    543             return mTestRunErrorMessage;
    544         }
    545     }
    546 
    547     /**
    548      * Output receiver for "pm install package.apk" command line.
    549      *
    550      */
    551     private static final class InstallReceiver extends MultiLineReceiver {
    552 
    553         private static final String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$
    554         private static final Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$
    555 
    556         private String mErrorMessage = null;
    557 
    558         public InstallReceiver() {
    559         }
    560 
    561         @Override
    562         public void processNewLines(String[] lines) {
    563             for (String line : lines) {
    564                 if (line.length() > 0) {
    565                     if (line.startsWith(SUCCESS_OUTPUT)) {
    566                         mErrorMessage = null;
    567                     } else {
    568                         Matcher m = FAILURE_PATTERN.matcher(line);
    569                         if (m.matches()) {
    570                             mErrorMessage = m.group(1);
    571                         }
    572                     }
    573                 }
    574             }
    575         }
    576 
    577         public boolean isCancelled() {
    578             return false;
    579         }
    580 
    581         public String getErrorMessage() {
    582             return mErrorMessage;
    583         }
    584     }
    585 
    586     /**
    587      * Helper method for installing an app to wherever is specified in its manifest, and
    588      * then verifying the app was installed onto SD Card.
    589      *
    590      * @param the path of the apk to install
    591      * @param the name of the package
    592      * @param true</code> if the app should be overwritten, <code>false</code> otherwise
    593      * @throws IOException if adb shell command failed
    594      * @throws InterruptedException if the thread was interrupted
    595      * <p/>
    596      * Assumes adb is running as root in device under test.
    597      */
    598     public void installAppAndVerifyExistsOnSDCard(String apkPath, String pkgName, boolean overwrite)
    599             throws IOException, InterruptedException {
    600         // Start with a clean slate if we're not overwriting
    601         if (!overwrite) {
    602             // cleanup test app just in case it already exists
    603             mDevice.uninstallPackage(pkgName);
    604             // grep for package to make sure its not installed
    605             assertFalse(doesPackageExist(pkgName));
    606         }
    607 
    608         installFile(apkPath, overwrite);
    609         assertTrue(doesAppExistOnSDCard(pkgName));
    610         assertFalse(doesAppExistOnDevice(pkgName));
    611         waitForPackageManager();
    612 
    613         // grep for package to make sure it is installed
    614         assertTrue(doesPackageExist(pkgName));
    615     }
    616 
    617     /**
    618      * Helper method for installing an app to wherever is specified in its manifest, and
    619      * then verifying the app was installed onto device.
    620      *
    621      * @param the path of the apk to install
    622      * @param the name of the package
    623      * @param true</code> if the app should be overwritten, <code>false</code> otherwise
    624      * @throws IOException if adb shell command failed
    625      * @throws InterruptedException if the thread was interrupted
    626      * <p/>
    627      * Assumes adb is running as root in device under test.
    628      */
    629     public void installAppAndVerifyExistsOnDevice(String apkPath, String pkgName, boolean overwrite)
    630             throws IOException, InterruptedException {
    631         // Start with a clean slate if we're not overwriting
    632         if (!overwrite) {
    633             // cleanup test app just in case it already exists
    634             mDevice.uninstallPackage(pkgName);
    635             // grep for package to make sure its not installed
    636             assertFalse(doesPackageExist(pkgName));
    637         }
    638 
    639         installFile(apkPath, overwrite);
    640         assertFalse(doesAppExistOnSDCard(pkgName));
    641         assertTrue(doesAppExistOnDevice(pkgName));
    642         waitForPackageManager();
    643 
    644         // grep for package to make sure it is installed
    645         assertTrue(doesPackageExist(pkgName));
    646     }
    647 
    648     /**
    649      * Helper method for installing an app as forward-locked, and
    650      * then verifying the app was installed in the proper forward-locked location.
    651      *
    652      * @param the path of the apk to install
    653      * @param the name of the package
    654      * @param true</code> if the app should be overwritten, <code>false</code> otherwise
    655      * @throws IOException if adb shell command failed
    656      * @throws InterruptedException if the thread was interrupted
    657      * <p/>
    658      * Assumes adb is running as root in device under test.
    659      */
    660     public void installFwdLockedAppAndVerifyExists(String apkPath,
    661             String pkgName, boolean overwrite) throws IOException, InterruptedException {
    662         // Start with a clean slate if we're not overwriting
    663         if (!overwrite) {
    664             // cleanup test app just in case it already exists
    665             mDevice.uninstallPackage(pkgName);
    666             // grep for package to make sure its not installed
    667             assertFalse(doesPackageExist(pkgName));
    668         }
    669 
    670         String result = installFileForwardLocked(apkPath, overwrite);
    671         assertEquals(null, result);
    672         assertTrue(doesAppExistAsForwardLocked(pkgName));
    673         assertFalse(doesAppExistOnSDCard(pkgName));
    674         waitForPackageManager();
    675 
    676         // grep for package to make sure it is installed
    677         assertTrue(doesPackageExist(pkgName));
    678     }
    679 
    680     /**
    681      * Helper method for uninstalling an app.
    682      *
    683      * @param pkgName package name to uninstall
    684      * @throws IOException if adb shell command failed
    685      * @throws InterruptedException if the thread was interrupted
    686      * <p/>
    687      * Assumes adb is running as root in device under test.
    688      */
    689     public void uninstallApp(String pkgName) throws IOException, InterruptedException {
    690         mDevice.uninstallPackage(pkgName);
    691         // make sure its not installed anymore
    692         assertFalse(doesPackageExist(pkgName));
    693     }
    694 
    695     /**
    696      * Helper method for clearing any installed non-system apps.
    697      * Useful ensuring no non-system apps are installed, and for cleaning up stale files that
    698      * may be lingering on the system for whatever reason.
    699      *
    700      * @throws IOException if adb shell command failed
    701      * <p/>
    702      * Assumes adb is running as root in device under test.
    703      */
    704     public void wipeNonSystemApps() throws IOException {
    705       String allInstalledPackages = executeShellCommand("pm list packages -f");
    706       BufferedReader outputReader = new BufferedReader(new StringReader(allInstalledPackages));
    707 
    708       // First use Package Manager to uninstall all non-system apps
    709       String currentLine = null;
    710       while ((currentLine = outputReader.readLine()) != null) {
    711           // Skip over any system apps...
    712           if (currentLine.contains("/system/")) {
    713               continue;
    714           }
    715           String packageName = currentLine.substring(currentLine.indexOf('=') + 1);
    716           mDevice.uninstallPackage(packageName);
    717       }
    718       // Make sure there are no stale app files under these directories
    719       executeShellCommand(String.format("rm %s*", SDCARD_APP_PATH, "*"));
    720       executeShellCommand(String.format("rm %s*", DEVICE_APP_PATH, "*"));
    721       executeShellCommand(String.format("rm %s*", APP_PRIVATE_PATH, "*"));
    722     }
    723 
    724     /**
    725      * Sets the device's install location preference.
    726      *
    727      * <p/>
    728      * Assumes adb is running as root in device under test.
    729      */
    730     public void setDevicePreferredInstallLocation(InstallLocPreference pref) throws IOException {
    731         String command = "pm setInstallLocation %d";
    732         int locValue = 0;
    733         switch (pref) {
    734             case INTERNAL:
    735                 locValue = 1;
    736                 break;
    737             case EXTERNAL:
    738                 locValue = 2;
    739                 break;
    740             default: // AUTO
    741                 locValue = 0;
    742                 break;
    743         }
    744         executeShellCommand(String.format(command, locValue));
    745     }
    746 
    747     /**
    748      * Gets the device's install location preference.
    749      *
    750      * <p/>
    751      * Assumes adb is running as root in device under test.
    752      */
    753     public InstallLocPreference getDevicePreferredInstallLocation() throws IOException {
    754         String result = executeShellCommand("pm getInstallLocation");
    755         if (result.indexOf('0') != -1) {
    756             return InstallLocPreference.AUTO;
    757         }
    758         else if (result.indexOf('1') != -1) {
    759             return InstallLocPreference.INTERNAL;
    760         }
    761         else {
    762             return InstallLocPreference.EXTERNAL;
    763         }
    764     }
    765 }
    766