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