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