1 /*
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
34 using namespace std;
35
36 #define NATIVE_TESTS "NATIVE_TESTS"
37
38 /**
39 * An entry from the command line for something that will be built, installed,
40 * and/or tested.
41 */
42 struct Target {
43 bool build;
44 bool install;
45 bool test;
46 string pattern;
47 string name;
48 vector<string> actions;
49 Module module;
50
51 int testActionCount;
52
53 int testPassCount;
54 int testFailCount;
55 int testIgnoreCount;
56 int unknownFailureCount; // unknown failure == "Process crashed", etc.
57
58 Target(bool b, bool i, bool t, const string& p);
59 };
60
Target(bool b,bool i,bool t,const string & p)61 Target::Target(bool b, bool i, bool t, const string& p)
62 : build(b),
63 install(i),
64 test(t),
65 pattern(p),
66 testActionCount(0),
67 testPassCount(0),
68 testFailCount(0),
69 testIgnoreCount(0),
70 unknownFailureCount(0) {}
71
72 /**
73 * Command line options.
74 */
75 struct Options {
76 // For help
77 bool runHelp;
78
79 // For refreshing module-info.json
80 bool runRefresh;
81
82 // For tab completion
83 bool runTab;
84 string tabPattern;
85
86 // For build/install/test
87 bool noRestart;
88 bool reboot;
89 vector<Target*> targets;
90
91 Options();
92 ~Options();
93 };
94
Options()95 Options::Options()
96 :runHelp(false),
97 runRefresh(false),
98 runTab(false),
99 noRestart(false),
100 reboot(false),
101 targets()
102 {
103 }
104
~Options()105 Options::~Options()
106 {
107 }
108
109 struct InstallApk
110 {
111 TrackedFile file;
112 bool alwaysInstall;
113 bool installed;
114
115 InstallApk();
116 InstallApk(const InstallApk& that);
117 InstallApk(const string& filename, bool always);
~InstallApkInstallApk118 ~InstallApk() {};
119 };
120
InstallApk()121 InstallApk::InstallApk()
122 {
123 }
124
InstallApk(const InstallApk & that)125 InstallApk::InstallApk(const InstallApk& that)
126 :file(that.file),
127 alwaysInstall(that.alwaysInstall),
128 installed(that.installed)
129 {
130 }
131
InstallApk(const string & filename,bool always)132 InstallApk::InstallApk(const string& filename, bool always)
133 :file(filename),
134 alwaysInstall(always),
135 installed(false)
136 {
137 }
138
139 struct PushedFile
140 {
141 TrackedFile file;
142 string dest;
143
144 PushedFile();
145 PushedFile(const PushedFile& that);
146 PushedFile(const string& filename, const string& dest);
~PushedFilePushedFile147 ~PushedFile() {};
148 };
149
PushedFile()150 PushedFile::PushedFile()
151 {
152 }
153
PushedFile(const PushedFile & that)154 PushedFile::PushedFile(const PushedFile& that)
155 :file(that.file),
156 dest(that.dest)
157 {
158 }
159
PushedFile(const string & f,const string & d)160 PushedFile::PushedFile(const string& f, const string& d)
161 :file(f),
162 dest(d)
163 {
164 }
165
166 /**
167 * Record for an test that is going to be launched.
168 */
169 struct TestAction {
170 TestAction();
171
172 // The package name from the apk
173 string packageName;
174
175 // The test runner class
176 string runner;
177
178 // The test class, or none if all tests should be run
179 string className;
180
181 // The original target that requested this action
182 Target* target;
183
184 // The number of tests that passed
185 int passCount;
186
187 // The number of tests that failed
188 int failCount;
189
190 // The number of tests that were ignored (because of @Ignore)
191 int ignoreCount;
192 };
193
TestAction()194 TestAction::TestAction() : passCount(0), failCount(0), ignoreCount(0) {}
195
196 /**
197 * Record for an activity that is going to be launched.
198 */
199 struct ActivityAction {
200 // The package name from the apk
201 string packageName;
202
203 // The test class, or none if all tests should be run
204 string className;
205 };
206
207 /**
208 * Callback class for the am instrument command.
209 */
210 class TestResults: public InstrumentationCallbacks
211 {
212 public:
213 virtual void OnTestStatus(TestStatus& status);
214 virtual void OnSessionStatus(SessionStatus& status);
215
216 /**
217 * Set the TestAction that the tests are for.
218 * It will be updated with statistics as the tests run.
219 */
220 void SetCurrentAction(TestAction* action);
221
222 bool IsSuccess();
223
224 string GetErrorMessage();
225
226 private:
227 TestAction* m_currentAction;
228 SessionStatus m_sessionStatus;
229 };
230
231 void
OnTestStatus(TestStatus & status)232 TestResults::OnTestStatus(TestStatus& status)
233 {
234 bool found;
235 // printf("OnTestStatus\n");
236 // status.PrintDebugString();
237 int32_t resultCode = status.has_results() ? status.result_code() : 0;
238
239 if (!status.has_results()) {
240 return;
241 }
242 const ResultsBundle &results = status.results();
243
244 int32_t currentTestNum = get_bundle_int(results, &found, "current", NULL);
245 if (!found) {
246 currentTestNum = -1;
247 }
248
249 int32_t testCount = get_bundle_int(results, &found, "numtests", NULL);
250 if (!found) {
251 testCount = -1;
252 }
253
254 string className = get_bundle_string(results, &found, "class", NULL);
255 if (!found) {
256 return;
257 }
258
259 string testName = get_bundle_string(results, &found, "test", NULL);
260 if (!found) {
261 return;
262 }
263
264 if (resultCode == 0) {
265 // test passed
266 m_currentAction->passCount++;
267 m_currentAction->target->testPassCount++;
268 } else if (resultCode == 1) {
269 // test starting
270 ostringstream line;
271 line << "Running";
272 if (currentTestNum > 0) {
273 line << ": " << currentTestNum;
274 if (testCount > 0) {
275 line << " of " << testCount;
276 }
277 }
278 line << ": " << m_currentAction->target->name << ':' << className << "#" << testName;
279 print_one_line("%s", line.str().c_str());
280 } else if ((resultCode == -1) || (resultCode == -2)) {
281 // test failed
282 // Note -2 means an assertion failure, and -1 means other exceptions. We just treat them
283 // all as "failures".
284 m_currentAction->failCount++;
285 m_currentAction->target->testFailCount++;
286 printf("%s\n%sFailed: %s:%s#%s%s\n", g_escapeClearLine, g_escapeRedBold,
287 m_currentAction->target->name.c_str(), className.c_str(), testName.c_str(),
288 g_escapeEndColor);
289
290 bool stackFound;
291 string stack = get_bundle_string(results, &stackFound, "stack", NULL);
292 if (status.has_logcat()) {
293 const string logcat = status.logcat();
294 if (logcat.length() > 0) {
295 printf("%s\n", logcat.c_str());
296 }
297 } else if (stackFound) {
298 printf("%s\n", stack.c_str());
299 }
300 } else if (resultCode == -3) {
301 // test ignored
302 m_currentAction->ignoreCount++;
303 m_currentAction->target->testIgnoreCount++;
304 printf("%s\n%sIgnored: %s:%s#%s%s\n", g_escapeClearLine, g_escapeYellowBold,
305 m_currentAction->target->name.c_str(), className.c_str(), testName.c_str(),
306 g_escapeEndColor);
307 }
308 }
309
310 void
OnSessionStatus(SessionStatus & status)311 TestResults::OnSessionStatus(SessionStatus& status)
312 {
313 //status.PrintDebugString();
314 m_sessionStatus = status;
315 if (m_currentAction && !IsSuccess()) {
316 m_currentAction->target->unknownFailureCount++;
317 }
318 }
319
320 void
SetCurrentAction(TestAction * action)321 TestResults::SetCurrentAction(TestAction* action)
322 {
323 m_currentAction = action;
324 }
325
326 bool
IsSuccess()327 TestResults::IsSuccess()
328 {
329 return m_sessionStatus.result_code() == -1; // Activity.RESULT_OK.
330 }
331
332 string
GetErrorMessage()333 TestResults::GetErrorMessage()
334 {
335 bool found;
336 string shortMsg = get_bundle_string(m_sessionStatus.results(), &found, "shortMsg", NULL);
337 if (!found) {
338 return IsSuccess() ? "" : "Unknown failure";
339 }
340 return shortMsg;
341 }
342
343
344 /**
345 * Prints the usage statement / help text.
346 */
347 static void
print_usage(FILE * out)348 print_usage(FILE* out) {
349 fprintf(out, "usage: bit OPTIONS PATTERN\n");
350 fprintf(out, "\n");
351 fprintf(out, " Build, sync and test android code.\n");
352 fprintf(out, "\n");
353 fprintf(out, " The -b -i and -t options allow you to specify which phases\n");
354 fprintf(out, " you want to run. If none of those options are given, then\n");
355 fprintf(out, " all phases are run. If any of these options are provided\n");
356 fprintf(out, " then only the listed phases are run.\n");
357 fprintf(out, "\n");
358 fprintf(out, " OPTIONS\n");
359 fprintf(out, " -b Run a build\n");
360 fprintf(out, " -i Install the targets\n");
361 fprintf(out, " -t Run the tests\n");
362 fprintf(out, "\n");
363 fprintf(out, " -n Don't reboot or restart\n");
364 fprintf(out, " -r If the runtime needs to be restarted, do a full reboot\n");
365 fprintf(out, " instead\n");
366 fprintf(out, "\n");
367 fprintf(out, " PATTERN\n");
368 fprintf(out, " One or more targets to build, install and test. The target\n");
369 fprintf(out, " names are the names that appear in the LOCAL_MODULE or\n");
370 fprintf(out, " LOCAL_PACKAGE_NAME variables in Android.mk or Android.bp files.\n");
371 fprintf(out, "\n");
372 fprintf(out, " Building and installing\n");
373 fprintf(out, " -----------------------\n");
374 fprintf(out, " The modules specified will be built and then installed. If the\n");
375 fprintf(out, " files are on the system partition, they will be synced and the\n");
376 fprintf(out, " attached device rebooted. If they are APKs that aren't on the\n");
377 fprintf(out, " system partition they are installed with adb install.\n");
378 fprintf(out, "\n");
379 fprintf(out, " For example:\n");
380 fprintf(out, " bit framework\n");
381 fprintf(out, " Builds framework.jar, syncs the system partition and reboots.\n");
382 fprintf(out, "\n");
383 fprintf(out, " bit SystemUI\n");
384 fprintf(out, " Builds SystemUI.apk, syncs the system partition and reboots.\n");
385 fprintf(out, "\n");
386 fprintf(out, " bit CtsProtoTestCases\n");
387 fprintf(out, " Builds this CTS apk, adb installs it, but does not run any\n");
388 fprintf(out, " tests.\n");
389 fprintf(out, "\n");
390 fprintf(out, " Running Unit Tests\n");
391 fprintf(out, " ------------------\n");
392 fprintf(out, " To run a unit test, list the test class names and optionally the\n");
393 fprintf(out, " test method after the module.\n");
394 fprintf(out, "\n");
395 fprintf(out, " For example:\n");
396 fprintf(out, " bit CtsProtoTestCases:*\n");
397 fprintf(out, " Builds this CTS apk, adb installs it, and runs all the tests\n");
398 fprintf(out, " contained in that apk.\n");
399 fprintf(out, "\n");
400 fprintf(out, " bit framework CtsProtoTestCases:*\n");
401 fprintf(out, " Builds the framework and the apk, syncs and reboots, then\n");
402 fprintf(out, " adb installs CtsProtoTestCases.apk, and runs all tests \n");
403 fprintf(out, " contained in that apk.\n");
404 fprintf(out, "\n");
405 fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\n");
406 fprintf(out, " bit CtsProtoTestCases:android.util.proto.cts.ProtoOutputStreamBoolTest\n");
407 fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs all the\n");
408 fprintf(out, " tests in the ProtoOutputStreamBoolTest class.\n");
409 fprintf(out, "\n");
410 fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest#testWrite\n");
411 fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
412 fprintf(out, " test method on that class.\n");
413 fprintf(out, "\n");
414 fprintf(out,
415 " bit "
416 "CtsProtoTestCases:.ProtoOutputStreamBoolTest#testWrite,.ProtoOutputStreamBoolTest#"
417 "testRepeated\n");
418 fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
419 fprintf(out, " and testRepeated test methods on that class.\n");
420 fprintf(out, "\n");
421 fprintf(out, " bit CtsProtoTestCases:android.util.proto.cts.\n");
422 fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs the tests in the java package\n");
423 fprintf(out, " \"android.util.proto.cts\".\n");
424 fprintf(out, "\n");
425 fprintf(out, " Launching an Activity\n");
426 fprintf(out, " ---------------------\n");
427 fprintf(out, " To launch an activity, specify the activity class name after\n");
428 fprintf(out, " the module name.\n");
429 fprintf(out, "\n");
430 fprintf(out, " For example:\n");
431 fprintf(out, " bit StatusBarTest:NotificationBuilderTest\n");
432 fprintf(out, " bit StatusBarTest:.NotificationBuilderTest\n");
433 fprintf(out, " bit StatusBarTest:com.android.statusbartest.NotificationBuilderTest\n");
434 fprintf(out, " Builds and installs StatusBarTest.apk, launches the\n");
435 fprintf(out, " com.android.statusbartest/.NotificationBuilderTest activity.\n");
436 fprintf(out, "\n");
437 fprintf(out, "\n");
438 fprintf(out, "usage: bit --refresh\n");
439 fprintf(out, "\n");
440 fprintf(out, " Update module-info.json, the cache of make goals that can be built.\n");
441 fprintf(out, "\n");
442 fprintf(out, "usage: bit --tab ...\n");
443 fprintf(out, "\n");
444 fprintf(out, " Lists the targets in a format for tab completion. To get tab\n");
445 fprintf(out, " completion, add this to your bash environment:\n");
446 fprintf(out, "\n");
447 fprintf(out, " complete -C \"bit --tab\" bit\n");
448 fprintf(out, "\n");
449 fprintf(out, " Sourcing android's build/envsetup.sh will do this for you\n");
450 fprintf(out, " automatically.\n");
451 fprintf(out, "\n");
452 fprintf(out, "\n");
453 fprintf(out, "usage: bit --help\n");
454 fprintf(out, "usage: bit -h\n");
455 fprintf(out, "\n");
456 fprintf(out, " Print this help message\n");
457 fprintf(out, "\n");
458 }
459
460 /**
461 * Prints a possibly color-coded summary of test results. Example output:
462 *
463 * "34 passed, 0 failed, 1 ignored\n"
464 */
print_results(int passed,int failed,int ignored)465 static void print_results(int passed, int failed, int ignored) {
466 char const* nothing = "";
467 char const* cp = nothing;
468 char const* cf = nothing;
469 char const* ci = nothing;
470
471 if (failed > 0) {
472 cf = g_escapeRedBold;
473 } else if (passed > 0 || ignored > 0) {
474 cp = passed > 0 ? g_escapeGreenBold : nothing;
475 ci = ignored > 0 ? g_escapeYellowBold : nothing;
476 } else {
477 cp = g_escapeYellowBold;
478 cf = g_escapeYellowBold;
479 }
480
481 if (ignored > 0) {
482 printf("%s%d passed%s, %s%d failed%s, %s%d ignored%s\n", cp, passed, g_escapeEndColor, cf,
483 failed, g_escapeEndColor, ci, ignored, g_escapeEndColor);
484 } else {
485 printf("%s%d passed%s, %s%d failed%s\n", cp, passed, g_escapeEndColor, cf, failed,
486 g_escapeEndColor);
487 }
488 }
489
490 /**
491 * Sets the appropriate flag* variables. If there is a problem with the
492 * commandline arguments, prints the help message and exits with an error.
493 */
494 static void
parse_args(Options * options,int argc,const char ** argv)495 parse_args(Options* options, int argc, const char** argv)
496 {
497 // Help
498 if (argc == 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
499 options->runHelp = true;
500 return;
501 }
502
503 // Refresh
504 if (argc == 2 && strcmp(argv[1], "--refresh") == 0) {
505 options->runRefresh = true;
506 return;
507 }
508
509 // Tab
510 if (argc >= 4 && strcmp(argv[1], "--tab") == 0) {
511 options->runTab = true;
512 options->tabPattern = argv[3];
513 return;
514 }
515
516 // Normal usage
517 bool anyPhases = false;
518 bool gotPattern = false;
519 bool flagBuild = false;
520 bool flagInstall = false;
521 bool flagTest = false;
522 for (int i=1; i < argc; i++) {
523 string arg(argv[i]);
524 if (arg[0] == '-') {
525 for (size_t j=1; j<arg.size(); j++) {
526 switch (arg[j]) {
527 case '-':
528 break;
529 case 'b':
530 if (gotPattern) {
531 gotPattern = false;
532 flagInstall = false;
533 flagTest = false;
534 }
535 flagBuild = true;
536 anyPhases = true;
537 break;
538 case 'i':
539 if (gotPattern) {
540 gotPattern = false;
541 flagBuild = false;
542 flagTest = false;
543 }
544 flagInstall = true;
545 anyPhases = true;
546 break;
547 case 't':
548 if (gotPattern) {
549 gotPattern = false;
550 flagBuild = false;
551 flagInstall = false;
552 }
553 flagTest = true;
554 anyPhases = true;
555 break;
556 case 'n':
557 options->noRestart = true;
558 break;
559 case 'r':
560 options->reboot = true;
561 break;
562 default:
563 fprintf(stderr, "Unrecognized option '%c'\n", arg[j]);
564 print_usage(stderr);
565 exit(1);
566 break;
567 }
568 }
569 } else {
570 Target* target = new Target(flagBuild || !anyPhases, flagInstall || !anyPhases,
571 flagTest || !anyPhases, arg);
572 size_t colonPos = arg.find(':');
573 if (colonPos == 0) {
574 fprintf(stderr, "Test / activity supplied without a module to build: %s\n",
575 arg.c_str());
576 print_usage(stderr);
577 delete target;
578 exit(1);
579 } else if (colonPos == string::npos) {
580 target->name = arg;
581 } else {
582 target->name.assign(arg, 0, colonPos);
583 size_t beginPos = colonPos+1;
584 size_t commaPos;
585 while (true) {
586 commaPos = arg.find(',', beginPos);
587 if (commaPos == string::npos) {
588 if (beginPos != arg.size()) {
589 target->actions.push_back(string(arg, beginPos, commaPos));
590 }
591 break;
592 } else {
593 if (commaPos != beginPos) {
594 target->actions.push_back(string(arg, beginPos, commaPos-beginPos));
595 }
596 beginPos = commaPos+1;
597 }
598 }
599 }
600 options->targets.push_back(target);
601 gotPattern = true;
602 }
603 }
604 // If no pattern was supplied, give an error
605 if (options->targets.size() == 0) {
606 fprintf(stderr, "No PATTERN supplied.\n\n");
607 print_usage(stderr);
608 exit(1);
609 }
610 }
611
612 /**
613 * Get an environment variable.
614 * Exits with an error if it is unset or the empty string.
615 */
616 static string
get_required_env(const char * name,bool quiet)617 get_required_env(const char* name, bool quiet)
618 {
619 const char* value = getenv(name);
620 if (value == NULL || value[0] == '\0') {
621 if (!quiet) {
622 fprintf(stderr, "%s not set. Did you source build/envsetup.sh,"
623 " run lunch and do a build?\n", name);
624 }
625 exit(1);
626 }
627 return string(value);
628 }
629
630 /**
631 * Get the out directory.
632 *
633 * This duplicates the logic in build/make/core/envsetup.mk (which hasn't changed since 2011)
634 * so that we don't have to wait for get_build_var make invocation.
635 */
636 string
get_out_dir()637 get_out_dir()
638 {
639 const char* out_dir = getenv("OUT_DIR");
640 if (out_dir == NULL || out_dir[0] == '\0') {
641 const char* common_base = getenv("OUT_DIR_COMMON_BASE");
642 if (common_base == NULL || common_base[0] == '\0') {
643 // We don't prefix with buildTop because we cd there and it
644 // makes all the filenames long when being pretty printed.
645 return "out";
646 } else {
647 char pwd[PATH_MAX];
648 if (getcwd(pwd, PATH_MAX) == NULL) {
649 fprintf(stderr, "Your pwd is too long.\n");
650 exit(1);
651 }
652 const char* slash = strrchr(pwd, '/');
653 if (slash == NULL) {
654 slash = "";
655 }
656 string result(common_base);
657 result += slash;
658 return result;
659 }
660 }
661 return string(out_dir);
662 }
663
664 /**
665 * Check that a system property on the device matches the expected value.
666 * Exits with an error if they don't.
667 */
668 static void
check_device_property(const string & property,const string & expected)669 check_device_property(const string& property, const string& expected)
670 {
671 int err;
672 string deviceValue = get_system_property(property, &err);
673 check_error(err);
674 if (deviceValue != expected) {
675 print_error("There is a mismatch between the build you just did and the device you");
676 print_error("are trying to sync it to in the %s system property", property.c_str());
677 print_error(" build: %s", expected.c_str());
678 print_error(" device: %s", deviceValue.c_str());
679 exit(1);
680 }
681 }
682
683 static void
chdir_or_exit(const char * path)684 chdir_or_exit(const char *path) {
685 // TODO: print_command("cd", path);
686 if (0 != chdir(path)) {
687 print_error("Error: Could not chdir: %s", path);
688 exit(1);
689 }
690 }
691
692 /**
693 * Run the build, install, and test actions.
694 */
695 bool
run_phases(vector<Target * > targets,const Options & options)696 run_phases(vector<Target*> targets, const Options& options)
697 {
698 int err = 0;
699
700 //
701 // Initialization
702 //
703
704 print_status("Initializing");
705
706 const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
707 const string buildProduct = get_required_env("TARGET_PRODUCT", false);
708 const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
709 const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
710 const string buildOut = get_out_dir();
711 chdir_or_exit(buildTop.c_str());
712
713 BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
714
715 const string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
716 const string buildId = buildVars.GetBuildVar("BUILD_ID", false);
717
718 // Get the modules for the targets
719 map<string,Module> modules;
720 read_modules(buildOut, buildDevice, &modules, false);
721 for (size_t i=0; i<targets.size(); i++) {
722 Target* target = targets[i];
723 map<string,Module>::iterator mod = modules.find(target->name);
724 if (mod != modules.end()) {
725 target->module = mod->second;
726 } else {
727 print_error("Error: Could not find module: %s", target->name.c_str());
728 fprintf(stderr, "Try running %sbit --refresh%s if you recently added %s%s%s.\n",
729 g_escapeBold, g_escapeEndColor,
730 g_escapeBold, target->name.c_str(), g_escapeEndColor);
731 err = 1;
732 }
733 }
734 if (err != 0) {
735 exit(1);
736 }
737
738 // Choose the goals
739 vector<string> goals;
740 for (size_t i=0; i<targets.size(); i++) {
741 Target* target = targets[i];
742 if (target->build) {
743 goals.push_back(target->name);
744 }
745 }
746
747
748 // Figure out whether we need to sync the system and which apks to install
749 string deviceTargetPath = buildOut + "/target/product/" + buildDevice;
750 string systemPath = deviceTargetPath + "/system/";
751 string dataPath = deviceTargetPath + "/data/";
752 string testPath = deviceTargetPath + "/testcases/";
753 bool syncSystem = false;
754 bool alwaysSyncSystem = false;
755 vector<string> systemFiles;
756 vector<InstallApk> installApks;
757 vector<PushedFile> pushedFiles;
758 for (size_t i=0; i<targets.size(); i++) {
759 Target* target = targets[i];
760 if (target->install) {
761 for (size_t j=0; j<target->module.installed.size(); j++) {
762 const string& file = target->module.installed[j];
763 // System partition
764 if (starts_with(file, systemPath)) {
765 syncSystem = true;
766 systemFiles.push_back(file);
767 if (!target->build) {
768 // If a system partition target didn't get built then
769 // it won't change we will always need to do adb sync
770 alwaysSyncSystem = true;
771 }
772 continue;
773 }
774 // Apk in the data partition
775 if (ends_with(file, ".apk")
776 && (starts_with(file, dataPath) || starts_with(file, testPath))) {
777 // Always install it if we didn't build it because otherwise
778 // it will never have changed.
779 installApks.push_back(InstallApk(file, !target->build));
780 continue;
781 }
782 // If it's a native test module, push it.
783 if (target->module.HasClass(NATIVE_TESTS) && starts_with(file, dataPath)) {
784 string installedPath(file.c_str() + deviceTargetPath.length());
785 pushedFiles.push_back(PushedFile(file, installedPath));
786 }
787 }
788 }
789 }
790 map<string,FileInfo> systemFilesBefore;
791 if (syncSystem && !alwaysSyncSystem) {
792 get_directory_contents(systemPath, &systemFilesBefore);
793 }
794
795 if (systemFiles.size() > 0){
796 print_info("System files:");
797 for (size_t i=0; i<systemFiles.size(); i++) {
798 printf(" %s\n", systemFiles[i].c_str());
799 }
800 }
801 if (pushedFiles.size() > 0){
802 print_info("Files to push:");
803 for (size_t i=0; i<pushedFiles.size(); i++) {
804 printf(" %s\n", pushedFiles[i].file.filename.c_str());
805 printf(" --> %s\n", pushedFiles[i].dest.c_str());
806 }
807 }
808 if (installApks.size() > 0){
809 print_info("APKs to install:");
810 for (size_t i=0; i<installApks.size(); i++) {
811 printf(" %s\n", installApks[i].file.filename.c_str());
812 }
813 }
814
815 //
816 // Build
817 //
818
819 // Run the build
820 if (goals.size() > 0) {
821 print_status("Building");
822 err = build_goals(goals);
823 check_error(err);
824 }
825
826 //
827 // Install
828 //
829
830 // Sync the system partition and reboot
831 bool skipSync = false;
832 if (syncSystem) {
833 print_status("Syncing /system");
834
835 if (!alwaysSyncSystem) {
836 // If nothing changed and we weren't forced to sync, skip the reboot for speed.
837 map<string,FileInfo> systemFilesAfter;
838 get_directory_contents(systemPath, &systemFilesAfter);
839 skipSync = !directory_contents_differ(systemFilesBefore, systemFilesAfter);
840 }
841 if (skipSync) {
842 printf("Skipping sync because no files changed.\n");
843 } else {
844 // Do some sanity checks
845 check_device_property("ro.build.product", buildProduct);
846 check_device_property("ro.build.type", buildVariant);
847 check_device_property("ro.build.id", buildId);
848
849 // Stop & Sync
850 if (!options.noRestart) {
851 err = run_adb("exec-out", "stop", NULL);
852 check_error(err);
853 }
854 err = run_adb("remount", NULL);
855 check_error(err);
856 err = run_adb("sync", "system", NULL);
857 check_error(err);
858
859 if (!options.noRestart) {
860 if (options.reboot) {
861 print_status("Rebooting");
862
863 err = run_adb("reboot", NULL);
864 check_error(err);
865 err = run_adb("wait-for-device", NULL);
866 check_error(err);
867 } else {
868 print_status("Restarting the runtime");
869
870 err = run_adb("exec-out", "setprop", "sys.boot_completed", "0", NULL);
871 check_error(err);
872 err = run_adb("exec-out", "start", NULL);
873 check_error(err);
874 }
875
876 while (true) {
877 string completed = get_system_property("sys.boot_completed", &err);
878 check_error(err);
879 if (completed == "1") {
880 break;
881 }
882 sleep(2);
883 }
884 sleep(1);
885 err = run_adb("exec-out", "wm", "dismiss-keyguard", NULL);
886 check_error(err);
887 }
888 }
889 }
890
891 // Push files
892 if (pushedFiles.size() > 0) {
893 print_status("Pushing files");
894 for (size_t i=0; i<pushedFiles.size(); i++) {
895 const PushedFile& pushed = pushedFiles[i];
896 string dir = dirname(pushed.dest);
897 if (dir.length() == 0 || dir == "/") {
898 // This isn't really a file inside the data directory. Just skip it.
899 continue;
900 }
901 // TODO: if (!apk.file.fileInfo.exists || apk.file.HasChanged())
902 err = run_adb("exec-out", "mkdir", "-p", dir.c_str(), NULL);
903 check_error(err);
904 err = run_adb("push", pushed.file.filename.c_str(), pushed.dest.c_str(), NULL);
905 check_error(err);
906 // pushed.installed = true;
907 }
908 }
909
910 // Install APKs
911 if (installApks.size() > 0) {
912 print_status("Installing APKs");
913 for (size_t i=0; i<installApks.size(); i++) {
914 InstallApk& apk = installApks[i];
915 if (!apk.file.fileInfo.exists || apk.file.HasChanged()) {
916 // It didn't exist before or it changed, so int needs install
917 err = run_adb("install", "-r", "-g", apk.file.filename.c_str(), NULL);
918 check_error(err);
919 apk.installed = true;
920 } else {
921 printf("APK didn't change. Skipping install of %s\n", apk.file.filename.c_str());
922 }
923 }
924 }
925
926 //
927 // Actions
928 //
929
930 // Whether there have been any tests run, so we can print a summary.
931 bool testsRun = false;
932
933 // Run the native tests.
934 // TODO: We don't have a good way of running these and capturing the output of
935 // them live. It'll take some work. On the other hand, if they're gtest tests,
936 // the output of gtest is not completely insane like the text output of the
937 // instrumentation tests. So for now, we'll just live with that.
938 for (size_t i=0; i<targets.size(); i++) {
939 Target* target = targets[i];
940 if (target->test && target->module.HasClass(NATIVE_TESTS)) {
941 // We don't have a clear signal from the build system which of the installed
942 // files is actually the test, so we guess by looking for one with the same
943 // leaf name as the module that is executable.
944 for (size_t j=0; j<target->module.installed.size(); j++) {
945 string filename = target->module.installed[j];
946 if (!starts_with(filename, dataPath)) {
947 // Native tests go into the data directory.
948 continue;
949 }
950 if (leafname(filename) != target->module.name) {
951 // This isn't the test executable.
952 continue;
953 }
954 if (!is_executable(filename)) {
955 continue;
956 }
957 string installedPath(filename.c_str() + deviceTargetPath.length());
958 printf("the magic one is: %s\n", filename.c_str());
959 printf(" and it's installed at: %s\n", installedPath.c_str());
960
961 // Convert bit-style actions to gtest test filter arguments
962 if (target->actions.size() > 0) {
963 testsRun = true;
964 target->testActionCount++;
965 bool runAll = false;
966 string filterArg("--gtest_filter=");
967 for (size_t k=0; k<target->actions.size(); k++) {
968 string actionString = target->actions[k];
969 if (actionString == "*") {
970 runAll = true;
971 } else {
972 filterArg += actionString;
973 if (k != target->actions.size()-1) {
974 // We would otherwise have to worry about this condition
975 // being true, and appending an extra ':', but we know that
976 // if the extra action is "*", then we'll just run all and
977 // won't use filterArg anyway, so just keep this condition
978 // simple.
979 filterArg += ':';
980 }
981 }
982 }
983 if (runAll) {
984 err = run_adb("exec-out", installedPath.c_str(), NULL);
985 } else {
986 err = run_adb("exec-out", installedPath.c_str(), filterArg.c_str(), NULL);
987 }
988 if (err == 0) {
989 target->testPassCount++;
990 } else {
991 target->testFailCount++;
992 }
993 }
994 }
995 }
996 }
997
998 // Inspect the apks, and figure out what is an activity and what needs a test runner
999 bool printedInspecting = false;
1000 vector<TestAction> testActions;
1001 vector<ActivityAction> activityActions;
1002 for (size_t i=0; i<targets.size(); i++) {
1003 Target* target = targets[i];
1004 if (target->test) {
1005 for (size_t j=0; j<target->module.installed.size(); j++) {
1006 string filename = target->module.installed[j];
1007
1008 // Skip of not apk in the data partition or test
1009 if (!(ends_with(filename, ".apk")
1010 && (starts_with(filename, dataPath) || starts_with(filename, testPath)))) {
1011 continue;
1012 }
1013
1014 if (!printedInspecting) {
1015 printedInspecting = true;
1016 print_status("Inspecting APKs");
1017 }
1018
1019 Apk apk;
1020 err = inspect_apk(&apk, filename);
1021 check_error(err);
1022
1023 for (size_t k=0; k<target->actions.size(); k++) {
1024 string actionString = target->actions[k];
1025 if (actionString == "*") {
1026 if (apk.runner.length() == 0) {
1027 print_error("Error: Test requested for apk that doesn't"
1028 " have an <instrumentation> tag: %s\n",
1029 target->module.name.c_str());
1030 exit(1);
1031 }
1032 TestAction action;
1033 action.packageName = apk.package;
1034 action.runner = apk.runner;
1035 action.target = target;
1036 testActions.push_back(action);
1037 target->testActionCount++;
1038 } else if (apk.HasActivity(actionString)) {
1039 ActivityAction action;
1040 action.packageName = apk.package;
1041 action.className = full_class_name(apk.package, actionString);
1042 activityActions.push_back(action);
1043 } else {
1044 if (apk.runner.length() == 0) {
1045 print_error("Error: Test requested for apk that doesn't"
1046 " have an <instrumentation> tag: %s\n",
1047 target->module.name.c_str());
1048 exit(1);
1049 }
1050 TestAction action;
1051 action.packageName = apk.package;
1052 action.runner = apk.runner;
1053 action.className = full_class_name(apk.package, actionString);
1054 action.target = target;
1055 testActions.push_back(action);
1056 target->testActionCount++;
1057 }
1058 }
1059 }
1060 }
1061 }
1062
1063 // Run the instrumentation tests
1064 TestResults testResults;
1065 if (testActions.size() > 0) {
1066 print_status("Running tests");
1067 testsRun = true;
1068 for (size_t i=0; i<testActions.size(); i++) {
1069 TestAction& action = testActions[i];
1070 testResults.SetCurrentAction(&action);
1071 err = run_instrumentation_test(action.packageName, action.runner, action.className,
1072 &testResults);
1073 check_error(err);
1074 int total = action.passCount + action.failCount;
1075 printf("%sRan %d test%s for %s. ", g_escapeClearLine,
1076 total, total > 1 ? "s" : "", action.target->name.c_str());
1077 print_results(action.passCount, action.failCount, action.ignoreCount);
1078 if (!testResults.IsSuccess()) {
1079 printf("\n%sTest didn't finish successfully: %s%s\n", g_escapeRedBold,
1080 testResults.GetErrorMessage().c_str(), g_escapeEndColor);
1081 }
1082 }
1083 }
1084
1085 // Launch the activity
1086 if (activityActions.size() > 0) {
1087 print_status("Starting activity");
1088
1089 if (activityActions.size() > 1) {
1090 print_warning("Multiple activities specified. Will only start the first one:");
1091 for (size_t i=0; i<activityActions.size(); i++) {
1092 ActivityAction& action = activityActions[i];
1093 print_warning(" %s",
1094 pretty_component_name(action.packageName, action.className).c_str());
1095 }
1096 }
1097
1098 const ActivityAction& action = activityActions[0];
1099 string componentName = action.packageName + "/" + action.className;
1100 err = run_adb("exec-out", "am", "start", componentName.c_str(), NULL);
1101 check_error(err);
1102 }
1103
1104 //
1105 // Print summary
1106 //
1107
1108 printf("\n%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
1109
1110 // Build
1111 if (goals.size() > 0) {
1112 printf("%sBuilt:%s\n", g_escapeBold, g_escapeEndColor);
1113 for (size_t i=0; i<goals.size(); i++) {
1114 printf(" %s\n", goals[i].c_str());
1115 }
1116 }
1117
1118 // Install
1119 if (syncSystem) {
1120 if (skipSync) {
1121 printf("%sSkipped syncing /system partition%s\n", g_escapeBold, g_escapeEndColor);
1122 } else {
1123 printf("%sSynced /system partition%s\n", g_escapeBold, g_escapeEndColor);
1124 }
1125 }
1126 if (installApks.size() > 0) {
1127 bool printedTitle = false;
1128 for (size_t i=0; i<installApks.size(); i++) {
1129 const InstallApk& apk = installApks[i];
1130 if (apk.installed) {
1131 if (!printedTitle) {
1132 printf("%sInstalled:%s\n", g_escapeBold, g_escapeEndColor);
1133 printedTitle = true;
1134 }
1135 printf(" %s\n", apk.file.filename.c_str());
1136 }
1137 }
1138 printedTitle = false;
1139 for (size_t i=0; i<installApks.size(); i++) {
1140 const InstallApk& apk = installApks[i];
1141 if (!apk.installed) {
1142 if (!printedTitle) {
1143 printf("%sSkipped install:%s\n", g_escapeBold, g_escapeEndColor);
1144 printedTitle = true;
1145 }
1146 printf(" %s\n", apk.file.filename.c_str());
1147 }
1148 }
1149 }
1150
1151 // Tests
1152 bool hasErrors = false;
1153 if (testsRun) {
1154 printf("%sRan tests:%s\n", g_escapeBold, g_escapeEndColor);
1155 size_t maxNameLength = 0;
1156 for (size_t i=0; i<targets.size(); i++) {
1157 Target* target = targets[i];
1158 if (target->test) {
1159 size_t len = target->name.length();
1160 if (len > maxNameLength) {
1161 maxNameLength = len;
1162 }
1163 }
1164 }
1165 string padding(maxNameLength, ' ');
1166 for (size_t i=0; i<targets.size(); i++) {
1167 Target* target = targets[i];
1168 if (target->testActionCount > 0) {
1169 printf(" %s%s", target->name.c_str(), padding.c_str() + target->name.length());
1170 if (target->unknownFailureCount > 0) {
1171 printf(" %sUnknown failure, see above message.%s\n",
1172 g_escapeRedBold, g_escapeEndColor);
1173 hasErrors = true;
1174 } else {
1175 printf(" %s%s ", target->name.c_str(),
1176 padding.c_str() + target->name.length());
1177 print_results(target->testPassCount, target->testFailCount,
1178 target->testIgnoreCount);
1179 }
1180 }
1181 }
1182 }
1183 if (activityActions.size() > 1) {
1184 printf("%sStarted Activity:%s\n", g_escapeBold, g_escapeEndColor);
1185 const ActivityAction& action = activityActions[0];
1186 printf(" %s\n", pretty_component_name(action.packageName, action.className).c_str());
1187 }
1188
1189 printf("%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
1190 return !hasErrors;
1191 }
1192
1193 /**
1194 * Refresh module-info.
1195 */
1196 void
run_refresh()1197 run_refresh()
1198 {
1199 int err;
1200
1201 print_status("Initializing");
1202 const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
1203 const string buildProduct = get_required_env("TARGET_PRODUCT", false);
1204 const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
1205 const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
1206 const string buildOut = get_out_dir();
1207 chdir_or_exit(buildTop.c_str());
1208
1209 BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
1210
1211 string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
1212
1213 vector<string> goals;
1214 goals.push_back(buildOut + "/target/product/" + buildDevice + "/module-info.json");
1215
1216 print_status("Refreshing module-info.json");
1217 err = build_goals(goals);
1218 check_error(err);
1219 }
1220
1221 /**
1222 * Implement tab completion of the target names from the all modules file.
1223 */
1224 void
run_tab_completion(const string & word)1225 run_tab_completion(const string& word)
1226 {
1227 const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
1228 const string buildProduct = get_required_env("TARGET_PRODUCT", false);
1229 const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
1230 const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
1231 const string buildOut = get_out_dir();
1232 chdir_or_exit(buildTop.c_str());
1233
1234 BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
1235
1236 string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
1237
1238 map<string,Module> modules;
1239 read_modules(buildOut, buildDevice, &modules, true);
1240
1241 for (map<string,Module>::const_iterator it = modules.begin(); it != modules.end(); it++) {
1242 if (starts_with(it->first, word)) {
1243 printf("%s\n", it->first.c_str());
1244 }
1245 }
1246 }
1247
1248 /**
1249 * Main entry point.
1250 */
1251 int
main(int argc,const char ** argv)1252 main(int argc, const char** argv)
1253 {
1254 GOOGLE_PROTOBUF_VERIFY_VERSION;
1255 init_print();
1256
1257 Options options;
1258 parse_args(&options, argc, argv);
1259
1260 if (options.runHelp) {
1261 // Help
1262 print_usage(stdout);
1263 exit(0);
1264 } else if (options.runRefresh) {
1265 run_refresh();
1266 exit(0);
1267 } else if (options.runTab) {
1268 run_tab_completion(options.tabPattern);
1269 exit(0);
1270 } else {
1271 // Normal run
1272 exit(run_phases(options.targets, options) ? 0 : 1);
1273 }
1274
1275 return 0;
1276 }
1277
1278