• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
TestPackage(final String instrumentationRunner, final String testPkgBinaryName, final String targetNameSpace, final String targetBinaryName, final String version, final String androidVersion, final String jarPath, final String appNameSpace, final String appPackageName)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      */
getAppNameSpace()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      */
getAppPackageName()121     public String getAppPackageName() {
122         return mAppPackageName;
123     }
124 
125     /**
126      * Returns whether this is a host side test package.
127      */
isHostSideOnly()128     public boolean isHostSideOnly() {
129         return false;
130     }
131 
132     /**
133      * Add a TestSuite.
134      *
135      * @param suite The TestSuite to be added.
136      */
addTestSuite(final TestSuite suite)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      */
getTestSuites()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      */
getTestSuiteByName(final String suiteFullName)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      */
getTestCaseByName(final String testCaseFullName)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      */
getAllTestSuites()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      */
getTestSuiteNames(final String expectName, List<String> suiteNameList, List<String> caseNameList)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      */
getAllTestSuiteNames()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      */
getAllTestCaseNames(final String suiteFullName)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      */
getAllTestNames(final String testCaseFullName)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      */
getTestCaseNames(final String expectPackage, List<String> caseList, List<String> testList)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      */
getTestNames(final String expectPackage, List<String> testList)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      */
getAppBinaryName()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      */
getVersion()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      */
getAndroidVersion()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      */
getTargetNameSpace()338     public String getTargetNameSpace() {
339         return mTargetNameSpace;
340     }
341 
342     /**
343      * Get the target binary name.
344      *
345      * @return The target binary name.
346      */
getTargetBinaryName()347     public String getTargetBinaryName() {
348         return mTargetBinaryName;
349     }
350 
351     /**
352      * Get the instrumentation runner.
353      *
354      * @return The instrumentation runner.
355      */
getInstrumentationRunner()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      */
searchTest(final String testName)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      */
getTests()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      */
getAllTestCases()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      */
setMessageDigest(final String digest)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      */
getMessageDigest()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      */
getJarPath()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      */
getExcludedList(final String resultType)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      */
println(final String msg)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      */
print(final String msg)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      */
notifyBatchModeFinish()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      */
handleMissingFinishEvent()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      */
notifyTestStatus(final Test test, final String status)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} */
notifyInstallingComplete(final int resultCode)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} */
notifyUninstallingComplete(final int resultCode)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      */
sendNotify()580     private void sendNotify() {
581         synchronized (this) {
582             notify();
583         }
584     }
585 
586     /** {@inheritDoc} */
notifyInstallingTimeout(final TestDevice testDevice)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} */
notifyUninstallingTimeout(final TestDevice testDevice)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      */
genPackageActionTimeoutCause(final TestDevice testDevice, String type)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} */
notifyTestingDeviceDisconnected()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      */
setTestDevice(final TestDevice device)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      */
getFullPath(String binaryFileName)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      */
install()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      */
uninstall()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      */
uninstallAPK(final String packageName)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      */
installAPK(final String apkPath)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      */
waitPackageActionComplete()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      */
genMessageDigest(final String packagePath)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      */
setSessionThread(TestSessionThread thread)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      */
supportsBatchMode()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      */
getPackageNames()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      */
runInBatchMode(final String javaPkgName)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      */
runInBatchModeImpl(String javaPkgName)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      */
runInIndividualMode(final String javaPkgName)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 
TimeOutTask(final TestPackage testPackage)921         public TimeOutTask(final TestPackage testPackage) {
922             mTestPackage = testPackage;
923         }
924 
925         @Override
run()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      */
killDeviceProcess(final String packageName)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      */
isAllTestsRun()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      */
noTestsExecuted()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      */
run(final TestDevice device, final String javaPkgName, TestSessionLog sessionLog)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      */
runImpl(final String javaPkgName)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      */
setup(final TestDevice device, final String javaPkgName)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      */
cleanUp()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      */
runTest(final TestDevice device, final Test test)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      */
runTestImpl(final Test test)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