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