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 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