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 * @paramtrue</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