blob: 4974a447be916748d0f5605b9bcb4ae7ae2a0bd8 [file] [log] [blame]
Joe Onorato0578cbc2016-10-19 17:03:06 -07001/*
2 * Copyright (C) 2016 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#include "aapt.h"
18#include "adb.h"
19#include "make.h"
20#include "print.h"
21#include "util.h"
22
23#include <sstream>
24#include <string>
25#include <vector>
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31
32#include <google/protobuf/stubs/common.h>
33
34using namespace std;
35
36/**
37 * An entry from the command line for something that will be built, installed,
38 * and/or tested.
39 */
40struct Target {
41 bool build;
42 bool install;
43 bool test;
44 string pattern;
45 string name;
46 vector<string> actions;
47 Module module;
48
49 int testActionCount;
50
51 int testPassCount;
52 int testFailCount;
53 bool actionsWithNoTests;
54
55 Target(bool b, bool i, bool t, const string& p);
56};
57
58Target::Target(bool b, bool i, bool t, const string& p)
59 :build(b),
60 install(i),
61 test(t),
62 pattern(p),
63 testActionCount(0),
64 testPassCount(0),
65 testFailCount(0),
66 actionsWithNoTests(false)
67{
68}
69
70/**
71 * Command line options.
72 */
73struct Options {
74 // For help
75 bool runHelp;
76
77 // For tab completion
78 bool runTab;
79 string tabPattern;
80
81 // For build/install/test
82 bool reboot;
83 vector<Target*> targets;
84
85 Options();
86 ~Options();
87};
88
89Options::Options()
90 :runHelp(false),
91 runTab(false),
92 reboot(false),
93 targets()
94{
95}
96
97Options::~Options()
98{
99}
100
101struct InstallApk
102{
103 TrackedFile file;
104 bool alwaysInstall;
105 bool installed;
106
107 InstallApk();
108 InstallApk(const InstallApk& that);
109 InstallApk(const string& filename, bool always);
110 ~InstallApk() {};
111};
112
113InstallApk::InstallApk()
114{
115}
116
117InstallApk::InstallApk(const InstallApk& that)
118 :file(that.file),
119 alwaysInstall(that.alwaysInstall),
120 installed(that.installed)
121{
122}
123
124InstallApk::InstallApk(const string& filename, bool always)
125 :file(filename),
126 alwaysInstall(always),
127 installed(false)
128{
129}
130
131
132/**
133 * Record for an test that is going to be launched.
134 */
135struct TestAction {
136 TestAction();
137
138 // The package name from the apk
139 string packageName;
140
141 // The test runner class
142 string runner;
143
144 // The test class, or none if all tests should be run
145 string className;
146
147 // The original target that requested this action
148 Target* target;
149
150 // The number of tests that passed
151 int passCount;
152
153 // The number of tests that failed
154 int failCount;
155};
156
157TestAction::TestAction()
158 :passCount(0),
159 failCount(0)
160{
161}
162
163/**
164 * Record for an activity that is going to be launched.
165 */
166struct ActivityAction {
167 // The package name from the apk
168 string packageName;
169
170 // The test class, or none if all tests should be run
171 string className;
172};
173
174/**
175 * Callback class for the am instrument command.
176 */
177class TestResults: public InstrumentationCallbacks
178{
179public:
180 virtual void OnTestStatus(TestStatus& status);
181 virtual void OnSessionStatus(SessionStatus& status);
182
183 /**
184 * Set the TestAction that the tests are for.
185 * It will be updated with statistics as the tests run.
186 */
187 void SetCurrentAction(TestAction* action);
188
189private:
190 TestAction* m_currentAction;
191};
192
193void
194TestResults::OnTestStatus(TestStatus& status)
195{
196 bool found;
197// printf("OnTestStatus\n");
198// status.PrintDebugString();
199 int32_t resultCode = status.has_results() ? status.result_code() : 0;
200
201 if (!status.has_results()) {
202 return;
203 }
204 const ResultsBundle &results = status.results();
205
206 int32_t currentTestNum = get_bundle_int(results, &found, "current", NULL);
207 if (!found) {
208 currentTestNum = -1;
209 }
210
211 int32_t testCount = get_bundle_int(results, &found, "numtests", NULL);
212 if (!found) {
213 testCount = -1;
214 }
215
216 string className = get_bundle_string(results, &found, "class", NULL);
217 if (!found) {
218 return;
219 }
220
221 string testName = get_bundle_string(results, &found, "test", NULL);
222 if (!found) {
223 return;
224 }
225
226 if (resultCode == 0) {
227 // test passed
228 m_currentAction->passCount++;
229 m_currentAction->target->testPassCount++;
230 } else if (resultCode == 1) {
231 // test starting
232 ostringstream line;
233 line << "Running";
234 if (currentTestNum > 0) {
235 line << ": " << currentTestNum;
236 if (testCount > 0) {
237 line << " of " << testCount;
238 }
239 }
240 line << ": " << m_currentAction->target->name << ':' << className << "\\#" << testName;
241 print_one_line("%s", line.str().c_str());
242 } else if (resultCode == -2) {
243 // test failed
244 m_currentAction->failCount++;
245 m_currentAction->target->testFailCount++;
246 printf("%s\n%sFailed: %s:%s\\#%s%s\n", g_escapeClearLine, g_escapeRedBold,
247 m_currentAction->target->name.c_str(), className.c_str(),
248 testName.c_str(), g_escapeEndColor);
249
250 string stack = get_bundle_string(results, &found, "stack", NULL);
251 if (found) {
252 printf("%s\n", stack.c_str());
253 }
254 }
255}
256
257void
258TestResults::OnSessionStatus(SessionStatus& /*status*/)
259{
260 //status.PrintDebugString();
261}
262
263void
264TestResults::SetCurrentAction(TestAction* action)
265{
266 m_currentAction = action;
267}
268
269/**
270 * Prints the usage statement / help text.
271 */
272static void
273print_usage(FILE* out) {
274 fprintf(out, "usage: bit OPTIONS PATTERN\n");
275 fprintf(out, "\n");
276 fprintf(out, " Build, sync and test android code.\n");
277 fprintf(out, "\n");
278 fprintf(out, " The -b -i and -t options allow you to specify which phases\n");
279 fprintf(out, " you want to run. If none of those options are given, then\n");
280 fprintf(out, " all phases are run. If any of these options are provided\n");
281 fprintf(out, " then only the listed phases are run.\n");
282 fprintf(out, "\n");
283 fprintf(out, " OPTIONS\n");
284 fprintf(out, " -b Run a build\n");
285 fprintf(out, " -i Install the targets\n");
286 fprintf(out, " -t Run the tests\n");
287 fprintf(out, "\n");
288 fprintf(out, " -r If the runtime needs to be restarted, do a full reboot\n");
289 fprintf(out, " instead\n");
290 fprintf(out, "\n");
291 fprintf(out, " PATTERN\n");
292 fprintf(out, " One or more targets to build, install and test. The target\n");
293 fprintf(out, " names are the names that appear in the LOCAL_MODULE or\n");
294 fprintf(out, " LOCAL_PACKAGE_NAME variables in Android.mk or Android.bp files.\n");
295 fprintf(out, "\n");
296 fprintf(out, " Building and installing\n");
297 fprintf(out, " -----------------------\n");
298 fprintf(out, " The modules specified will be built and then installed. If the\n");
299 fprintf(out, " files are on the system partition, they will be synced and the\n");
300 fprintf(out, " attached device rebooted. If they are APKs that aren't on the\n");
301 fprintf(out, " system partition they are installed with adb install.\n");
302 fprintf(out, "\n");
303 fprintf(out, " For example:\n");
304 fprintf(out, " bit framework\n");
305 fprintf(out, " Builds framework.jar, syncs the system partition and reboots.\n");
306 fprintf(out, "\n");
307 fprintf(out, " bit SystemUI\n");
308 fprintf(out, " Builds SystemUI.apk, syncs the system partition and reboots.\n");
309 fprintf(out, "\n");
310 fprintf(out, " bit CtsProtoTestCases\n");
311 fprintf(out, " Builds this CTS apk, adb installs it, but does not run any\n");
312 fprintf(out, " tests.\n");
313 fprintf(out, "\n");
314 fprintf(out, " Running Unit Tests\n");
315 fprintf(out, " ------------------\n");
316 fprintf(out, " To run a unit test, list the test class names and optionally the\n");
317 fprintf(out, " test method after the module.\n");
318 fprintf(out, "\n");
319 fprintf(out, " For example:\n");
320 fprintf(out, " bit CtsProtoTestCases:*\n");
321 fprintf(out, " Builds this CTS apk, adb installs it, and runs all the tests\n");
322 fprintf(out, " contained in that apk.\n");
323 fprintf(out, "\n");
324 fprintf(out, " bit framework CtsProtoTestCases:*\n");
325 fprintf(out, " Builds the framework and the apk, syncs and reboots, then\n");
326 fprintf(out, " adb installs CtsProtoTestCases.apk, and runs all tests \n");
327 fprintf(out, " contained in that apk.\n");
328 fprintf(out, "\n");
329 fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\n");
330 fprintf(out, " bit CtsProtoTestCases:android.util.proto.cts.ProtoOutputStreamBoolTest\n");
331 fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs all the\n");
332 fprintf(out, " tests in the ProtoOutputStreamBoolTest class.\n");
333 fprintf(out, "\n");
334 fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite\n");
335 fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
336 fprintf(out, " test method on that class.\n");
337 fprintf(out, "\n");
338 fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite,.ProtoOutputStreamBoolTest\\#testRepeated\n");
339 fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
340 fprintf(out, " and testRepeated test methods on that class.\n");
341 fprintf(out, "\n");
342 fprintf(out, " Launching an Activity\n");
343 fprintf(out, " ---------------------\n");
344 fprintf(out, " To launch an activity, specify the activity class name after\n");
345 fprintf(out, " the module name.\n");
346 fprintf(out, "\n");
347 fprintf(out, " For example:\n");
348 fprintf(out, " bit StatusBarTest:NotificationBuilderTest\n");
349 fprintf(out, " bit StatusBarTest:.NotificationBuilderTest\n");
350 fprintf(out, " bit StatusBarTest:com.android.statusbartest.NotificationBuilderTest\n");
351 fprintf(out, " Builds and installs StatusBarTest.apk, launches the\n");
352 fprintf(out, " com.android.statusbartest/.NotificationBuilderTest activity.\n");
353 fprintf(out, "\n");
354 fprintf(out, "\n");
355 fprintf(out, "usage: bit --tab ...\n");
356 fprintf(out, "\n");
357 fprintf(out, " Lists the targets in a format for tab completion. To get tab\n");
358 fprintf(out, " completion, add this to your bash environment:\n");
359 fprintf(out, "\n");
360 fprintf(out, " complete -C \"bit --tab\" bit\n");
361 fprintf(out, "\n");
362 fprintf(out, " Sourcing android's build/envsetup.sh will do this for you\n");
363 fprintf(out, " automatically.\n");
364 fprintf(out, "\n");
365 fprintf(out, "\n");
366 fprintf(out, "usage: bit --help\n");
367 fprintf(out, "usage: bit -h\n");
368 fprintf(out, "\n");
369 fprintf(out, " Print this help message\n");
370 fprintf(out, "\n");
371}
372
373
374/**
375 * Sets the appropriate flag* variables. If there is a problem with the
376 * commandline arguments, prints the help message and exits with an error.
377 */
378static void
379parse_args(Options* options, int argc, const char** argv)
380{
381 // Help
382 if (argc == 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
383 options->runHelp = true;
384 return;
385 }
386
387 // Tab
388 if (argc >= 4 && strcmp(argv[1], "--tab") == 0) {
389 options->runTab = true;
390 options->tabPattern = argv[3];
391 return;
392 }
393
394 // Normal usage
395 bool anyPhases = false;
396 bool gotPattern = false;
397 bool flagBuild = false;
398 bool flagInstall = false;
399 bool flagTest = false;
400 for (int i=1; i < argc; i++) {
401 string arg(argv[i]);
402 if (arg[0] == '-') {
403 for (size_t j=1; j<arg.size(); j++) {
404 switch (arg[j]) {
405 case '-':
406 break;
407 case 'b':
408 if (gotPattern) {
409 gotPattern = false;
410 flagInstall = false;
411 flagTest = false;
412 }
413 flagBuild = true;
414 anyPhases = true;
415 break;
416 case 'i':
417 if (gotPattern) {
418 gotPattern = false;
419 flagBuild = false;
420 flagTest = false;
421 }
422 flagInstall = true;
423 anyPhases = true;
424 break;
425 case 't':
426 if (gotPattern) {
427 gotPattern = false;
428 flagBuild = false;
429 flagInstall = false;
430 }
431 flagTest = true;
432 anyPhases = true;
433 break;
434 case 'r':
435 options->reboot = true;
436 break;
437 default:
438 fprintf(stderr, "Unrecognized option '%c'\n", arg[j]);
439 print_usage(stderr);
440 exit(1);
441 break;
442 }
443 }
444 } else {
445 Target* target = new Target(flagBuild || !anyPhases, flagInstall || !anyPhases,
446 flagTest || !anyPhases, arg);
447 size_t colonPos = arg.find(':');
448 if (colonPos == 0) {
449 fprintf(stderr, "Test / activity supplied without a module to build: %s\n",
450 arg.c_str());
451 print_usage(stderr);
452 exit(1);
453 } else if (colonPos == string::npos) {
454 target->name = arg;
455 } else {
456 target->name.assign(arg, 0, colonPos);
457 size_t beginPos = colonPos+1;
458 size_t commaPos;
459 while (true) {
460 commaPos = arg.find(',', beginPos);
461 if (commaPos == string::npos) {
462 if (beginPos != arg.size()) {
463 target->actions.push_back(string(arg, beginPos, commaPos));
464 }
465 break;
466 } else {
467 if (commaPos != beginPos) {
468 target->actions.push_back(string(arg, beginPos, commaPos-beginPos));
469 }
470 beginPos = commaPos+1;
471 }
472 }
473 }
474 options->targets.push_back(target);
475 gotPattern = true;
476 }
477 }
478 // If no pattern was supplied, give an error
479 if (options->targets.size() == 0) {
480 fprintf(stderr, "No PATTERN supplied.\n\n");
481 print_usage(stderr);
482 exit(1);
483 }
484}
485
486/**
487 * Get an environment variable.
488 * Exits with an error if it is unset or the empty string.
489 */
490static string
491get_required_env(const char* name, bool quiet)
492{
493 const char* value = getenv(name);
494 if (value == NULL || value[0] == '\0') {
495 if (!quiet) {
496 fprintf(stderr, "%s not set. Did you source build/envsetup.sh,"
497 " run lunch and do a build?\n", name);
498 }
499 exit(1);
500 }
501 return string(value);
502}
503
504/**
505 * Get the out directory.
506 *
507 * This duplicates the logic in build/make/core/envsetup.mk (which hasn't changed since 2011)
508 * so that we don't have to wait for get_build_var make invocation.
509 */
510string
511get_out_dir()
512{
513 const char* out_dir = getenv("OUT_DIR");
514 if (out_dir == NULL || out_dir[0] == '\0') {
515 const char* common_base = getenv("OUT_DIR_COMMON_BASE");
516 if (common_base == NULL || common_base[0] == '\0') {
517 // We don't prefix with buildTop because we cd there and it
518 // makes all the filenames long when being pretty printed.
519 return "out";
520 } else {
Joe Onorato8a5bb632016-10-21 14:31:42 -0700521 char pwd[PATH_MAX];
522 if (getcwd(pwd, PATH_MAX) == NULL) {
523 fprintf(stderr, "Your pwd is too long.\n");
524 exit(1);
525 }
Joe Onorato0578cbc2016-10-19 17:03:06 -0700526 const char* slash = strrchr(pwd, '/');
527 if (slash == NULL) {
528 slash = "";
529 }
530 string result(common_base);
531 result += slash;
Joe Onorato0578cbc2016-10-19 17:03:06 -0700532 return result;
533 }
534 }
535 return string(out_dir);
536}
537
538/**
539 * Check that a system property on the device matches the expected value.
540 * Exits with an error if they don't.
541 */
542static void
543check_device_property(const string& property, const string& expected)
544{
545 int err;
546 string deviceValue = get_system_property(property, &err);
547 check_error(err);
548 if (deviceValue != expected) {
549 print_error("There is a mismatch between the build you just did and the device you");
550 print_error("are trying to sync it to in the %s system property", property.c_str());
551 print_error(" build: %s", expected.c_str());
552 print_error(" device: %s", deviceValue.c_str());
553 exit(1);
554 }
555}
556
557/**
558 * Run the build, install, and test actions.
559 */
560void
561run_phases(vector<Target*> targets, bool reboot)
562{
563 int err = 0;
564
565 //
566 // Initialization
567 //
568
569 print_status("Initializing");
570
571 const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
572 const string buildProduct = get_required_env("TARGET_PRODUCT", false);
573 const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
574 const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
575 const string buildDevice = get_build_var(buildTop, "TARGET_DEVICE", false);
576 const string buildId = get_build_var(buildTop, "BUILD_ID", false);
577 const string buildOut = get_out_dir();
578
579 // TODO: print_command("cd", buildTop.c_str());
580 chdir(buildTop.c_str());
581
582 // Get the modules for the targets
583 map<string,Module> modules;
584 read_modules(buildOut, buildDevice, &modules, false);
585 for (size_t i=0; i<targets.size(); i++) {
586 Target* target = targets[i];
587 map<string,Module>::iterator mod = modules.find(target->name);
588 if (mod != modules.end()) {
589 target->module = mod->second;
590 } else {
591 print_error("Error: Could not find module: %s", target->name.c_str());
592 err = 1;
593 }
594 }
595 if (err != 0) {
596 exit(1);
597 }
598
599 // Choose the goals
600 vector<string> goals;
601 for (size_t i=0; i<targets.size(); i++) {
602 Target* target = targets[i];
603 if (target->build) {
604 goals.push_back(target->name);
605 }
606 }
607
608 // Figure out whether we need to sync the system and which apks to install
609 string systemPath = buildOut + "/target/product/" + buildDevice + "/system/";
610 string dataPath = buildOut + "/target/product/" + buildDevice + "/data/";
611 bool syncSystem = false;
612 bool alwaysSyncSystem = false;
613 vector<InstallApk> installApks;
614 for (size_t i=0; i<targets.size(); i++) {
615 Target* target = targets[i];
616 if (target->install) {
617 for (size_t j=0; j<target->module.installed.size(); j++) {
618 const string& file = target->module.installed[j];
619 // System partition
620 if (starts_with(file, systemPath)) {
621 syncSystem = true;
622 if (!target->build) {
623 // If a system partition target didn't get built then
624 // it won't change we will always need to do adb sync
625 alwaysSyncSystem = true;
626 }
627 continue;
628 }
629 // Apk in the data partition
630 if (starts_with(file, dataPath) && ends_with(file, ".apk")) {
631 // Always install it if we didn't build it because otherwise
632 // it will never have changed.
633 installApks.push_back(InstallApk(file, !target->build));
634 continue;
635 }
636 }
637 }
638 }
639 map<string,FileInfo> systemFilesBefore;
640 if (syncSystem && !alwaysSyncSystem) {
641 get_directory_contents(systemPath, &systemFilesBefore);
642 }
643
644 //
645 // Build
646 //
647
648 // Run the build
649 if (goals.size() > 0) {
650 print_status("Building");
651 err = build_goals(goals);
652 check_error(err);
653 }
654
655 //
656 // Install
657 //
658
659 // Sync the system partition and reboot
660 bool skipSync = false;
661 if (syncSystem) {
662 print_status("Syncing /system");
663
664 if (!alwaysSyncSystem) {
665 // If nothing changed and we weren't forced to sync, skip the reboot for speed.
666 map<string,FileInfo> systemFilesAfter;
667 get_directory_contents(systemPath, &systemFilesAfter);
668 skipSync = !directory_contents_differ(systemFilesBefore, systemFilesAfter);
669 }
670 if (skipSync) {
671 printf("Skipping sync because no files changed.\n");
672 } else {
673 // Do some sanity checks
674 check_device_property("ro.build.product", buildProduct);
675 check_device_property("ro.build.type", buildVariant);
676 check_device_property("ro.build.id", buildId);
677
678 // Stop & Sync
679 err = run_adb("shell", "stop", NULL);
680 check_error(err);
681 err = run_adb("remount", NULL);
682 check_error(err);
683 err = run_adb("sync", "system", NULL);
684 check_error(err);
685
686 if (reboot) {
687 print_status("Rebooting");
688
689 err = run_adb("reboot", NULL);
690 check_error(err);
691 err = run_adb("wait-for-device", NULL);
692 check_error(err);
693 } else {
694 print_status("Restarting the runtime");
695
696 err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
697 check_error(err);
698 err = run_adb("shell", "start", NULL);
699 check_error(err);
700 }
701
702 while (true) {
703 string completed = get_system_property("sys.boot_completed", &err);
704 check_error(err);
705 if (completed == "1") {
706 break;
707 }
708 sleep(2);
709 }
710 sleep(1);
711 err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
712 check_error(err);
713 }
714 }
715
716 // Install APKs
717 if (installApks.size() > 0) {
718 print_status("Installing APKs");
719 for (size_t i=0; i<installApks.size(); i++) {
720 InstallApk& apk = installApks[i];
721 if (!apk.file.fileInfo.exists || apk.file.HasChanged()) {
722 // It didn't exist before or it changed, so int needs install
723 err = run_adb("install", "-r", apk.file.filename.c_str(), NULL);
724 check_error(err);
725 apk.installed = true;
726 } else {
727 printf("APK didn't change. Skipping install of %s\n", apk.file.filename.c_str());
728 }
729 }
730 }
731
732 //
733 // Actions
734 //
735
736 // Inspect the apks, and figure out what is an activity and what needs a test runner
737 bool printedInspecting = false;
738 vector<TestAction> testActions;
739 vector<ActivityAction> activityActions;
740 for (size_t i=0; i<targets.size(); i++) {
741 Target* target = targets[i];
742 if (target->test) {
743 for (size_t j=0; j<target->module.installed.size(); j++) {
744 string filename = target->module.installed[j];
745
746 if (!ends_with(filename, ".apk")) {
747 continue;
748 }
749
750 if (!printedInspecting) {
751 printedInspecting = true;
752 print_status("Inspecting APKs");
753 }
754
755 Apk apk;
756 err = inspect_apk(&apk, filename);
757 check_error(err);
758
759 for (size_t k=0; k<target->actions.size(); k++) {
760 string actionString = target->actions[k];
761 if (actionString == "*") {
762 if (apk.runner.length() == 0) {
763 print_error("Error: Test requested for apk that doesn't"
764 " have an <instrumentation> tag: %s\n",
765 target->module.name.c_str());
766 exit(1);
767 }
768 TestAction action;
769 action.packageName = apk.package;
770 action.runner = apk.runner;
771 action.target = target;
772 testActions.push_back(action);
773 target->testActionCount++;
774 } else if (apk.HasActivity(actionString)) {
775 ActivityAction action;
776 action.packageName = apk.package;
777 action.className = full_class_name(apk.package, actionString);
778 activityActions.push_back(action);
779 } else {
780 if (apk.runner.length() == 0) {
781 print_error("Error: Test requested for apk that doesn't"
782 " have an <instrumentation> tag: %s\n",
783 target->module.name.c_str());
784 exit(1);
785 }
786 TestAction action;
787 action.packageName = apk.package;
788 action.runner = apk.runner;
789 action.className = full_class_name(apk.package, actionString);
790 action.target = target;
791 testActions.push_back(action);
792 target->testActionCount++;
793 }
794 }
795 }
796 }
797 }
798
799 // Run the instrumentation tests
800 TestResults testResults;
801 if (testActions.size() > 0) {
802 print_status("Running tests");
803 for (size_t i=0; i<testActions.size(); i++) {
804 TestAction& action = testActions[i];
805 testResults.SetCurrentAction(&action);
806 err = run_instrumentation_test(action.packageName, action.runner, action.className,
807 &testResults);
808 check_error(err);
809 if (action.passCount == 0 && action.failCount == 0) {
810 action.target->actionsWithNoTests = true;
811 }
812 int total = action.passCount + action.failCount;
813 printf("%sRan %d test%s for %s. ", g_escapeClearLine,
814 total, total > 1 ? "s" : "", action.target->name.c_str());
815 if (action.passCount == 0 && action.failCount == 0) {
816 printf("%s%d passed, %d failed%s\n", g_escapeYellowBold, action.passCount,
817 action.failCount, g_escapeEndColor);
818 } else if (action.failCount > 0) {
819 printf("%d passed, %s%d failed%s\n", action.passCount, g_escapeRedBold,
820 action.failCount, g_escapeEndColor);
821 } else {
822 printf("%s%d passed%s, %d failed\n", g_escapeGreenBold, action.passCount,
823 g_escapeEndColor, action.failCount);
824 }
825 }
826 }
827
828 // Launch the activity
829 if (activityActions.size() > 0) {
830 print_status("Starting activity");
831
832 if (activityActions.size() > 1) {
833 print_warning("Multiple activities specified. Will only start the first one:");
834 for (size_t i=0; i<activityActions.size(); i++) {
835 ActivityAction& action = activityActions[i];
836 print_warning(" %s",
837 pretty_component_name(action.packageName, action.className).c_str());
838 }
839 }
840
841 const ActivityAction& action = activityActions[0];
842 string componentName = action.packageName + "/" + action.className;
843 err = run_adb("shell", "am", "start", componentName.c_str(), NULL);
844 check_error(err);
845 }
846
847 //
848 // Print summary
849 //
850
851 printf("\n%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
852
853 // Build
854 if (goals.size() > 0) {
855 printf("%sBuilt:%s\n", g_escapeBold, g_escapeEndColor);
856 for (size_t i=0; i<goals.size(); i++) {
857 printf(" %s\n", goals[i].c_str());
858 }
859 }
860
861 // Install
862 if (syncSystem) {
863 if (skipSync) {
864 printf("%sSkipped syncing /system partition%s\n", g_escapeBold, g_escapeEndColor);
865 } else {
866 printf("%sSynced /system partition%s\n", g_escapeBold, g_escapeEndColor);
867 }
868 }
869 if (installApks.size() > 0) {
870 bool printedTitle = false;
871 for (size_t i=0; i<installApks.size(); i++) {
872 const InstallApk& apk = installApks[i];
873 if (apk.installed) {
874 if (!printedTitle) {
875 printf("%sInstalled:%s\n", g_escapeBold, g_escapeEndColor);
876 printedTitle = true;
877 }
878 printf(" %s\n", apk.file.filename.c_str());
879 }
880 }
881 printedTitle = false;
882 for (size_t i=0; i<installApks.size(); i++) {
883 const InstallApk& apk = installApks[i];
884 if (!apk.installed) {
885 if (!printedTitle) {
886 printf("%sSkipped install:%s\n", g_escapeBold, g_escapeEndColor);
887 printedTitle = true;
888 }
889 printf(" %s\n", apk.file.filename.c_str());
890 }
891 }
892 }
893
894 // Tests
895 if (testActions.size() > 0) {
896 printf("%sRan tests:%s\n", g_escapeBold, g_escapeEndColor);
897 size_t maxNameLength = 0;
898 for (size_t i=0; i<targets.size(); i++) {
899 Target* target = targets[i];
900 if (target->test) {
901 size_t len = target->name.length();
902 if (len > maxNameLength) {
903 maxNameLength = len;
904 }
905 }
906 }
907 string padding(maxNameLength, ' ');
908 for (size_t i=0; i<targets.size(); i++) {
909 Target* target = targets[i];
910 if (target->testActionCount > 0) {
911 printf(" %s%s", target->name.c_str(), padding.c_str() + target->name.length());
912 if (target->actionsWithNoTests) {
913 printf(" %s%d passed, %d failed%s\n", g_escapeYellowBold,
914 target->testPassCount, target->testFailCount, g_escapeEndColor);
915 } else if (target->testFailCount > 0) {
916 printf(" %d passed, %s%d failed%s\n", target->testPassCount,
917 g_escapeRedBold, target->testFailCount, g_escapeEndColor);
918 } else {
919 printf(" %s%d passed%s, %d failed\n", g_escapeGreenBold,
920 target->testPassCount, g_escapeEndColor, target->testFailCount);
921 }
922 }
923 }
924 }
925 if (activityActions.size() > 1) {
926 printf("%sStarted Activity:%s\n", g_escapeBold, g_escapeEndColor);
927 const ActivityAction& action = activityActions[0];
928 printf(" %s\n", pretty_component_name(action.packageName, action.className).c_str());
929 }
930
931 printf("%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
932}
933
934/**
935 * Implement tab completion of the target names from the all modules file.
936 */
937void
938run_tab_completion(const string& word)
939{
940 const string buildTop = get_required_env("ANDROID_BUILD_TOP", true);
941 const string buildProduct = get_required_env("TARGET_PRODUCT", false);
942 const string buildOut = get_out_dir();
943
944 chdir(buildTop.c_str());
945
946 string buildDevice = sniff_device_name(buildOut, buildProduct);
947
948 map<string,Module> modules;
949 read_modules(buildOut, buildDevice, &modules, true);
950
951 for (map<string,Module>::const_iterator it = modules.begin(); it != modules.end(); it++) {
952 if (starts_with(it->first, word)) {
953 printf("%s\n", it->first.c_str());
954 }
955 }
956}
957
958/**
959 * Main entry point.
960 */
961int
962main(int argc, const char** argv)
963{
964 GOOGLE_PROTOBUF_VERIFY_VERSION;
965 init_print();
966
967 Options options;
968 parse_args(&options, argc, argv);
969
970 if (options.runHelp) {
971 // Help
972 print_usage(stdout);
973 exit(0);
974 } else if (options.runTab) {
975 run_tab_completion(options.tabPattern);
976 exit(0);
977 } else {
978 // Normal run
979 run_phases(options.targets, options.reboot);
980 }
981
982 return 0;
983}
984