1 /* 2 * Copyright (C) 2008 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.cts; 18 19 import java.io.FileInputStream; 20 import java.io.IOException; 21 import java.security.MessageDigest; 22 import java.security.NoSuchAlgorithmException; 23 import java.util.ArrayList; 24 import java.util.Collection; 25 import java.util.Iterator; 26 import java.util.List; 27 import java.util.TimerTask; 28 29 import com.android.cts.TestSession.TestSessionThread; 30 31 /** 32 * Correspond to an APK, provide functions on 33 * representing and executing an APK from CTS test harness. 34 */ 35 public class TestPackage implements DeviceObserver { 36 protected static final String PKG_LOG_SEPARATOR = 37 "=============================================================="; 38 39 /** 40 * For batch mode, there is just one command sent to the device 41 * for the whole package, and the device will feed back the result 42 * test by test. To guard the command, a timeout timer is started 43 * to prevent it from running forever. And to make the timeout time 44 * not too long, it's better choice to restart the timer each time 45 * received the feedback from device. The following two variables 46 * are used to restart/stop the timer, START for restarting and 47 * FINISH for stopping. 48 */ 49 public static final String FINISH = "finish"; 50 public static final String START = "start"; 51 52 private String mName, mVersion, mAndroidVersion; 53 private String mTargetNameSpace, mTargetBinaryName, mInstrumentationRunner; 54 private Collection<TestSuite> mSuites; 55 private String mDigest; 56 private String mJarPath; 57 private String mAppNameSpace; 58 private String mAppPackageName; 59 60 protected TestSuite mCurrentTestSuite; 61 62 protected TestDevice mDevice; 63 64 protected boolean mTestStop; 65 private TestSessionThread mTestThread; 66 67 private HostTimer mTimeOutTimer; 68 private ProgressObserver mProgressObserver; 69 private boolean mIsInBatchMode; 70 private Test mCurrentTest; 71 72 /** 73 * Construct a test package with given necessary information. 74 * 75 * @param instrumentationRunner The instrumentation runner. 76 * @param testPkgBinaryName The binary name of the TestPackage. 77 * @param targetNameSpace The target name space of the dependent package, if available. 78 * @param version The version of the CTS Host allowed. 79 * @param androidVersion The version of the Anroid platform allowed. 80 * @param jarPath The host controller's jar path and file. 81 * @param appNameSpace The package name space. 82 * @param appPackageName The Java package name of the test package. 83 */ 84 public TestPackage(final String instrumentationRunner, 85 final String testPkgBinaryName, final String targetNameSpace, 86 final String targetBinaryName, final String version, 87 final String androidVersion, final String jarPath, final String appNameSpace, 88 final String appPackageName) { 89 mInstrumentationRunner = instrumentationRunner; 90 mName = testPkgBinaryName; 91 mTargetNameSpace = targetNameSpace; 92 mTargetBinaryName = targetBinaryName; 93 mVersion = version; 94 mAndroidVersion = androidVersion; 95 mSuites = new ArrayList<TestSuite>(); 96 mJarPath = jarPath; 97 mAppNameSpace = appNameSpace; 98 mAppPackageName = appPackageName; 99 100 mDevice = null; 101 mTestStop = false; 102 mTestThread = null; 103 mIsInBatchMode = false; 104 mCurrentTest = null; 105 } 106 107 /** 108 * Get the app package name space. 109 * 110 * @return The app package name space. 111 */ 112 public String getAppNameSpace() { 113 return mAppNameSpace; 114 } 115 116 /** 117 * Get the app JAVA package name. 118 * 119 * @return The app JAVA package name. 120 */ 121 public String getAppPackageName() { 122 return mAppPackageName; 123 } 124 125 /** 126 * Returns whether this is a host side test package. 127 */ 128 public boolean isHostSideOnly() { 129 return false; 130 } 131 132 /** 133 * Add a TestSuite. 134 * 135 * @param suite The TestSuite to be added. 136 */ 137 public void addTestSuite(final TestSuite suite) { 138 mSuites.add(suite); 139 } 140 141 /** 142 * Get test suites under this package. 143 * 144 * @return The test suites under this package. 145 */ 146 public Collection<TestSuite> getTestSuites() { 147 return mSuites; 148 } 149 150 /** 151 * Get the specific test suite by the full suite name. 152 * 153 * @param suiteFullName The full suite name. 154 * @return The test suite. 155 */ 156 public TestSuite getTestSuiteByName(final String suiteFullName) { 157 for (TestSuite suite : getAllTestSuites()) { 158 if (suite.getFullName().equals(suiteFullName)) { 159 return suite; 160 } 161 } 162 return null; 163 } 164 165 /** 166 * Get the specific test case by the full test case name. 167 * 168 * @param testCaseFullName The full test case name. 169 * @return The test case. 170 */ 171 public TestCase getTestCaseByName(final String testCaseFullName) { 172 for (TestCase testCase : getAllTestCases()) { 173 if (testCase.getFullName().equals(testCaseFullName)) { 174 return testCase; 175 } 176 } 177 return null; 178 } 179 180 /** 181 * Get all of test suites under this package. 182 * 183 * @return All of the test suites under this package. 184 */ 185 public Collection<TestSuite> getAllTestSuites() { 186 Collection<TestSuite> suites = new ArrayList<TestSuite>(); 187 for (TestSuite suite : mSuites) { 188 suites.addAll(suite.getAllSuites()); 189 } 190 return suites; 191 } 192 193 /** 194 * Get suite/case names contained in this test package, searched against the expected name. 195 * 196 * @param expectName The expected name. 197 * @param suiteNameList The suite names list. 198 * @param caseNameList The case names list. 199 */ 200 public void getTestSuiteNames(final String expectName, 201 List<String> suiteNameList, List<String> caseNameList) { 202 203 for (TestCase testCase : getAllTestCases()) { 204 String testCaseName = testCase.getFullName(); 205 if (testCaseName.startsWith(expectName)) { 206 String suiteName = testCaseName.substring(0, testCaseName.lastIndexOf(".")); 207 if (suiteName.equals(expectName)) { 208 if (!caseNameList.contains(testCaseName)) { 209 caseNameList.add(testCaseName); 210 } 211 } else { 212 if (!suiteNameList.contains(suiteName)) { 213 suiteNameList.add(suiteName); 214 } 215 } 216 } 217 } 218 } 219 220 /** 221 * Get all test suite names contained in this test package. 222 * 223 * @return The test suite name list. 224 */ 225 public List<String> getAllTestSuiteNames() { 226 List<String> suiteNameList = new ArrayList<String>(); 227 for (TestCase testCase : getAllTestCases()) { 228 String testCaseName = testCase.getFullName(); 229 String suiteName = testCaseName.substring(0, testCaseName.lastIndexOf(".")); 230 if (!suiteNameList.contains(suiteName)) { 231 suiteNameList.add(suiteName); 232 } 233 } 234 return suiteNameList; 235 } 236 237 /** 238 * Get all test case names contained in the suite in this test package. 239 * 240 * @param suiteFullName The full suite name. 241 * @return All test case names. 242 */ 243 public List<String> getAllTestCaseNames(final String suiteFullName) { 244 List<String> caseNameList = new ArrayList<String>(); 245 TestSuite suite = getTestSuiteByName(suiteFullName); 246 if (suite != null) { 247 caseNameList.addAll(suite.getAllTestCaseNames()); 248 } 249 return caseNameList; 250 } 251 252 /** 253 * Get all test names contained in the test case in this test package. 254 * 255 * @param testCaseFullName The full test case name. 256 * @return All test names. 257 */ 258 public List<String> getAllTestNames(final String testCaseFullName) { 259 List<String> testNameList = new ArrayList<String>(); 260 TestCase testCase = getTestCaseByName(testCaseFullName); 261 if (testCase != null) { 262 testNameList.addAll(testCase.getAllTestNames()); 263 } 264 return testNameList; 265 } 266 267 /** 268 * Get test case names list. 269 * 270 * @param expectPackage The expected package name. 271 * @param caseList The searched test case result. 272 * @param testList The searched test result. 273 */ 274 public void getTestCaseNames(final String expectPackage, List<String> caseList, 275 List<String> testList) { 276 277 for (TestCase testCase : getAllTestCases()) { 278 String testCaseName = testCase.getFullName(); 279 if (testCaseName.equals(expectPackage)) { 280 for (Test test : testCase.getTests()) { 281 testList.add(test.getFullName()); 282 } 283 return; 284 } else if (testCaseName.startsWith(expectPackage)) { 285 caseList.add(testCaseName); 286 } 287 } 288 } 289 290 /** 291 * Get test names list. 292 * 293 * @param expectPackage The expected package name. 294 * @param testList The searched test result. 295 */ 296 public void getTestNames(final String expectPackage, List<String> testList) { 297 298 for (Test test : getTests()) { 299 String testName = test.getFullName(); 300 if (testName.startsWith(expectPackage)) { 301 testList.add(testName); 302 } 303 } 304 } 305 306 /** 307 * Get the binary name of this package. 308 * 309 * @return The binary name of this package. 310 */ 311 public String getAppBinaryName() { 312 return mName; 313 } 314 315 /** 316 * Get the version string of this package. 317 * 318 * @return The version string of this package. 319 */ 320 public String getVersion() { 321 return mVersion; 322 } 323 324 /** 325 * Get the version information of Android. 326 * 327 * @return The version information of Android. 328 */ 329 public String getAndroidVersion() { 330 return mAndroidVersion; 331 } 332 333 /** 334 * Get the target name space of this package. 335 * 336 * @return The target name space of the package. 337 */ 338 public String getTargetNameSpace() { 339 return mTargetNameSpace; 340 } 341 342 /** 343 * Get the target binary name. 344 * 345 * @return The target binary name. 346 */ 347 public String getTargetBinaryName() { 348 return mTargetBinaryName; 349 } 350 351 /** 352 * Get the instrumentation runner. 353 * 354 * @return The instrumentation runner. 355 */ 356 public String getInstrumentationRunner() { 357 return mInstrumentationRunner; 358 } 359 360 /** 361 * Search a specific Test within this package. 362 * 363 * @param testName The test name to be searched against. 364 * @return The Test matches the given name. 365 */ 366 public Test searchTest(final String testName) { 367 Test test = null; 368 for (TestSuite suite : mSuites) { 369 test = suite.searchTest(testName); 370 if (test != null) { 371 break; 372 } 373 } 374 375 return test; 376 } 377 378 /** 379 * Get all tests of this test package. 380 * 381 * @return The tests of this test package. 382 */ 383 public Collection<Test> getTests() { 384 List<Test> tests = new ArrayList<Test>(); 385 for (TestSuite s : mSuites) { 386 tests.addAll(s.getTests()); 387 } 388 389 return tests; 390 } 391 392 /** 393 * Get all test cases of this test package. 394 * 395 * @return The test cases of this test package. 396 */ 397 public Collection<TestCase> getAllTestCases() { 398 List<TestCase> testCases = new ArrayList<TestCase>(); 399 for (TestSuite s : mSuites) { 400 testCases.addAll(s.getAllTestCases()); 401 } 402 403 return testCases; 404 } 405 406 /** 407 * Set the message digest of the test package. 408 * 409 * @param digest the string of the package's message digest. 410 */ 411 private void setMessageDigest(final String digest) { 412 mDigest = digest; 413 } 414 415 /** 416 * Get the string of package's message digest. 417 * 418 * @return message digest string. 419 */ 420 public String getMessageDigest() { 421 return mDigest; 422 } 423 424 /** 425 * Get the the path of the controller jar file. 426 * 427 * @return message digest string. 428 */ 429 public String getJarPath() { 430 return mJarPath; 431 } 432 433 /** 434 * Get the excluded list according to the execution status of each test. 435 * 436 * @param resultType The result type to filter the tests. 437 * @return All excluded list. There are three scenarios to interpret the return value: 438 * <ul> 439 * <li> null: nothing should be added to plan; 440 * <li> list size equals 0: the whole package should be added to plan; 441 * <li> list size greater than 0: the given excluded list should be added to plan. 442 * </ul> 443 */ 444 public ArrayList<String> getExcludedList(final String resultType) { 445 ArrayList<String> excludedList = new ArrayList<String>(); 446 ArrayList<String> fullNameList = new ArrayList<String>(); 447 for (TestSuite suite : getTestSuites()) { 448 fullNameList.add(suite.getFullName()); 449 ArrayList<String> list = suite.getExcludedList(resultType); 450 if ((list != null) && (list.size() > 0)) { 451 excludedList.addAll(list); 452 } 453 } 454 455 int count = 0; 456 for (String fullName : fullNameList) { 457 if (excludedList.contains(fullName)) { 458 count ++; 459 } 460 } 461 if (count == fullNameList.size()) { 462 //all suites contained have been excluded, 463 //return null to tell the caller nothing to add to the plan 464 return null; 465 } 466 return excludedList; 467 } 468 469 /** 470 * Print the message by appending the new line mark. 471 * 472 * @param msg The message to be print. 473 */ 474 protected void println(final String msg) { 475 if (!mTestStop) { 476 CUIOutputStream.println(msg); 477 } 478 } 479 480 /** 481 * Print the message without appending the new line mark. 482 * 483 * @param msg The message to be print. 484 */ 485 protected void print(final String msg) { 486 if (!mTestStop) { 487 CUIOutputStream.print(msg); 488 } 489 } 490 491 /** 492 * Notify that the batch mode finished. 493 */ 494 public void notifyBatchModeFinish() { 495 Log.d("TestPackage.notifyBatchModeFinish() is called, mTestStop=" + mTestStop); 496 if (mTestStop) { 497 return; 498 } 499 500 if (mIsInBatchMode) { 501 if (mCurrentTest != null) { 502 handleMissingFinishEvent(); 503 } 504 synchronized (mTimeOutTimer) { 505 mTimeOutTimer.sendNotify(); 506 } 507 } 508 } 509 510 /** 511 * Handle the missing FINISH event. 512 */ 513 private void handleMissingFinishEvent() { 514 mProgressObserver.stop(); 515 synchronized (mTimeOutTimer) { 516 mTimeOutTimer.cancel(false); 517 } 518 // The currently running test did not report a result. Mark it as not executed, so that it 519 // will be run again in individual mode. 520 mCurrentTest.setResult(new CtsTestResult(CtsTestResult.CODE_NOT_EXECUTED, null, null)); 521 mCurrentTest = null; 522 } 523 524 /** 525 * Update Test running status when running in batch mode. 526 * 527 * @param test The Test to update. May be null if a status gets reported on a test that is not 528 * in the test plan. 529 * @param status The status to be updated. 530 */ 531 public void notifyTestStatus(final Test test, final String status) { 532 if (mTestStop) { 533 return; 534 } 535 536 if (mIsInBatchMode) { 537 if (status.equals(START)) { 538 if ((mCurrentTest != null) && (mCurrentTest.getResult().isNotExecuted())) { 539 Log.d("Err: Missing FINISH msg for test " + mCurrentTest.getFullName()); 540 handleMissingFinishEvent(); 541 } 542 mCurrentTest = test; 543 if (test != null) { 544 print(mCurrentTest.getFullName() + "..."); 545 mProgressObserver.start(); 546 } 547 } else { 548 mProgressObserver.stop(); 549 mCurrentTest = null; 550 } 551 // restart the timer even for unexpected tests 552 mTimeOutTimer.restart(new TimeOutTask(this), 553 HostConfig.Ints.testStatusTimeoutMs.value()); 554 } 555 } 556 557 /** {@inheritDoc} */ 558 public void notifyInstallingComplete(final int resultCode) { 559 Log.d("notifyInstallingComplete() is called with resultCode=" + resultCode); 560 sendNotify(); 561 562 if (resultCode == FAIL) { 563 Log.d("install failed"); 564 } 565 } 566 567 /** {@inheritDoc} */ 568 public void notifyUninstallingComplete(final int resultCode) { 569 Log.d("notifyUninstallingComplete() is called with resultCode=" + resultCode); 570 sendNotify(); 571 572 if (resultCode == FAIL) { 573 Log.d("uninstall failed"); 574 } 575 } 576 577 /** 578 * Send notify to wake up the thread waiting on the object. 579 */ 580 private void sendNotify() { 581 synchronized (this) { 582 notify(); 583 } 584 } 585 586 /** {@inheritDoc} */ 587 public void notifyInstallingTimeout(final TestDevice testDevice) { 588 Log.d("TestPackage.notifyInstallingTimeout() is called"); 589 mTestStop = true; 590 synchronized (this) { 591 notify(); 592 } 593 594 genPackageActionTimeoutCause(testDevice, "Installing"); 595 } 596 597 /** {@inheritDoc} */ 598 public void notifyUninstallingTimeout(final TestDevice testDevice) { 599 Log.d("TestPackage.notifyUninstallingTimeout() is called"); 600 mTestStop = true; 601 synchronized (this) { 602 notify(); 603 } 604 605 genPackageActionTimeoutCause(testDevice, "Uninstalling"); 606 } 607 608 /** 609 * Generate the cause of package action timeout. 610 * 611 * @param testDevice The {@link TestDevice} which got timeout. 612 * @param type Install or Uninstall. 613 */ 614 private void genPackageActionTimeoutCause(final TestDevice testDevice, String type) { 615 String cause; 616 if (testDevice.getStatus() == TestDevice.STATUS_OFFLINE) { 617 cause = testDevice.getSerialNumber() + " is offline."; 618 } else { 619 cause = "Unknown reason."; 620 } 621 622 if (type == null) { 623 type = "Unknown timer"; 624 } 625 Log.e(type + " met timeout due to " + cause, null); 626 } 627 628 /** {@inheritDoc} */ 629 public void notifyTestingDeviceDisconnected() { 630 Log.d("busyDeviceDisconnected invoked"); 631 mTestStop = true; 632 synchronized (this) { 633 notify(); 634 } 635 636 cleanUp(); 637 638 try { 639 CUIOutputStream.println("Test stopped."); 640 mTestThread.join(); 641 } catch (InterruptedException e) { 642 Log.e("", e); 643 } 644 } 645 646 /** 647 * Set the {@link TestDevice} which will run the test. 648 * 649 * @param device The {@link TestDevice} will run the test. 650 */ 651 public void setTestDevice(final TestDevice device) { 652 mDevice = device; 653 device.setRuntimeListener(this); 654 device.setStatus(TestDevice.STATUS_BUSY); 655 } 656 657 /** 658 * Get the full path information. 659 * 660 * @param binaryFileName The binary file name. 661 * @return The full path information. 662 */ 663 private String getFullPath(String binaryFileName) { 664 String packagePath = null; 665 if ((binaryFileName != null) && (binaryFileName.length() != 0)) { 666 packagePath = HostConfig.getInstance().getCaseRepository() 667 .getApkPath(binaryFileName); 668 } 669 return packagePath; 670 } 671 /** 672 * Load(install) test package and target package(if it exists). 673 * 674 * @return If succeed in installing, return true; else, return false. 675 */ 676 private boolean install() throws DeviceDisconnectedException, InvalidApkPathException { 677 String packageBinaryName = getAppBinaryName(); 678 String targetBinaryName = getTargetBinaryName(); 679 String packagePath = getFullPath(packageBinaryName); 680 String targetApkPath = getFullPath(targetBinaryName); 681 682 boolean success = true; 683 if (packagePath != null) { 684 installAPK(packagePath); 685 if ((!mTestStop) && (targetApkPath != null)) { 686 installAPK(targetApkPath); 687 } 688 } else { 689 success = false; 690 Log.e("The package binary name contains nothing!", null); 691 } 692 693 if (mTestStop) { 694 success = false; 695 println("Install package " + packageBinaryName + "failed"); 696 } 697 698 return success; 699 } 700 701 /** 702 * Uninstall test package and target package(if it exists) 703 */ 704 private void uninstall() throws DeviceDisconnectedException, InvalidNameSpaceException { 705 706 String testPkgBinaryName = getAppBinaryName(); 707 String appNameSpace = getAppNameSpace(); 708 String targetNameSpace = getTargetNameSpace(); 709 String packagePath = getFullPath(testPkgBinaryName); 710 String targetApkPath = getFullPath(targetNameSpace); 711 712 if ((packagePath != null) && HostUtils.isFileExist(packagePath)) { 713 uninstallAPK(appNameSpace); 714 if ((!mTestStop) && (targetNameSpace != null) 715 && ((targetApkPath != null) && (HostUtils.isFileExist(targetApkPath)))) { 716 uninstallAPK(targetNameSpace); 717 } 718 } 719 } 720 721 /** 722 * Uninstall the specified package(.apk) 723 */ 724 private void uninstallAPK(final String packageName) throws DeviceDisconnectedException, 725 InvalidNameSpaceException { 726 Log.d("Uninstall: " + packageName); 727 mDevice.uninstallAPK(packageName); 728 waitPackageActionComplete(); 729 } 730 731 /** 732 * Install the test package on the devices attached to this session. 733 * 734 * @param apkPath The test package to be installed. 735 */ 736 private void installAPK(final String apkPath) throws DeviceDisconnectedException, 737 InvalidApkPathException { 738 Log.d("installAPK " + apkPath + " ..."); 739 mDevice.installAPK(apkPath); 740 waitPackageActionComplete(); 741 Log.d("installAPK " + apkPath + " finish"); 742 } 743 744 /** 745 * Wait for package action to complete. 746 */ 747 private void waitPackageActionComplete() { 748 Log.d("Enter waitPackageActionComplete()"); 749 synchronized (this) { 750 if (!mTestStop) { 751 try { 752 wait(); 753 } catch (InterruptedException e) { 754 Log.e("", e); 755 } 756 } 757 } 758 try { 759 Thread.sleep(HostConfig.Ints.postInstallWaitMs.value()); 760 } catch (InterruptedException e) { 761 Log.e("", e); 762 } 763 Log.d("Leave waitPackageActionComplete()"); 764 } 765 766 /** 767 * Generate the message digest of the specified package 768 * 769 * @param packagePath path to the package. 770 * @return message digest string(base64 encoded). 771 */ 772 private String genMessageDigest(final String packagePath) throws IOException { 773 final String algorithm = "SHA-1"; 774 FileInputStream fin = new FileInputStream(packagePath); 775 try { 776 MessageDigest md = MessageDigest.getInstance(algorithm); 777 byte[] buffer = new byte[1024]; 778 int len; 779 while ((len = fin.read(buffer)) != -1) { 780 md.update(buffer, 0, len); 781 } 782 fin.close(); 783 return HostUtils.toHexString(md.digest()); 784 } catch (NoSuchAlgorithmException e) { 785 return algorithm + " not found"; 786 } 787 } 788 789 /** 790 * Set the test session thread. 791 * 792 * @param thread 793 */ 794 public void setSessionThread(TestSessionThread thread) { 795 mTestThread = thread; 796 } 797 798 /** 799 * Check if it's valid to use batch mode. 800 * 801 * @return If each test under this package doesn't depend on any host controller, return true; 802 * else, return false; 803 */ 804 private boolean supportsBatchMode() { 805 Collection<Test> tests = getTests(); 806 807 // check whether the package is small enough for batch mode 808 if (tests.size() > HostConfig.Ints.maxTestsInBatchMode.value()) { 809 return false; 810 } 811 812 for (Test test : tests) { 813 if (!test.getResult().isNotExecuted()) { 814 // if any test has been run, use individual mode 815 return false; 816 } 817 818 if ((test.getTestController() != null) 819 && (test.getTestController().getFullName() != null)) { 820 return false; 821 } 822 } 823 824 return true; 825 } 826 827 /** 828 * Get the first segment list of all of the test packages. 829 * 830 * @return the first segment list of all of the test packages contained in this test package; 831 */ 832 List<String> getPackageNames() { 833 List<String> pkgNames = new ArrayList<String>(); 834 List<String> suiteNames = getAllTestSuiteNames(); 835 for (String suiteName : suiteNames) { 836 String pkgSeg = suiteName; 837 if (suiteName.contains(".")) { 838 pkgSeg = suiteName.split("\\.")[0]; 839 } 840 if (!pkgNames.contains(pkgSeg)) { 841 pkgNames.add(pkgSeg); 842 } 843 } 844 845 return pkgNames; 846 } 847 848 /** 849 * Run this package or the java package contained in this package in batch mode. 850 * 851 * @param javaPkgName The java package name. If null, run the whole package; 852 * else, run the specified java package contained in this package 853 */ 854 private void runInBatchMode(final String javaPkgName) 855 throws DeviceDisconnectedException { 856 mTimeOutTimer = new HostTimer(new TimeOutTask(this), 857 HostConfig.Ints.batchStartTimeoutMs.value()); 858 mTimeOutTimer.start(); 859 mProgressObserver = new ProgressObserver(); 860 861 if ((javaPkgName != null) && (javaPkgName.length() > 0)) { 862 runInBatchModeImpl(javaPkgName); 863 } else { 864 for (String pkgName : getPackageNames()) { 865 runInBatchModeImpl(pkgName); 866 } 867 } 868 } 869 870 /** 871 * Implementation of running in batch mode. 872 * 873 * @param javaPkgName The java package name. 874 */ 875 private void runInBatchModeImpl(String javaPkgName) throws DeviceDisconnectedException { 876 mDevice.runInBatchMode(this, javaPkgName); 877 878 synchronized (mTimeOutTimer) { 879 if (!mTestStop) { 880 try { 881 mTimeOutTimer.waitOn(); 882 } catch (InterruptedException e) { 883 Log.d("time out object interrupted"); 884 } 885 } 886 887 mProgressObserver.stop(); 888 if (mTimeOutTimer.isTimeOut()) { 889 return; 890 } else { 891 // not caused by watch dog timer timing out, 892 // need to cancel timer 893 mTimeOutTimer.cancel(false); 894 } 895 } 896 } 897 898 /** 899 * Run this package in individual mode. 900 * 901 * @param javaPkgName The java package name. 902 */ 903 protected void runInIndividualMode(final String javaPkgName) throws IOException, 904 DeviceDisconnectedException, ADBServerNeedRestartException { 905 Iterator<TestSuite> suites = getTestSuites().iterator(); 906 while (suites.hasNext() && (!mTestStop)) { 907 mCurrentTestSuite = suites.next(); 908 mCurrentTestSuite.run(mDevice, javaPkgName); 909 } 910 } 911 912 /** 913 * The timer task which aids in guarding the running package with the 914 * guarding timer. If the executing of the package is not finished, and the 915 * guarding timer is expired, this task will be executed to force the finish 916 * of the running package. 917 */ 918 class TimeOutTask extends TimerTask { 919 private TestPackage mTestPackage; 920 921 public TimeOutTask(final TestPackage testPackage) { 922 mTestPackage = testPackage; 923 } 924 925 @Override 926 public void run() { 927 mProgressObserver.stop(); 928 synchronized (mTimeOutTimer) { 929 mTimeOutTimer.cancel(true); 930 mTimeOutTimer.sendNotify(); 931 } 932 933 if ((mIsInBatchMode) && (mCurrentTest != null)) { 934 mCurrentTest.setResult( 935 new CtsTestResult(CtsTestResult.CODE_TIMEOUT, null, null)); 936 mCurrentTest = null; 937 } 938 939 Log.d("mTimeOutTimer timed out"); 940 killDeviceProcess(mTestPackage.getAppPackageName()); 941 } 942 } 943 944 /** 945 * Kill the device process. 946 * 947 * @param packageName 948 */ 949 private void killDeviceProcess(final String packageName) { 950 mDevice.killProcess(packageName); 951 } 952 953 /** 954 * Check if all of the tests contained in this package have been run. 955 * 956 * @return If all tests have been run, return true; else, return false. 957 */ 958 protected boolean isAllTestsRun(){ 959 for (Test test : getTests()) { 960 if (test.getResult().isNotExecuted()) { 961 return false; 962 } 963 } 964 return true; 965 } 966 967 /** 968 * Check if any of the tests contained in this package have been executed. 969 * 970 * @return If no tests have been executed, return true, otherwise return false. 971 */ 972 protected boolean noTestsExecuted() { 973 for (Test test : getTests()) { 974 if (!test.getResult().isNotExecuted()) { 975 return false; 976 } 977 } 978 return true; 979 } 980 981 /** 982 * Run the java package contained within this package over device. 983 * 984 * @param device The device to run this package.getName 985 * @param sessionLog the TestSession log for this TestSession. 986 */ 987 public void run(final TestDevice device, final String javaPkgName, 988 TestSessionLog sessionLog) 989 throws IOException, DeviceDisconnectedException, 990 ADBServerNeedRestartException, InvalidApkPathException, 991 InvalidNameSpaceException { 992 if (isAllTestsRun()) { 993 return; 994 } 995 996 setup(device, javaPkgName); 997 runImpl(javaPkgName); 998 } 999 1000 /** 1001 * Implementation of running the test package. 1002 * 1003 * @param javaPkgName The JAVA package name. 1004 */ 1005 protected void runImpl(final String javaPkgName) throws IOException, 1006 DeviceDisconnectedException, ADBServerNeedRestartException, InvalidApkPathException, 1007 InvalidNameSpaceException { 1008 try { 1009 if (!install()) { 1010 return; 1011 } 1012 1013 if (!mTestStop) { 1014 Log.d("install " + getAppBinaryName() + " succeed!"); 1015 1016 setMessageDigest(genMessageDigest(HostConfig.getInstance() 1017 .getCaseRepository().getApkPath(getAppBinaryName()))); 1018 1019 if (supportsBatchMode()) { 1020 mIsInBatchMode = true; 1021 Log.d("run in batch mode..."); 1022 runInBatchMode(javaPkgName); 1023 if (!isAllTestsRun()) { 1024 mIsInBatchMode = false; 1025 Log.d("run in individual mode"); 1026 runInIndividualMode(javaPkgName); 1027 } 1028 } else { 1029 Log.d("run in individual mode..."); 1030 runInIndividualMode(javaPkgName); 1031 } 1032 } 1033 1034 if (!mTestStop) { 1035 uninstall(); 1036 if (!TestSession.isADBServerRestartedMode()) { 1037 println(PKG_LOG_SEPARATOR); 1038 } 1039 } 1040 } catch (DeviceDisconnectedException e) { 1041 cleanUp(); 1042 throw e; 1043 } 1044 } 1045 1046 /** 1047 * Set up before running. 1048 * 1049 * @param device The device to run this package.getName 1050 * @param javaPkgName The JAVA package name. 1051 */ 1052 protected void setup(final TestDevice device, final String javaPkgName) { 1053 if (!TestSession.isADBServerRestartedMode() || noTestsExecuted()) { 1054 println(PKG_LOG_SEPARATOR); 1055 if ((javaPkgName == null) || (javaPkgName.length() == 0)) { 1056 println("Test package: " + getAppPackageName()); 1057 } else { 1058 println("Test java package contained in test package " 1059 + getAppPackageName() + ": " + javaPkgName); 1060 } 1061 } 1062 1063 mTestStop = false; 1064 mIsInBatchMode = false; 1065 mCurrentTest = null; 1066 mCurrentTestSuite = null; 1067 1068 setTestDevice(device); 1069 } 1070 1071 /** 1072 * Clean up. 1073 */ 1074 public void cleanUp() { 1075 if (mCurrentTestSuite != null) { 1076 mCurrentTestSuite.setTestStopped(mTestStop); 1077 mCurrentTestSuite.notifyTestingDeviceDisconnected(); 1078 } 1079 1080 if (mProgressObserver != null) { 1081 mProgressObserver.stop(); 1082 } 1083 1084 if (mTimeOutTimer != null) { 1085 mTimeOutTimer.cancel(false); 1086 } 1087 } 1088 1089 /** 1090 * Run the specific test contained in the package over device. 1091 * 1092 * @param device The device to run the specific test. 1093 * @param test The specific test to be run. 1094 */ 1095 public void runTest(final TestDevice device, final Test test) 1096 throws DeviceDisconnectedException, ADBServerNeedRestartException, 1097 InvalidApkPathException, InvalidNameSpaceException { 1098 1099 if (test == null) { 1100 return; 1101 } 1102 1103 mTestStop = false; 1104 mIsInBatchMode = false; 1105 1106 println(PKG_LOG_SEPARATOR); 1107 println("Test package: " + getAppPackageName()); 1108 setTestDevice(device); 1109 1110 runTestImpl(test); 1111 } 1112 1113 /** 1114 * Implementation of running test. 1115 * 1116 * @param test The test to be run. 1117 */ 1118 protected void runTestImpl(final Test test) throws DeviceDisconnectedException, 1119 ADBServerNeedRestartException, InvalidApkPathException, 1120 InvalidNameSpaceException { 1121 try { 1122 if (!install()) { 1123 return; 1124 } 1125 1126 if (!mTestStop) { 1127 Log.d("install " + getAppPackageName() + " succeed!"); 1128 mCurrentTestSuite = test.getTestSuite(); 1129 mCurrentTestSuite.run(mDevice, test); 1130 } 1131 1132 if (!mTestStop) { 1133 uninstall(); 1134 println(PKG_LOG_SEPARATOR); 1135 } 1136 } catch (DeviceDisconnectedException e) { 1137 cleanUp(); 1138 throw e; 1139 } 1140 } 1141 } 1142