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    int unknownFailureCount; // unknown failure == "Process crashed", etc.
54    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),
67     unknownFailureCount(0),
68     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
84    bool noRestart;
85    bool reboot;
86    vector<Target*> targets;
87
88    Options();
89    ~Options();
90};
91
92Options::Options()
93    :runHelp(false),
94     runTab(false),
95     noRestart(false),
96     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
193    bool IsSuccess();
194
195    string GetErrorMessage();
196
197private:
198    TestAction* m_currentAction;
199    SessionStatus m_sessionStatus;
200};
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());
251    } else if ((resultCode == -1) || (resultCode == -2)) {
252        // test failed
253        // Note -2 means an assertion failure, and -1 means other exceptions.  We just treat them
254        // all as "failures".
255        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
269TestResults::OnSessionStatus(SessionStatus& status)
270{
271    //status.PrintDebugString();
272    m_sessionStatus = status;
273    if (m_currentAction && !IsSuccess()) {
274        m_currentAction->target->unknownFailureCount++;
275    }
276}
277
278void
279TestResults::SetCurrentAction(TestAction* action)
280{
281    m_currentAction = action;
282}
283
284bool
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
302/**
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");
321    fprintf(out, "  -n     Don't reboot or restart\n");
322    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");
376    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");
380    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;
472                    case 'n':
473                        options->noRestart = true;
474                        break;
475                    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);
493                delete target;
494                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 {
563            char pwd[PATH_MAX];
564            if (getcwd(pwd, PATH_MAX) == NULL) {
565                fprintf(stderr, "Your pwd is too long.\n");
566                exit(1);
567            }
568            const char* slash = strrchr(pwd, '/');
569            if (slash == NULL) {
570                slash = "";
571            }
572            string result(common_base);
573            result += slash;
574            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
599/**
600 * Run the build, install, and test actions.
601 */
602bool
603run_phases(vector<Target*> targets, const Options& options)
604{
605    int err = 0;
606
607    //
608    // Initialization
609    //
610
611    print_status("Initializing");
612
613    const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
614    const string buildProduct = get_required_env("TARGET_PRODUCT", false);
615    const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
616    const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
617    const string buildDevice = get_build_var(buildTop, "TARGET_DEVICE", false);
618    const string buildId = get_build_var(buildTop, "BUILD_ID", false);
619    const string buildOut = get_out_dir();
620
621    // TODO: print_command("cd", buildTop.c_str());
622    chdir(buildTop.c_str());
623
624    // Get the modules for the targets
625    map<string,Module> modules;
626    read_modules(buildOut, buildDevice, &modules, false);
627    for (size_t i=0; i<targets.size(); i++) {
628        Target* target = targets[i];
629        map<string,Module>::iterator mod = modules.find(target->name);
630        if (mod != modules.end()) {
631            target->module = mod->second;
632        } else {
633            print_error("Error: Could not find module: %s", target->name.c_str());
634            err = 1;
635        }
636    }
637    if (err != 0) {
638        exit(1);
639    }
640
641    // Choose the goals
642    vector<string> goals;
643    for (size_t i=0; i<targets.size(); i++) {
644        Target* target = targets[i];
645        if (target->build) {
646            goals.push_back(target->name);
647        }
648    }
649
650    // Figure out whether we need to sync the system and which apks to install
651    string systemPath = buildOut + "/target/product/" + buildDevice + "/system/";
652    string dataPath = buildOut + "/target/product/" + buildDevice + "/data/";
653    bool syncSystem = false;
654    bool alwaysSyncSystem = false;
655    vector<InstallApk> installApks;
656    for (size_t i=0; i<targets.size(); i++) {
657        Target* target = targets[i];
658        if (target->install) {
659            for (size_t j=0; j<target->module.installed.size(); j++) {
660                const string& file = target->module.installed[j];
661                // System partition
662                if (starts_with(file, systemPath)) {
663                    syncSystem = true;
664                    if (!target->build) {
665                        // If a system partition target didn't get built then
666                        // it won't change we will always need to do adb sync
667                        alwaysSyncSystem = true;
668                    }
669                    continue;
670                }
671                // Apk in the data partition
672                if (starts_with(file, dataPath) && ends_with(file, ".apk")) {
673                    // Always install it if we didn't build it because otherwise
674                    // it will never have changed.
675                    installApks.push_back(InstallApk(file, !target->build));
676                    continue;
677                }
678            }
679        }
680    }
681    map<string,FileInfo> systemFilesBefore;
682    if (syncSystem && !alwaysSyncSystem) {
683        get_directory_contents(systemPath, &systemFilesBefore);
684    }
685
686    //
687    // Build
688    //
689
690    // Run the build
691    if (goals.size() > 0) {
692        print_status("Building");
693        err = build_goals(goals);
694        check_error(err);
695    }
696
697    //
698    // Install
699    //
700
701    // Sync the system partition and reboot
702    bool skipSync = false;
703    if (syncSystem) {
704        print_status("Syncing /system");
705
706        if (!alwaysSyncSystem) {
707            // If nothing changed and we weren't forced to sync, skip the reboot for speed.
708            map<string,FileInfo> systemFilesAfter;
709            get_directory_contents(systemPath, &systemFilesAfter);
710            skipSync = !directory_contents_differ(systemFilesBefore, systemFilesAfter);
711        }
712        if (skipSync) {
713            printf("Skipping sync because no files changed.\n");
714        } else {
715            // Do some sanity checks
716            check_device_property("ro.build.product", buildProduct);
717            check_device_property("ro.build.type", buildVariant);
718            check_device_property("ro.build.id", buildId);
719
720            // Stop & Sync
721            if (!options.noRestart) {
722                err = run_adb("shell", "stop", NULL);
723                check_error(err);
724            }
725            err = run_adb("remount", NULL);
726            check_error(err);
727            err = run_adb("sync", "system", NULL);
728            check_error(err);
729
730            if (!options.noRestart) {
731                if (options.reboot) {
732                    print_status("Rebooting");
733
734                    err = run_adb("reboot", NULL);
735                    check_error(err);
736                    err = run_adb("wait-for-device", NULL);
737                    check_error(err);
738                } else {
739                    print_status("Restarting the runtime");
740
741                    err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
742                    check_error(err);
743                    err = run_adb("shell", "start", NULL);
744                    check_error(err);
745                }
746
747                while (true) {
748                    string completed = get_system_property("sys.boot_completed", &err);
749                    check_error(err);
750                    if (completed == "1") {
751                        break;
752                    }
753                    sleep(2);
754                }
755                sleep(1);
756                err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
757                check_error(err);
758            }
759        }
760    }
761
762    // Install APKs
763    if (installApks.size() > 0) {
764        print_status("Installing APKs");
765        for (size_t i=0; i<installApks.size(); i++) {
766            InstallApk& apk = installApks[i];
767            if (!apk.file.fileInfo.exists || apk.file.HasChanged()) {
768                // It didn't exist before or it changed, so int needs install
769                err = run_adb("install", "-r", "-g", apk.file.filename.c_str(), NULL);
770                check_error(err);
771                apk.installed = true;
772            } else {
773                printf("APK didn't change. Skipping install of %s\n", apk.file.filename.c_str());
774            }
775        }
776    }
777
778    //
779    // Actions
780    //
781
782    // Inspect the apks, and figure out what is an activity and what needs a test runner
783    bool printedInspecting = false;
784    vector<TestAction> testActions;
785    vector<ActivityAction> activityActions;
786    for (size_t i=0; i<targets.size(); i++) {
787        Target* target = targets[i];
788        if (target->test) {
789            for (size_t j=0; j<target->module.installed.size(); j++) {
790                string filename = target->module.installed[j];
791
792                if (!ends_with(filename, ".apk")) {
793                    continue;
794                }
795
796                if (!printedInspecting) {
797                    printedInspecting = true;
798                    print_status("Inspecting APKs");
799                }
800
801                Apk apk;
802                err = inspect_apk(&apk, filename);
803                check_error(err);
804
805                for (size_t k=0; k<target->actions.size(); k++) {
806                    string actionString = target->actions[k];
807                    if (actionString == "*") {
808                        if (apk.runner.length() == 0) {
809                            print_error("Error: Test requested for apk that doesn't"
810                                    " have an <instrumentation> tag: %s\n",
811                                    target->module.name.c_str());
812                            exit(1);
813                        }
814                        TestAction action;
815                        action.packageName = apk.package;
816                        action.runner = apk.runner;
817                        action.target = target;
818                        testActions.push_back(action);
819                        target->testActionCount++;
820                    } else if (apk.HasActivity(actionString)) {
821                        ActivityAction action;
822                        action.packageName = apk.package;
823                        action.className = full_class_name(apk.package, actionString);
824                        activityActions.push_back(action);
825                    } else {
826                        if (apk.runner.length() == 0) {
827                            print_error("Error: Test requested for apk that doesn't"
828                                    " have an <instrumentation> tag: %s\n",
829                                    target->module.name.c_str());
830                            exit(1);
831                        }
832                        TestAction action;
833                        action.packageName = apk.package;
834                        action.runner = apk.runner;
835                        action.className = full_class_name(apk.package, actionString);
836                        action.target = target;
837                        testActions.push_back(action);
838                        target->testActionCount++;
839                    }
840                }
841            }
842        }
843    }
844
845    // Run the instrumentation tests
846    TestResults testResults;
847    if (testActions.size() > 0) {
848        print_status("Running tests");
849        for (size_t i=0; i<testActions.size(); i++) {
850            TestAction& action = testActions[i];
851            testResults.SetCurrentAction(&action);
852            err = run_instrumentation_test(action.packageName, action.runner, action.className,
853                    &testResults);
854            check_error(err);
855            if (action.passCount == 0 && action.failCount == 0) {
856                action.target->actionsWithNoTests = true;
857            }
858            int total = action.passCount + action.failCount;
859            printf("%sRan %d test%s for %s. ", g_escapeClearLine,
860                    total, total > 1 ? "s" : "", action.target->name.c_str());
861            if (action.passCount == 0 && action.failCount == 0) {
862                printf("%s%d passed, %d failed%s\n", g_escapeYellowBold, action.passCount,
863                        action.failCount, g_escapeEndColor);
864            } else if (action.failCount >  0) {
865                printf("%d passed, %s%d failed%s\n", action.passCount, g_escapeRedBold,
866                        action.failCount, g_escapeEndColor);
867            } else {
868                printf("%s%d passed%s, %d failed\n", g_escapeGreenBold, action.passCount,
869                        g_escapeEndColor, action.failCount);
870            }
871            if (!testResults.IsSuccess()) {
872                printf("\n%sTest didn't finish successfully: %s%s\n", g_escapeRedBold,
873                        testResults.GetErrorMessage().c_str(), g_escapeEndColor);
874            }
875        }
876    }
877
878    // Launch the activity
879    if (activityActions.size() > 0) {
880        print_status("Starting activity");
881
882        if (activityActions.size() > 1) {
883            print_warning("Multiple activities specified.  Will only start the first one:");
884            for (size_t i=0; i<activityActions.size(); i++) {
885                ActivityAction& action = activityActions[i];
886                print_warning("   %s",
887                        pretty_component_name(action.packageName, action.className).c_str());
888            }
889        }
890
891        const ActivityAction& action = activityActions[0];
892        string componentName = action.packageName + "/" + action.className;
893        err = run_adb("shell", "am", "start", componentName.c_str(), NULL);
894        check_error(err);
895    }
896
897    //
898    // Print summary
899    //
900
901    printf("\n%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
902
903    // Build
904    if (goals.size() > 0) {
905        printf("%sBuilt:%s\n", g_escapeBold, g_escapeEndColor);
906        for (size_t i=0; i<goals.size(); i++) {
907            printf("   %s\n", goals[i].c_str());
908        }
909    }
910
911    // Install
912    if (syncSystem) {
913        if (skipSync) {
914            printf("%sSkipped syncing /system partition%s\n", g_escapeBold, g_escapeEndColor);
915        } else {
916            printf("%sSynced /system partition%s\n", g_escapeBold, g_escapeEndColor);
917        }
918    }
919    if (installApks.size() > 0) {
920        bool printedTitle = false;
921        for (size_t i=0; i<installApks.size(); i++) {
922            const InstallApk& apk = installApks[i];
923            if (apk.installed) {
924                if (!printedTitle) {
925                    printf("%sInstalled:%s\n", g_escapeBold, g_escapeEndColor);
926                    printedTitle = true;
927                }
928                printf("   %s\n", apk.file.filename.c_str());
929            }
930        }
931        printedTitle = false;
932        for (size_t i=0; i<installApks.size(); i++) {
933            const InstallApk& apk = installApks[i];
934            if (!apk.installed) {
935                if (!printedTitle) {
936                    printf("%sSkipped install:%s\n", g_escapeBold, g_escapeEndColor);
937                    printedTitle = true;
938                }
939                printf("   %s\n", apk.file.filename.c_str());
940            }
941        }
942    }
943
944    // Tests
945    bool hasErrors = false;
946    if (testActions.size() > 0) {
947        printf("%sRan tests:%s\n", g_escapeBold, g_escapeEndColor);
948        size_t maxNameLength = 0;
949        for (size_t i=0; i<targets.size(); i++) {
950            Target* target = targets[i];
951            if (target->test) {
952                size_t len = target->name.length();
953                if (len > maxNameLength) {
954                    maxNameLength = len;
955                }
956            }
957        }
958        string padding(maxNameLength, ' ');
959        for (size_t i=0; i<targets.size(); i++) {
960            Target* target = targets[i];
961            if (target->testActionCount > 0) {
962                printf("   %s%s", target->name.c_str(), padding.c_str() + target->name.length());
963                if (target->unknownFailureCount > 0) {
964                    printf("     %sUnknown failure, see above message.%s\n",
965                            g_escapeRedBold, g_escapeEndColor);
966                    hasErrors = true;
967                } else if (target->actionsWithNoTests) {
968                    printf("     %s%d passed, %d failed%s\n", g_escapeYellowBold,
969                            target->testPassCount, target->testFailCount, g_escapeEndColor);
970                    hasErrors = true;
971                } else if (target->testFailCount > 0) {
972                    printf("     %d passed, %s%d failed%s\n", target->testPassCount,
973                            g_escapeRedBold, target->testFailCount, g_escapeEndColor);
974                    hasErrors = true;
975                } else {
976                    printf("     %s%d passed%s, %d failed\n", g_escapeGreenBold,
977                            target->testPassCount, g_escapeEndColor, target->testFailCount);
978                }
979            }
980        }
981    }
982    if (activityActions.size() > 1) {
983        printf("%sStarted Activity:%s\n", g_escapeBold, g_escapeEndColor);
984        const ActivityAction& action = activityActions[0];
985        printf("   %s\n", pretty_component_name(action.packageName, action.className).c_str());
986    }
987
988    printf("%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
989    return !hasErrors;
990}
991
992/**
993 * Implement tab completion of the target names from the all modules file.
994 */
995void
996run_tab_completion(const string& word)
997{
998    const string buildTop = get_required_env("ANDROID_BUILD_TOP", true);
999    const string buildProduct = get_required_env("TARGET_PRODUCT", false);
1000    const string buildOut = get_out_dir();
1001
1002    chdir(buildTop.c_str());
1003
1004    string buildDevice = sniff_device_name(buildOut, buildProduct);
1005
1006    map<string,Module> modules;
1007    read_modules(buildOut, buildDevice, &modules, true);
1008
1009    for (map<string,Module>::const_iterator it = modules.begin(); it != modules.end(); it++) {
1010        if (starts_with(it->first, word)) {
1011            printf("%s\n", it->first.c_str());
1012        }
1013    }
1014}
1015
1016/**
1017 * Main entry point.
1018 */
1019int
1020main(int argc, const char** argv)
1021{
1022    GOOGLE_PROTOBUF_VERIFY_VERSION;
1023    init_print();
1024
1025    Options options;
1026    parse_args(&options, argc, argv);
1027
1028    if (options.runHelp) {
1029        // Help
1030        print_usage(stdout);
1031        exit(0);
1032    } else if (options.runTab) {
1033        run_tab_completion(options.tabPattern);
1034        exit(0);
1035    } else {
1036        // Normal run
1037        exit(run_phases(options.targets, options) ? 0 : 1);
1038    }
1039
1040    return 0;
1041}
1042
1043