Home | History | Annotate | Download | only in cts
      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