Home | History | Annotate | Download | only in bit
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "aapt.h"
     18 #include "adb.h"
     19 #include "make.h"
     20 #include "print.h"
     21 #include "util.h"
     22 
     23 #include <sstream>
     24 #include <string>
     25 #include <vector>
     26 
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <unistd.h>
     31 
     32 #include <google/protobuf/stubs/common.h>
     33 
     34 using namespace std;
     35 
     36 /**
     37  * An entry from the command line for something that will be built, installed,
     38  * and/or tested.
     39  */
     40 struct 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 
     58 Target::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  */
     73 struct 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 
     90 Options::Options()
     91     :runHelp(false),
     92      runTab(false),
     93      noRestart(false),
     94      reboot(false),
     95      targets()
     96 {
     97 }
     98 
     99 Options::~Options()
    100 {
    101 }
    102 
    103 struct 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 
    115 InstallApk::InstallApk()
    116 {
    117 }
    118 
    119 InstallApk::InstallApk(const InstallApk& that)
    120     :file(that.file),
    121      alwaysInstall(that.alwaysInstall),
    122      installed(that.installed)
    123 {
    124 }
    125 
    126 InstallApk::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  */
    137 struct 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 
    159 TestAction::TestAction()
    160     :passCount(0),
    161      failCount(0)
    162 {
    163 }
    164 
    165 /**
    166  * Record for an activity that is going to be launched.
    167  */
    168 struct 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  */
    179 class TestResults: public InstrumentationCallbacks
    180 {
    181 public:
    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 
    191 private:
    192     TestAction* m_currentAction;
    193 };
    194 
    195 void
    196 TestResults::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 
    259 void
    260 TestResults::OnSessionStatus(SessionStatus& /*status*/)
    261 {
    262     //status.PrintDebugString();
    263 }
    264 
    265 void
    266 TestResults::SetCurrentAction(TestAction* action)
    267 {
    268     m_currentAction = action;
    269 }
    270 
    271 /**
    272  * Prints the usage statement / help text.
    273  */
    274 static void
    275 print_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, "  Launching an Activity\n");
    346     fprintf(out, "  ---------------------\n");
    347     fprintf(out, "  To launch an activity, specify the activity class name after\n");
    348     fprintf(out, "  the module name.\n");
    349     fprintf(out, "\n");
    350     fprintf(out, "  For example:\n");
    351     fprintf(out, "    bit StatusBarTest:NotificationBuilderTest\n");
    352     fprintf(out, "    bit StatusBarTest:.NotificationBuilderTest\n");
    353     fprintf(out, "    bit StatusBarTest:com.android.statusbartest.NotificationBuilderTest\n");
    354     fprintf(out, "      Builds and installs StatusBarTest.apk, launches the\n");
    355     fprintf(out, "      com.android.statusbartest/.NotificationBuilderTest activity.\n");
    356     fprintf(out, "\n");
    357     fprintf(out, "\n");
    358     fprintf(out, "usage: bit --tab ...\n");
    359     fprintf(out, "\n");
    360     fprintf(out, "  Lists the targets in a format for tab completion. To get tab\n");
    361     fprintf(out, "  completion, add this to your bash environment:\n");
    362     fprintf(out, "\n");
    363     fprintf(out, "     complete -C \"bit --tab\" bit\n");
    364     fprintf(out, "\n");
    365     fprintf(out, "  Sourcing android's build/envsetup.sh will do this for you\n");
    366     fprintf(out, "  automatically.\n");
    367     fprintf(out, "\n");
    368     fprintf(out, "\n");
    369     fprintf(out, "usage: bit --help\n");
    370     fprintf(out, "usage: bit -h\n");
    371     fprintf(out, "\n");
    372     fprintf(out, "  Print this help message\n");
    373     fprintf(out, "\n");
    374 }
    375 
    376 
    377 /**
    378  * Sets the appropriate flag* variables. If there is a problem with the
    379  * commandline arguments, prints the help message and exits with an error.
    380  */
    381 static void
    382 parse_args(Options* options, int argc, const char** argv)
    383 {
    384     // Help
    385     if (argc == 2 && (strcmp(argv[1],  "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
    386         options->runHelp = true;
    387         return;
    388     }
    389 
    390     // Tab
    391     if (argc >= 4 && strcmp(argv[1], "--tab") == 0) {
    392         options->runTab = true;
    393         options->tabPattern = argv[3];
    394         return;
    395     }
    396 
    397     // Normal usage
    398     bool anyPhases = false;
    399     bool gotPattern = false;
    400     bool flagBuild = false;
    401     bool flagInstall = false;
    402     bool flagTest = false;
    403     for (int i=1; i < argc; i++) {
    404         string arg(argv[i]);
    405         if (arg[0] == '-') {
    406             for (size_t j=1; j<arg.size(); j++) {
    407                 switch (arg[j]) {
    408                     case '-':
    409                         break;
    410                     case 'b':
    411                         if (gotPattern) {
    412                             gotPattern = false;
    413                             flagInstall = false;
    414                             flagTest = false;
    415                         }
    416                         flagBuild = true;
    417                         anyPhases = true;
    418                         break;
    419                     case 'i':
    420                         if (gotPattern) {
    421                             gotPattern = false;
    422                             flagBuild = false;
    423                             flagTest = false;
    424                         }
    425                         flagInstall = true;
    426                         anyPhases = true;
    427                         break;
    428                     case 't':
    429                         if (gotPattern) {
    430                             gotPattern = false;
    431                             flagBuild = false;
    432                             flagInstall = false;
    433                         }
    434                         flagTest = true;
    435                         anyPhases = true;
    436                         break;
    437                     case 'n':
    438                         options->noRestart = true;
    439                         break;
    440                     case 'r':
    441                         options->reboot = true;
    442                         break;
    443                     default:
    444                         fprintf(stderr, "Unrecognized option '%c'\n", arg[j]);
    445                         print_usage(stderr);
    446                         exit(1);
    447                         break;
    448                 }
    449             }
    450         } else {
    451             Target* target = new Target(flagBuild || !anyPhases, flagInstall || !anyPhases,
    452                     flagTest || !anyPhases, arg);
    453             size_t colonPos = arg.find(':');
    454             if (colonPos == 0) {
    455                 fprintf(stderr, "Test / activity supplied without a module to build: %s\n",
    456                         arg.c_str());
    457                 print_usage(stderr);
    458                 delete target;
    459                 exit(1);
    460             } else if (colonPos == string::npos) {
    461                 target->name = arg;
    462             } else {
    463                 target->name.assign(arg, 0, colonPos);
    464                 size_t beginPos = colonPos+1;
    465                 size_t commaPos;
    466                 while (true) {
    467                     commaPos = arg.find(',', beginPos);
    468                     if (commaPos == string::npos) {
    469                         if (beginPos != arg.size()) {
    470                             target->actions.push_back(string(arg, beginPos, commaPos));
    471                         }
    472                         break;
    473                     } else {
    474                         if (commaPos != beginPos) {
    475                             target->actions.push_back(string(arg, beginPos, commaPos-beginPos));
    476                         }
    477                         beginPos = commaPos+1;
    478                     }
    479                 }
    480             }
    481             options->targets.push_back(target);
    482             gotPattern = true;
    483         }
    484     }
    485     // If no pattern was supplied, give an error
    486     if (options->targets.size() == 0) {
    487         fprintf(stderr, "No PATTERN supplied.\n\n");
    488         print_usage(stderr);
    489         exit(1);
    490     }
    491 }
    492 
    493 /**
    494  * Get an environment variable.
    495  * Exits with an error if it is unset or the empty string.
    496  */
    497 static string
    498 get_required_env(const char* name, bool quiet)
    499 {
    500     const char* value = getenv(name);
    501     if (value == NULL || value[0] == '\0') {
    502         if (!quiet) {
    503             fprintf(stderr, "%s not set. Did you source build/envsetup.sh,"
    504                     " run lunch and do a build?\n", name);
    505         }
    506         exit(1);
    507     }
    508     return string(value);
    509 }
    510 
    511 /**
    512  * Get the out directory.
    513  *
    514  * This duplicates the logic in build/make/core/envsetup.mk (which hasn't changed since 2011)
    515  * so that we don't have to wait for get_build_var make invocation.
    516  */
    517 string
    518 get_out_dir()
    519 {
    520     const char* out_dir = getenv("OUT_DIR");
    521     if (out_dir == NULL || out_dir[0] == '\0') {
    522         const char* common_base = getenv("OUT_DIR_COMMON_BASE");
    523         if (common_base == NULL || common_base[0] == '\0') {
    524             // We don't prefix with buildTop because we cd there and it
    525             // makes all the filenames long when being pretty printed.
    526             return "out";
    527         } else {
    528             char pwd[PATH_MAX];
    529             if (getcwd(pwd, PATH_MAX) == NULL) {
    530                 fprintf(stderr, "Your pwd is too long.\n");
    531                 exit(1);
    532             }
    533             const char* slash = strrchr(pwd, '/');
    534             if (slash == NULL) {
    535                 slash = "";
    536             }
    537             string result(common_base);
    538             result += slash;
    539             return result;
    540         }
    541     }
    542     return string(out_dir);
    543 }
    544 
    545 /**
    546  * Check that a system property on the device matches the expected value.
    547  * Exits with an error if they don't.
    548  */
    549 static void
    550 check_device_property(const string& property, const string& expected)
    551 {
    552     int err;
    553     string deviceValue = get_system_property(property, &err);
    554     check_error(err);
    555     if (deviceValue != expected) {
    556         print_error("There is a mismatch between the build you just did and the device you");
    557         print_error("are trying to sync it to in the %s system property", property.c_str());
    558         print_error("   build:  %s", expected.c_str());
    559         print_error("   device: %s", deviceValue.c_str());
    560         exit(1);
    561     }
    562 }
    563 
    564 /**
    565  * Run the build, install, and test actions.
    566  */
    567 void
    568 run_phases(vector<Target*> targets, const Options& options)
    569 {
    570     int err = 0;
    571 
    572     //
    573     // Initialization
    574     //
    575 
    576     print_status("Initializing");
    577 
    578     const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
    579     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
    580     const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
    581     const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
    582     const string buildDevice = get_build_var(buildTop, "TARGET_DEVICE", false);
    583     const string buildId = get_build_var(buildTop, "BUILD_ID", false);
    584     const string buildOut = get_out_dir();
    585 
    586     // TODO: print_command("cd", buildTop.c_str());
    587     chdir(buildTop.c_str());
    588 
    589     // Get the modules for the targets
    590     map<string,Module> modules;
    591     read_modules(buildOut, buildDevice, &modules, false);
    592     for (size_t i=0; i<targets.size(); i++) {
    593         Target* target = targets[i];
    594         map<string,Module>::iterator mod = modules.find(target->name);
    595         if (mod != modules.end()) {
    596             target->module = mod->second;
    597         } else {
    598             print_error("Error: Could not find module: %s", target->name.c_str());
    599             err = 1;
    600         }
    601     }
    602     if (err != 0) {
    603         exit(1);
    604     }
    605 
    606     // Choose the goals
    607     vector<string> goals;
    608     for (size_t i=0; i<targets.size(); i++) {
    609         Target* target = targets[i];
    610         if (target->build) {
    611             goals.push_back(target->name);
    612         }
    613     }
    614 
    615     // Figure out whether we need to sync the system and which apks to install
    616     string systemPath = buildOut + "/target/product/" + buildDevice + "/system/";
    617     string dataPath = buildOut + "/target/product/" + buildDevice + "/data/";
    618     bool syncSystem = false;
    619     bool alwaysSyncSystem = false;
    620     vector<InstallApk> installApks;
    621     for (size_t i=0; i<targets.size(); i++) {
    622         Target* target = targets[i];
    623         if (target->install) {
    624             for (size_t j=0; j<target->module.installed.size(); j++) {
    625                 const string& file = target->module.installed[j];
    626                 // System partition
    627                 if (starts_with(file, systemPath)) {
    628                     syncSystem = true;
    629                     if (!target->build) {
    630                         // If a system partition target didn't get built then
    631                         // it won't change we will always need to do adb sync
    632                         alwaysSyncSystem = true;
    633                     }
    634                     continue;
    635                 }
    636                 // Apk in the data partition
    637                 if (starts_with(file, dataPath) && ends_with(file, ".apk")) {
    638                     // Always install it if we didn't build it because otherwise
    639                     // it will never have changed.
    640                     installApks.push_back(InstallApk(file, !target->build));
    641                     continue;
    642                 }
    643             }
    644         }
    645     }
    646     map<string,FileInfo> systemFilesBefore;
    647     if (syncSystem && !alwaysSyncSystem) {
    648         get_directory_contents(systemPath, &systemFilesBefore);
    649     }
    650 
    651     //
    652     // Build
    653     //
    654 
    655     // Run the build
    656     if (goals.size() > 0) {
    657         print_status("Building");
    658         err = build_goals(goals);
    659         check_error(err);
    660     }
    661 
    662     //
    663     // Install
    664     //
    665 
    666     // Sync the system partition and reboot
    667     bool skipSync = false;
    668     if (syncSystem) {
    669         print_status("Syncing /system");
    670 
    671         if (!alwaysSyncSystem) {
    672             // If nothing changed and we weren't forced to sync, skip the reboot for speed.
    673             map<string,FileInfo> systemFilesAfter;
    674             get_directory_contents(systemPath, &systemFilesAfter);
    675             skipSync = !directory_contents_differ(systemFilesBefore, systemFilesAfter);
    676         }
    677         if (skipSync) {
    678             printf("Skipping sync because no files changed.\n");
    679         } else {
    680             // Do some sanity checks
    681             check_device_property("ro.build.product", buildProduct);
    682             check_device_property("ro.build.type", buildVariant);
    683             check_device_property("ro.build.id", buildId);
    684 
    685             // Stop & Sync
    686             if (!options.noRestart) {
    687                 err = run_adb("shell", "stop", NULL);
    688                 check_error(err);
    689             }
    690             err = run_adb("remount", NULL);
    691             check_error(err);
    692             err = run_adb("sync", "system", NULL);
    693             check_error(err);
    694 
    695             if (!options.noRestart) {
    696                 if (options.reboot) {
    697                     print_status("Rebooting");
    698 
    699                     err = run_adb("reboot", NULL);
    700                     check_error(err);
    701                     err = run_adb("wait-for-device", NULL);
    702                     check_error(err);
    703                 } else {
    704                     print_status("Restarting the runtime");
    705 
    706                     err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
    707                     check_error(err);
    708                     err = run_adb("shell", "start", NULL);
    709                     check_error(err);
    710                 }
    711 
    712                 while (true) {
    713                     string completed = get_system_property("sys.boot_completed", &err);
    714                     check_error(err);
    715                     if (completed == "1") {
    716                         break;
    717                     }
    718                     sleep(2);
    719                 }
    720                 sleep(1);
    721                 err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
    722                 check_error(err);
    723             }
    724         }
    725     }
    726 
    727     // Install APKs
    728     if (installApks.size() > 0) {
    729         print_status("Installing APKs");
    730         for (size_t i=0; i<installApks.size(); i++) {
    731             InstallApk& apk = installApks[i];
    732             if (!apk.file.fileInfo.exists || apk.file.HasChanged()) {
    733                 // It didn't exist before or it changed, so int needs install
    734                 err = run_adb("install", "-r", apk.file.filename.c_str(), NULL);
    735                 check_error(err);
    736                 apk.installed = true;
    737             } else {
    738                 printf("APK didn't change. Skipping install of %s\n", apk.file.filename.c_str());
    739             }
    740         }
    741     }
    742 
    743     //
    744     // Actions
    745     //
    746 
    747     // Inspect the apks, and figure out what is an activity and what needs a test runner
    748     bool printedInspecting = false;
    749     vector<TestAction> testActions;
    750     vector<ActivityAction> activityActions;
    751     for (size_t i=0; i<targets.size(); i++) {
    752         Target* target = targets[i];
    753         if (target->test) {
    754             for (size_t j=0; j<target->module.installed.size(); j++) {
    755                 string filename = target->module.installed[j];
    756 
    757                 if (!ends_with(filename, ".apk")) {
    758                     continue;
    759                 }
    760 
    761                 if (!printedInspecting) {
    762                     printedInspecting = true;
    763                     print_status("Inspecting APKs");
    764                 }
    765 
    766                 Apk apk;
    767                 err = inspect_apk(&apk, filename);
    768                 check_error(err);
    769 
    770                 for (size_t k=0; k<target->actions.size(); k++) {
    771                     string actionString = target->actions[k];
    772                     if (actionString == "*") {
    773                         if (apk.runner.length() == 0) {
    774                             print_error("Error: Test requested for apk that doesn't"
    775                                     " have an <instrumentation> tag: %s\n",
    776                                     target->module.name.c_str());
    777                             exit(1);
    778                         }
    779                         TestAction action;
    780                         action.packageName = apk.package;
    781                         action.runner = apk.runner;
    782                         action.target = target;
    783                         testActions.push_back(action);
    784                         target->testActionCount++;
    785                     } else if (apk.HasActivity(actionString)) {
    786                         ActivityAction action;
    787                         action.packageName = apk.package;
    788                         action.className = full_class_name(apk.package, actionString);
    789                         activityActions.push_back(action);
    790                     } else {
    791                         if (apk.runner.length() == 0) {
    792                             print_error("Error: Test requested for apk that doesn't"
    793                                     " have an <instrumentation> tag: %s\n",
    794                                     target->module.name.c_str());
    795                             exit(1);
    796                         }
    797                         TestAction action;
    798                         action.packageName = apk.package;
    799                         action.runner = apk.runner;
    800                         action.className = full_class_name(apk.package, actionString);
    801                         action.target = target;
    802                         testActions.push_back(action);
    803                         target->testActionCount++;
    804                     }
    805                 }
    806             }
    807         }
    808     }
    809 
    810     // Run the instrumentation tests
    811     TestResults testResults;
    812     if (testActions.size() > 0) {
    813         print_status("Running tests");
    814         for (size_t i=0; i<testActions.size(); i++) {
    815             TestAction& action = testActions[i];
    816             testResults.SetCurrentAction(&action);
    817             err = run_instrumentation_test(action.packageName, action.runner, action.className,
    818                     &testResults);
    819             check_error(err);
    820             if (action.passCount == 0 && action.failCount == 0) {
    821                 action.target->actionsWithNoTests = true;
    822             }
    823             int total = action.passCount + action.failCount;
    824             printf("%sRan %d test%s for %s. ", g_escapeClearLine,
    825                     total, total > 1 ? "s" : "", action.target->name.c_str());
    826             if (action.passCount == 0 && action.failCount == 0) {
    827                 printf("%s%d passed, %d failed%s\n", g_escapeYellowBold, action.passCount,
    828                         action.failCount, g_escapeEndColor);
    829             } else if (action.failCount >  0) {
    830                 printf("%d passed, %s%d failed%s\n", action.passCount, g_escapeRedBold,
    831                         action.failCount, g_escapeEndColor);
    832             } else {
    833                 printf("%s%d passed%s, %d failed\n", g_escapeGreenBold, action.passCount,
    834                         g_escapeEndColor, action.failCount);
    835             }
    836         }
    837     }
    838 
    839     // Launch the activity
    840     if (activityActions.size() > 0) {
    841         print_status("Starting activity");
    842 
    843         if (activityActions.size() > 1) {
    844             print_warning("Multiple activities specified.  Will only start the first one:");
    845             for (size_t i=0; i<activityActions.size(); i++) {
    846                 ActivityAction& action = activityActions[i];
    847                 print_warning("   %s",
    848                         pretty_component_name(action.packageName, action.className).c_str());
    849             }
    850         }
    851 
    852         const ActivityAction& action = activityActions[0];
    853         string componentName = action.packageName + "/" + action.className;
    854         err = run_adb("shell", "am", "start", componentName.c_str(), NULL);
    855         check_error(err);
    856     }
    857 
    858     //
    859     // Print summary
    860     //
    861 
    862     printf("\n%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
    863 
    864     // Build
    865     if (goals.size() > 0) {
    866         printf("%sBuilt:%s\n", g_escapeBold, g_escapeEndColor);
    867         for (size_t i=0; i<goals.size(); i++) {
    868             printf("   %s\n", goals[i].c_str());
    869         }
    870     }
    871 
    872     // Install
    873     if (syncSystem) {
    874         if (skipSync) {
    875             printf("%sSkipped syncing /system partition%s\n", g_escapeBold, g_escapeEndColor);
    876         } else {
    877             printf("%sSynced /system partition%s\n", g_escapeBold, g_escapeEndColor);
    878         }
    879     }
    880     if (installApks.size() > 0) {
    881         bool printedTitle = false;
    882         for (size_t i=0; i<installApks.size(); i++) {
    883             const InstallApk& apk = installApks[i];
    884             if (apk.installed) {
    885                 if (!printedTitle) {
    886                     printf("%sInstalled:%s\n", g_escapeBold, g_escapeEndColor);
    887                     printedTitle = true;
    888                 }
    889                 printf("   %s\n", apk.file.filename.c_str());
    890             }
    891         }
    892         printedTitle = false;
    893         for (size_t i=0; i<installApks.size(); i++) {
    894             const InstallApk& apk = installApks[i];
    895             if (!apk.installed) {
    896                 if (!printedTitle) {
    897                     printf("%sSkipped install:%s\n", g_escapeBold, g_escapeEndColor);
    898                     printedTitle = true;
    899                 }
    900                 printf("   %s\n", apk.file.filename.c_str());
    901             }
    902         }
    903     }
    904 
    905     // Tests
    906     if (testActions.size() > 0) {
    907         printf("%sRan tests:%s\n", g_escapeBold, g_escapeEndColor);
    908         size_t maxNameLength = 0;
    909         for (size_t i=0; i<targets.size(); i++) {
    910             Target* target = targets[i];
    911             if (target->test) {
    912                 size_t len = target->name.length();
    913                 if (len > maxNameLength) {
    914                     maxNameLength = len;
    915                 }
    916             }
    917         }
    918         string padding(maxNameLength, ' ');
    919         for (size_t i=0; i<targets.size(); i++) {
    920             Target* target = targets[i];
    921             if (target->testActionCount > 0) {
    922                 printf("   %s%s", target->name.c_str(), padding.c_str() + target->name.length());
    923                 if (target->actionsWithNoTests) {
    924                     printf("     %s%d passed, %d failed%s\n", g_escapeYellowBold,
    925                             target->testPassCount, target->testFailCount, g_escapeEndColor);
    926                 } else if (target->testFailCount > 0) {
    927                     printf("     %d passed, %s%d failed%s\n", target->testPassCount,
    928                             g_escapeRedBold, target->testFailCount, g_escapeEndColor);
    929                 } else {
    930                     printf("     %s%d passed%s, %d failed\n", g_escapeGreenBold,
    931                             target->testPassCount, g_escapeEndColor, target->testFailCount);
    932                 }
    933             }
    934         }
    935     }
    936     if (activityActions.size() > 1) {
    937         printf("%sStarted Activity:%s\n", g_escapeBold, g_escapeEndColor);
    938         const ActivityAction& action = activityActions[0];
    939         printf("   %s\n", pretty_component_name(action.packageName, action.className).c_str());
    940     }
    941 
    942     printf("%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
    943 }
    944 
    945 /**
    946  * Implement tab completion of the target names from the all modules file.
    947  */
    948 void
    949 run_tab_completion(const string& word)
    950 {
    951     const string buildTop = get_required_env("ANDROID_BUILD_TOP", true);
    952     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
    953     const string buildOut = get_out_dir();
    954 
    955     chdir(buildTop.c_str());
    956 
    957     string buildDevice = sniff_device_name(buildOut, buildProduct);
    958 
    959     map<string,Module> modules;
    960     read_modules(buildOut, buildDevice, &modules, true);
    961 
    962     for (map<string,Module>::const_iterator it = modules.begin(); it != modules.end(); it++) {
    963         if (starts_with(it->first, word)) {
    964             printf("%s\n", it->first.c_str());
    965         }
    966     }
    967 }
    968 
    969 /**
    970  * Main entry point.
    971  */
    972 int
    973 main(int argc, const char** argv)
    974 {
    975     GOOGLE_PROTOBUF_VERIFY_VERSION;
    976     init_print();
    977 
    978     Options options;
    979     parse_args(&options, argc, argv);
    980 
    981     if (options.runHelp) {
    982         // Help
    983         print_usage(stdout);
    984         exit(0);
    985     } else if (options.runTab) {
    986         run_tab_completion(options.tabPattern);
    987         exit(0);
    988     } else {
    989         // Normal run
    990         run_phases(options.targets, options);
    991     }
    992 
    993     return 0;
    994 }
    995 
    996