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