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