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