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 #define NATIVE_TESTS "NATIVE_TESTS"
     37 
     38 /**
     39  * An entry from the command line for something that will be built, installed,
     40  * and/or tested.
     41  */
     42 struct Target {
     43     bool build;
     44     bool install;
     45     bool test;
     46     string pattern;
     47     string name;
     48     vector<string> actions;
     49     Module module;
     50 
     51     int testActionCount;
     52 
     53     int testPassCount;
     54     int testFailCount;
     55     int unknownFailureCount; // unknown failure == "Process crashed", etc.
     56     bool actionsWithNoTests;
     57 
     58     Target(bool b, bool i, bool t, const string& p);
     59 };
     60 
     61 Target::Target(bool b, bool i, bool t, const string& p)
     62     :build(b),
     63      install(i),
     64      test(t),
     65      pattern(p),
     66      testActionCount(0),
     67      testPassCount(0),
     68      testFailCount(0),
     69      unknownFailureCount(0),
     70      actionsWithNoTests(false)
     71 {
     72 }
     73 
     74 /**
     75  * Command line options.
     76  */
     77 struct Options {
     78     // For help
     79     bool runHelp;
     80 
     81     // For refreshing module-info.json
     82     bool runRefresh;
     83 
     84     // For tab completion
     85     bool runTab;
     86     string tabPattern;
     87 
     88     // For build/install/test
     89     bool noRestart;
     90     bool reboot;
     91     vector<Target*> targets;
     92 
     93     Options();
     94     ~Options();
     95 };
     96 
     97 Options::Options()
     98     :runHelp(false),
     99      runRefresh(false),
    100      runTab(false),
    101      noRestart(false),
    102      reboot(false),
    103      targets()
    104 {
    105 }
    106 
    107 Options::~Options()
    108 {
    109 }
    110 
    111 struct InstallApk
    112 {
    113     TrackedFile file;
    114     bool alwaysInstall;
    115     bool installed;
    116 
    117     InstallApk();
    118     InstallApk(const InstallApk& that);
    119     InstallApk(const string& filename, bool always);
    120     ~InstallApk() {};
    121 };
    122 
    123 InstallApk::InstallApk()
    124 {
    125 }
    126 
    127 InstallApk::InstallApk(const InstallApk& that)
    128     :file(that.file),
    129      alwaysInstall(that.alwaysInstall),
    130      installed(that.installed)
    131 {
    132 }
    133 
    134 InstallApk::InstallApk(const string& filename, bool always)
    135     :file(filename),
    136      alwaysInstall(always),
    137      installed(false)
    138 {
    139 }
    140 
    141 struct PushedFile
    142 {
    143     TrackedFile file;
    144     string dest;
    145 
    146     PushedFile();
    147     PushedFile(const PushedFile& that);
    148     PushedFile(const string& filename, const string& dest);
    149     ~PushedFile() {};
    150 };
    151 
    152 PushedFile::PushedFile()
    153 {
    154 }
    155 
    156 PushedFile::PushedFile(const PushedFile& that)
    157     :file(that.file),
    158      dest(that.dest)
    159 {
    160 }
    161 
    162 PushedFile::PushedFile(const string& f, const string& d)
    163     :file(f),
    164      dest(d)
    165 {
    166 }
    167 
    168 /**
    169  * Record for an test that is going to be launched.
    170  */
    171 struct TestAction {
    172     TestAction();
    173 
    174     // The package name from the apk
    175     string packageName;
    176 
    177     // The test runner class
    178     string runner;
    179 
    180     // The test class, or none if all tests should be run
    181     string className;
    182 
    183     // The original target that requested this action
    184     Target* target;
    185 
    186     // The number of tests that passed
    187     int passCount;
    188 
    189     // The number of tests that failed
    190     int failCount;
    191 };
    192 
    193 TestAction::TestAction()
    194     :passCount(0),
    195      failCount(0)
    196 {
    197 }
    198 
    199 /**
    200  * Record for an activity that is going to be launched.
    201  */
    202 struct ActivityAction {
    203     // The package name from the apk
    204     string packageName;
    205 
    206     // The test class, or none if all tests should be run
    207     string className;
    208 };
    209 
    210 /**
    211  * Callback class for the am instrument command.
    212  */
    213 class TestResults: public InstrumentationCallbacks
    214 {
    215 public:
    216     virtual void OnTestStatus(TestStatus& status);
    217     virtual void OnSessionStatus(SessionStatus& status);
    218 
    219     /**
    220      * Set the TestAction that the tests are for.
    221      * It will be updated with statistics as the tests run.
    222      */
    223     void SetCurrentAction(TestAction* action);
    224 
    225     bool IsSuccess();
    226 
    227     string GetErrorMessage();
    228 
    229 private:
    230     TestAction* m_currentAction;
    231     SessionStatus m_sessionStatus;
    232 };
    233 
    234 void
    235 TestResults::OnTestStatus(TestStatus& status)
    236 {
    237     bool found;
    238 //    printf("OnTestStatus\n");
    239 //    status.PrintDebugString();
    240     int32_t resultCode = status.has_results() ? status.result_code() : 0;
    241 
    242     if (!status.has_results()) {
    243         return;
    244     }
    245     const ResultsBundle &results = status.results();
    246 
    247     int32_t currentTestNum = get_bundle_int(results, &found, "current", NULL);
    248     if (!found) {
    249         currentTestNum = -1;
    250     }
    251 
    252     int32_t testCount = get_bundle_int(results, &found, "numtests", NULL);
    253     if (!found) {
    254         testCount = -1;
    255     }
    256 
    257     string className = get_bundle_string(results, &found, "class", NULL);
    258     if (!found) {
    259         return;
    260     }
    261 
    262     string testName = get_bundle_string(results, &found, "test", NULL);
    263     if (!found) {
    264         return;
    265     }
    266 
    267     if (resultCode == 0) {
    268         // test passed
    269         m_currentAction->passCount++;
    270         m_currentAction->target->testPassCount++;
    271     } else if (resultCode == 1) {
    272         // test starting
    273         ostringstream line;
    274         line << "Running";
    275         if (currentTestNum > 0) {
    276             line << ": " << currentTestNum;
    277             if (testCount > 0) {
    278                 line << " of " << testCount;
    279             }
    280         }
    281         line << ": " << m_currentAction->target->name << ':' << className << "\\#" << testName;
    282         print_one_line("%s", line.str().c_str());
    283     } else if ((resultCode == -1) || (resultCode == -2)) {
    284         // test failed
    285         // Note -2 means an assertion failure, and -1 means other exceptions.  We just treat them
    286         // all as "failures".
    287         m_currentAction->failCount++;
    288         m_currentAction->target->testFailCount++;
    289         printf("%s\n%sFailed: %s:%s\\#%s%s\n", g_escapeClearLine, g_escapeRedBold,
    290                 m_currentAction->target->name.c_str(), className.c_str(),
    291                 testName.c_str(), g_escapeEndColor);
    292 
    293         bool stackFound;
    294         string stack = get_bundle_string(results, &stackFound, "stack", NULL);
    295         if (status.has_logcat()) {
    296             const string logcat = status.logcat();
    297             if (logcat.length() > 0) {
    298                 printf("%s\n", logcat.c_str());
    299             }
    300         } else if (stackFound) {
    301             printf("%s\n", stack.c_str());
    302         }
    303     }
    304 }
    305 
    306 void
    307 TestResults::OnSessionStatus(SessionStatus& status)
    308 {
    309     //status.PrintDebugString();
    310     m_sessionStatus = status;
    311     if (m_currentAction && !IsSuccess()) {
    312         m_currentAction->target->unknownFailureCount++;
    313     }
    314 }
    315 
    316 void
    317 TestResults::SetCurrentAction(TestAction* action)
    318 {
    319     m_currentAction = action;
    320 }
    321 
    322 bool
    323 TestResults::IsSuccess()
    324 {
    325     return m_sessionStatus.result_code() == -1; // Activity.RESULT_OK.
    326 }
    327 
    328 string
    329 TestResults::GetErrorMessage()
    330 {
    331     bool found;
    332     string shortMsg = get_bundle_string(m_sessionStatus.results(), &found, "shortMsg", NULL);
    333     if (!found) {
    334         return IsSuccess() ? "" : "Unknown failure";
    335     }
    336     return shortMsg;
    337 }
    338 
    339 
    340 /**
    341  * Prints the usage statement / help text.
    342  */
    343 static void
    344 print_usage(FILE* out) {
    345     fprintf(out, "usage: bit OPTIONS PATTERN\n");
    346     fprintf(out, "\n");
    347     fprintf(out, "  Build, sync and test android code.\n");
    348     fprintf(out, "\n");
    349     fprintf(out, "  The -b -i and -t options allow you to specify which phases\n");
    350     fprintf(out, "  you want to run. If none of those options are given, then\n");
    351     fprintf(out, "  all phases are run. If any of these options are provided\n");
    352     fprintf(out, "  then only the listed phases are run.\n");
    353     fprintf(out, "\n");
    354     fprintf(out, "  OPTIONS\n");
    355     fprintf(out, "  -b     Run a build\n");
    356     fprintf(out, "  -i     Install the targets\n");
    357     fprintf(out, "  -t     Run the tests\n");
    358     fprintf(out, "\n");
    359     fprintf(out, "  -n     Don't reboot or restart\n");
    360     fprintf(out, "  -r     If the runtime needs to be restarted, do a full reboot\n");
    361     fprintf(out, "         instead\n");
    362     fprintf(out, "\n");
    363     fprintf(out, "  PATTERN\n");
    364     fprintf(out, "  One or more targets to build, install and test. The target\n");
    365     fprintf(out, "  names are the names that appear in the LOCAL_MODULE or\n");
    366     fprintf(out, "  LOCAL_PACKAGE_NAME variables in Android.mk or Android.bp files.\n");
    367     fprintf(out, "\n");
    368     fprintf(out, "  Building and installing\n");
    369     fprintf(out, "  -----------------------\n");
    370     fprintf(out, "  The modules specified will be built and then installed. If the\n");
    371     fprintf(out, "  files are on the system partition, they will be synced and the\n");
    372     fprintf(out, "  attached device rebooted. If they are APKs that aren't on the\n");
    373     fprintf(out, "  system partition they are installed with adb install.\n");
    374     fprintf(out, "\n");
    375     fprintf(out, "  For example:\n");
    376     fprintf(out, "    bit framework\n");
    377     fprintf(out, "      Builds framework.jar, syncs the system partition and reboots.\n");
    378     fprintf(out, "\n");
    379     fprintf(out, "    bit SystemUI\n");
    380     fprintf(out, "      Builds SystemUI.apk, syncs the system partition and reboots.\n");
    381     fprintf(out, "\n");
    382     fprintf(out, "    bit CtsProtoTestCases\n");
    383     fprintf(out, "      Builds this CTS apk, adb installs it, but does not run any\n");
    384     fprintf(out, "      tests.\n");
    385     fprintf(out, "\n");
    386     fprintf(out, "  Running Unit Tests\n");
    387     fprintf(out, "  ------------------\n");
    388     fprintf(out, "  To run a unit test, list the test class names and optionally the\n");
    389     fprintf(out, "  test method after the module.\n");
    390     fprintf(out, "\n");
    391     fprintf(out, "  For example:\n");
    392     fprintf(out, "    bit CtsProtoTestCases:*\n");
    393     fprintf(out, "      Builds this CTS apk, adb installs it, and runs all the tests\n");
    394     fprintf(out, "      contained in that apk.\n");
    395     fprintf(out, "\n");
    396     fprintf(out, "    bit framework CtsProtoTestCases:*\n");
    397     fprintf(out, "      Builds the framework and the apk, syncs and reboots, then\n");
    398     fprintf(out, "      adb installs CtsProtoTestCases.apk, and runs all tests \n");
    399     fprintf(out, "      contained in that apk.\n");
    400     fprintf(out, "\n");
    401     fprintf(out, "    bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\n");
    402     fprintf(out, "    bit CtsProtoTestCases:android.util.proto.cts.ProtoOutputStreamBoolTest\n");
    403     fprintf(out, "      Builds and installs CtsProtoTestCases.apk, and runs all the\n");
    404     fprintf(out, "      tests in the ProtoOutputStreamBoolTest class.\n");
    405     fprintf(out, "\n");
    406     fprintf(out, "    bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite\n");
    407     fprintf(out, "      Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
    408     fprintf(out, "      test method on that class.\n");
    409     fprintf(out, "\n");
    410     fprintf(out, "    bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite,.ProtoOutputStreamBoolTest\\#testRepeated\n");
    411     fprintf(out, "      Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
    412     fprintf(out, "      and testRepeated test methods on that class.\n");
    413     fprintf(out, "\n");
    414     fprintf(out, "    bit CtsProtoTestCases:android.util.proto.cts.\n");
    415     fprintf(out, "      Builds and installs CtsProtoTestCases.apk, and runs the tests in the java package\n");
    416     fprintf(out, "      \"android.util.proto.cts\".\n");
    417     fprintf(out, "\n");
    418     fprintf(out, "  Launching an Activity\n");
    419     fprintf(out, "  ---------------------\n");
    420     fprintf(out, "  To launch an activity, specify the activity class name after\n");
    421     fprintf(out, "  the module name.\n");
    422     fprintf(out, "\n");
    423     fprintf(out, "  For example:\n");
    424     fprintf(out, "    bit StatusBarTest:NotificationBuilderTest\n");
    425     fprintf(out, "    bit StatusBarTest:.NotificationBuilderTest\n");
    426     fprintf(out, "    bit StatusBarTest:com.android.statusbartest.NotificationBuilderTest\n");
    427     fprintf(out, "      Builds and installs StatusBarTest.apk, launches the\n");
    428     fprintf(out, "      com.android.statusbartest/.NotificationBuilderTest activity.\n");
    429     fprintf(out, "\n");
    430     fprintf(out, "\n");
    431     fprintf(out, "usage: bit --refresh\n");
    432     fprintf(out, "\n");
    433     fprintf(out, "  Update module-info.json, the cache of make goals that can be built.\n");
    434     fprintf(out, "\n");
    435     fprintf(out, "usage: bit --tab ...\n");
    436     fprintf(out, "\n");
    437     fprintf(out, "  Lists the targets in a format for tab completion. To get tab\n");
    438     fprintf(out, "  completion, add this to your bash environment:\n");
    439     fprintf(out, "\n");
    440     fprintf(out, "     complete -C \"bit --tab\" bit\n");
    441     fprintf(out, "\n");
    442     fprintf(out, "  Sourcing android's build/envsetup.sh will do this for you\n");
    443     fprintf(out, "  automatically.\n");
    444     fprintf(out, "\n");
    445     fprintf(out, "\n");
    446     fprintf(out, "usage: bit --help\n");
    447     fprintf(out, "usage: bit -h\n");
    448     fprintf(out, "\n");
    449     fprintf(out, "  Print this help message\n");
    450     fprintf(out, "\n");
    451 }
    452 
    453 
    454 /**
    455  * Sets the appropriate flag* variables. If there is a problem with the
    456  * commandline arguments, prints the help message and exits with an error.
    457  */
    458 static void
    459 parse_args(Options* options, int argc, const char** argv)
    460 {
    461     // Help
    462     if (argc == 2 && (strcmp(argv[1],  "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
    463         options->runHelp = true;
    464         return;
    465     }
    466 
    467     // Refresh
    468     if (argc == 2 && strcmp(argv[1], "--refresh") == 0) {
    469         options->runRefresh = true;
    470         return;
    471     }
    472 
    473     // Tab
    474     if (argc >= 4 && strcmp(argv[1], "--tab") == 0) {
    475         options->runTab = true;
    476         options->tabPattern = argv[3];
    477         return;
    478     }
    479 
    480     // Normal usage
    481     bool anyPhases = false;
    482     bool gotPattern = false;
    483     bool flagBuild = false;
    484     bool flagInstall = false;
    485     bool flagTest = false;
    486     for (int i=1; i < argc; i++) {
    487         string arg(argv[i]);
    488         if (arg[0] == '-') {
    489             for (size_t j=1; j<arg.size(); j++) {
    490                 switch (arg[j]) {
    491                     case '-':
    492                         break;
    493                     case 'b':
    494                         if (gotPattern) {
    495                             gotPattern = false;
    496                             flagInstall = false;
    497                             flagTest = false;
    498                         }
    499                         flagBuild = true;
    500                         anyPhases = true;
    501                         break;
    502                     case 'i':
    503                         if (gotPattern) {
    504                             gotPattern = false;
    505                             flagBuild = false;
    506                             flagTest = false;
    507                         }
    508                         flagInstall = true;
    509                         anyPhases = true;
    510                         break;
    511                     case 't':
    512                         if (gotPattern) {
    513                             gotPattern = false;
    514                             flagBuild = false;
    515                             flagInstall = false;
    516                         }
    517                         flagTest = true;
    518                         anyPhases = true;
    519                         break;
    520                     case 'n':
    521                         options->noRestart = true;
    522                         break;
    523                     case 'r':
    524                         options->reboot = true;
    525                         break;
    526                     default:
    527                         fprintf(stderr, "Unrecognized option '%c'\n", arg[j]);
    528                         print_usage(stderr);
    529                         exit(1);
    530                         break;
    531                 }
    532             }
    533         } else {
    534             Target* target = new Target(flagBuild || !anyPhases, flagInstall || !anyPhases,
    535                     flagTest || !anyPhases, arg);
    536             size_t colonPos = arg.find(':');
    537             if (colonPos == 0) {
    538                 fprintf(stderr, "Test / activity supplied without a module to build: %s\n",
    539                         arg.c_str());
    540                 print_usage(stderr);
    541                 delete target;
    542                 exit(1);
    543             } else if (colonPos == string::npos) {
    544                 target->name = arg;
    545             } else {
    546                 target->name.assign(arg, 0, colonPos);
    547                 size_t beginPos = colonPos+1;
    548                 size_t commaPos;
    549                 while (true) {
    550                     commaPos = arg.find(',', beginPos);
    551                     if (commaPos == string::npos) {
    552                         if (beginPos != arg.size()) {
    553                             target->actions.push_back(string(arg, beginPos, commaPos));
    554                         }
    555                         break;
    556                     } else {
    557                         if (commaPos != beginPos) {
    558                             target->actions.push_back(string(arg, beginPos, commaPos-beginPos));
    559                         }
    560                         beginPos = commaPos+1;
    561                     }
    562                 }
    563             }
    564             options->targets.push_back(target);
    565             gotPattern = true;
    566         }
    567     }
    568     // If no pattern was supplied, give an error
    569     if (options->targets.size() == 0) {
    570         fprintf(stderr, "No PATTERN supplied.\n\n");
    571         print_usage(stderr);
    572         exit(1);
    573     }
    574 }
    575 
    576 /**
    577  * Get an environment variable.
    578  * Exits with an error if it is unset or the empty string.
    579  */
    580 static string
    581 get_required_env(const char* name, bool quiet)
    582 {
    583     const char* value = getenv(name);
    584     if (value == NULL || value[0] == '\0') {
    585         if (!quiet) {
    586             fprintf(stderr, "%s not set. Did you source build/envsetup.sh,"
    587                     " run lunch and do a build?\n", name);
    588         }
    589         exit(1);
    590     }
    591     return string(value);
    592 }
    593 
    594 /**
    595  * Get the out directory.
    596  *
    597  * This duplicates the logic in build/make/core/envsetup.mk (which hasn't changed since 2011)
    598  * so that we don't have to wait for get_build_var make invocation.
    599  */
    600 string
    601 get_out_dir()
    602 {
    603     const char* out_dir = getenv("OUT_DIR");
    604     if (out_dir == NULL || out_dir[0] == '\0') {
    605         const char* common_base = getenv("OUT_DIR_COMMON_BASE");
    606         if (common_base == NULL || common_base[0] == '\0') {
    607             // We don't prefix with buildTop because we cd there and it
    608             // makes all the filenames long when being pretty printed.
    609             return "out";
    610         } else {
    611             char pwd[PATH_MAX];
    612             if (getcwd(pwd, PATH_MAX) == NULL) {
    613                 fprintf(stderr, "Your pwd is too long.\n");
    614                 exit(1);
    615             }
    616             const char* slash = strrchr(pwd, '/');
    617             if (slash == NULL) {
    618                 slash = "";
    619             }
    620             string result(common_base);
    621             result += slash;
    622             return result;
    623         }
    624     }
    625     return string(out_dir);
    626 }
    627 
    628 /**
    629  * Check that a system property on the device matches the expected value.
    630  * Exits with an error if they don't.
    631  */
    632 static void
    633 check_device_property(const string& property, const string& expected)
    634 {
    635     int err;
    636     string deviceValue = get_system_property(property, &err);
    637     check_error(err);
    638     if (deviceValue != expected) {
    639         print_error("There is a mismatch between the build you just did and the device you");
    640         print_error("are trying to sync it to in the %s system property", property.c_str());
    641         print_error("   build:  %s", expected.c_str());
    642         print_error("   device: %s", deviceValue.c_str());
    643         exit(1);
    644     }
    645 }
    646 
    647 static void
    648 chdir_or_exit(const char *path) {
    649     // TODO: print_command("cd", path);
    650     if (0 != chdir(path)) {
    651         print_error("Error: Could not chdir: %s", path);
    652         exit(1);
    653     }
    654 }
    655 
    656 /**
    657  * Run the build, install, and test actions.
    658  */
    659 bool
    660 run_phases(vector<Target*> targets, const Options& options)
    661 {
    662     int err = 0;
    663 
    664     //
    665     // Initialization
    666     //
    667 
    668     print_status("Initializing");
    669 
    670     const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
    671     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
    672     const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
    673     const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
    674     const string buildOut = get_out_dir();
    675     chdir_or_exit(buildTop.c_str());
    676 
    677     BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
    678 
    679     const string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
    680     const string buildId = buildVars.GetBuildVar("BUILD_ID", false);
    681 
    682     // Get the modules for the targets
    683     map<string,Module> modules;
    684     read_modules(buildOut, buildDevice, &modules, false);
    685     for (size_t i=0; i<targets.size(); i++) {
    686         Target* target = targets[i];
    687         map<string,Module>::iterator mod = modules.find(target->name);
    688         if (mod != modules.end()) {
    689             target->module = mod->second;
    690         } else {
    691             print_error("Error: Could not find module: %s", target->name.c_str());
    692             fprintf(stderr, "Try running %sbit --refresh%s if you recently added %s%s%s.\n",
    693                     g_escapeBold, g_escapeEndColor,
    694                     g_escapeBold, target->name.c_str(), g_escapeEndColor);
    695             err = 1;
    696         }
    697     }
    698     if (err != 0) {
    699         exit(1);
    700     }
    701 
    702     // Choose the goals
    703     vector<string> goals;
    704     for (size_t i=0; i<targets.size(); i++) {
    705         Target* target = targets[i];
    706         if (target->build) {
    707             goals.push_back(target->name);
    708         }
    709     }
    710 
    711     // Figure out whether we need to sync the system and which apks to install
    712     string deviceTargetPath = buildOut + "/target/product/" + buildDevice;
    713     string systemPath = deviceTargetPath + "/system/";
    714     string dataPath = deviceTargetPath + "/data/";
    715     bool syncSystem = false;
    716     bool alwaysSyncSystem = false;
    717     vector<string> systemFiles;
    718     vector<InstallApk> installApks;
    719     vector<PushedFile> pushedFiles;
    720     for (size_t i=0; i<targets.size(); i++) {
    721         Target* target = targets[i];
    722         if (target->install) {
    723             for (size_t j=0; j<target->module.installed.size(); j++) {
    724                 const string& file = target->module.installed[j];
    725                 // System partition
    726                 if (starts_with(file, systemPath)) {
    727                     syncSystem = true;
    728                     systemFiles.push_back(file);
    729                     if (!target->build) {
    730                         // If a system partition target didn't get built then
    731                         // it won't change we will always need to do adb sync
    732                         alwaysSyncSystem = true;
    733                     }
    734                     continue;
    735                 }
    736                 // Apk in the data partition
    737                 if (starts_with(file, dataPath) && ends_with(file, ".apk")) {
    738                     // Always install it if we didn't build it because otherwise
    739                     // it will never have changed.
    740                     installApks.push_back(InstallApk(file, !target->build));
    741                     continue;
    742                 }
    743                 // If it's a native test module, push it.
    744                 if (target->module.HasClass(NATIVE_TESTS) && starts_with(file, dataPath)) {
    745                     string installedPath(file.c_str() + deviceTargetPath.length());
    746                     pushedFiles.push_back(PushedFile(file, installedPath));
    747                 }
    748             }
    749         }
    750     }
    751     map<string,FileInfo> systemFilesBefore;
    752     if (syncSystem && !alwaysSyncSystem) {
    753         get_directory_contents(systemPath, &systemFilesBefore);
    754     }
    755 
    756     if (systemFiles.size() > 0){
    757         print_info("System files:");
    758         for (size_t i=0; i<systemFiles.size(); i++) {
    759             printf("  %s\n", systemFiles[i].c_str());
    760         }
    761     }
    762     if (pushedFiles.size() > 0){
    763         print_info("Files to push:");
    764         for (size_t i=0; i<pushedFiles.size(); i++) {
    765             printf("  %s\n", pushedFiles[i].file.filename.c_str());
    766             printf("    --> %s\n", pushedFiles[i].dest.c_str());
    767         }
    768     }
    769     if (installApks.size() > 0){
    770         print_info("APKs to install:");
    771         for (size_t i=0; i<installApks.size(); i++) {
    772             printf("  %s\n", installApks[i].file.filename.c_str());
    773         }
    774     }
    775 
    776     //
    777     // Build
    778     //
    779 
    780     // Run the build
    781     if (goals.size() > 0) {
    782         print_status("Building");
    783         err = build_goals(goals);
    784         check_error(err);
    785     }
    786 
    787     //
    788     // Install
    789     //
    790 
    791     // Sync the system partition and reboot
    792     bool skipSync = false;
    793     if (syncSystem) {
    794         print_status("Syncing /system");
    795 
    796         if (!alwaysSyncSystem) {
    797             // If nothing changed and we weren't forced to sync, skip the reboot for speed.
    798             map<string,FileInfo> systemFilesAfter;
    799             get_directory_contents(systemPath, &systemFilesAfter);
    800             skipSync = !directory_contents_differ(systemFilesBefore, systemFilesAfter);
    801         }
    802         if (skipSync) {
    803             printf("Skipping sync because no files changed.\n");
    804         } else {
    805             // Do some sanity checks
    806             check_device_property("ro.build.product", buildProduct);
    807             check_device_property("ro.build.type", buildVariant);
    808             check_device_property("ro.build.id", buildId);
    809 
    810             // Stop & Sync
    811             if (!options.noRestart) {
    812                 err = run_adb("shell", "stop", NULL);
    813                 check_error(err);
    814             }
    815             err = run_adb("remount", NULL);
    816             check_error(err);
    817             err = run_adb("sync", "system", NULL);
    818             check_error(err);
    819 
    820             if (!options.noRestart) {
    821                 if (options.reboot) {
    822                     print_status("Rebooting");
    823 
    824                     err = run_adb("reboot", NULL);
    825                     check_error(err);
    826                     err = run_adb("wait-for-device", NULL);
    827                     check_error(err);
    828                 } else {
    829                     print_status("Restarting the runtime");
    830 
    831                     err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
    832                     check_error(err);
    833                     err = run_adb("shell", "start", NULL);
    834                     check_error(err);
    835                 }
    836 
    837                 while (true) {
    838                     string completed = get_system_property("sys.boot_completed", &err);
    839                     check_error(err);
    840                     if (completed == "1") {
    841                         break;
    842                     }
    843                     sleep(2);
    844                 }
    845                 sleep(1);
    846                 err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
    847                 check_error(err);
    848             }
    849         }
    850     }
    851 
    852     // Push files
    853     if (pushedFiles.size() > 0) {
    854         print_status("Pushing files");
    855         for (size_t i=0; i<pushedFiles.size(); i++) {
    856             const PushedFile& pushed = pushedFiles[i];
    857             string dir = dirname(pushed.dest);
    858             if (dir.length() == 0 || dir == "/") {
    859                 // This isn't really a file inside the data directory. Just skip it.
    860                 continue;
    861             }
    862             // TODO: if (!apk.file.fileInfo.exists || apk.file.HasChanged())
    863             err = run_adb("shell", "mkdir", "-p", dir.c_str(), NULL);
    864             check_error(err);
    865             err = run_adb("push", pushed.file.filename.c_str(), pushed.dest.c_str(), NULL);
    866             check_error(err);
    867             // pushed.installed = true;
    868         }
    869     }
    870 
    871     // Install APKs
    872     if (installApks.size() > 0) {
    873         print_status("Installing APKs");
    874         for (size_t i=0; i<installApks.size(); i++) {
    875             InstallApk& apk = installApks[i];
    876             if (!apk.file.fileInfo.exists || apk.file.HasChanged()) {
    877                 // It didn't exist before or it changed, so int needs install
    878                 err = run_adb("install", "-r", "-g", apk.file.filename.c_str(), NULL);
    879                 check_error(err);
    880                 apk.installed = true;
    881             } else {
    882                 printf("APK didn't change. Skipping install of %s\n", apk.file.filename.c_str());
    883             }
    884         }
    885     }
    886 
    887     //
    888     // Actions
    889     //
    890 
    891     // Whether there have been any tests run, so we can print a summary.
    892     bool testsRun = false;
    893 
    894     // Run the native tests.
    895     // TODO: We don't have a good way of running these and capturing the output of
    896     // them live.  It'll take some work.  On the other hand, if they're gtest tests,
    897     // the output of gtest is not completely insane like the text output of the
    898     // instrumentation tests.  So for now, we'll just live with that.
    899     for (size_t i=0; i<targets.size(); i++) {
    900         Target* target = targets[i];
    901         if (target->test && target->module.HasClass(NATIVE_TESTS)) {
    902             // We don't have a clear signal from the build system which of the installed
    903             // files is actually the test, so we guess by looking for one with the same
    904             // leaf name as the module that is executable.
    905             for (size_t j=0; j<target->module.installed.size(); j++) {
    906                 string filename = target->module.installed[j];
    907                 if (!starts_with(filename, dataPath)) {
    908                     // Native tests go into the data directory.
    909                     continue;
    910                 }
    911                 if (leafname(filename) != target->module.name) {
    912                     // This isn't the test executable.
    913                     continue;
    914                 }
    915                 if (!is_executable(filename)) {
    916                     continue;
    917                 }
    918                 string installedPath(filename.c_str() + deviceTargetPath.length());
    919                 printf("the magic one is: %s\n", filename.c_str());
    920                 printf("  and it's installed at: %s\n", installedPath.c_str());
    921 
    922                 // Convert bit-style actions to gtest test filter arguments
    923                 if (target->actions.size() > 0) {
    924                     testsRun = true;
    925                     target->testActionCount++;
    926                     bool runAll = false;
    927                     string filterArg("--gtest_filter=");
    928                     for (size_t k=0; k<target->actions.size(); k++) {
    929                         string actionString = target->actions[k];
    930                         if (actionString == "*") {
    931                             runAll = true;
    932                         } else {
    933                             filterArg += actionString;
    934                             if (k != target->actions.size()-1) {
    935                                 // We would otherwise have to worry about this condition
    936                                 // being true, and appending an extra ':', but we know that
    937                                 // if the extra action is "*", then we'll just run all and
    938                                 // won't use filterArg anyway, so just keep this condition
    939                                 // simple.
    940                                 filterArg += ':';
    941                             }
    942                         }
    943                     }
    944                     if (runAll) {
    945                         err = run_adb("shell", installedPath.c_str(), NULL);
    946                     } else {
    947                         err = run_adb("shell", installedPath.c_str(), filterArg.c_str(), NULL);
    948                     }
    949                     if (err == 0) {
    950                         target->testPassCount++;
    951                     } else {
    952                         target->testFailCount++;
    953                     }
    954                 }
    955             }
    956         }
    957     }
    958 
    959     // Inspect the apks, and figure out what is an activity and what needs a test runner
    960     bool printedInspecting = false;
    961     vector<TestAction> testActions;
    962     vector<ActivityAction> activityActions;
    963     for (size_t i=0; i<targets.size(); i++) {
    964         Target* target = targets[i];
    965         if (target->test) {
    966             for (size_t j=0; j<target->module.installed.size(); j++) {
    967                 string filename = target->module.installed[j];
    968 
    969                 // Apk in the data partition
    970                 if (!starts_with(filename, dataPath) || !ends_with(filename, ".apk")) {
    971                     continue;
    972                 }
    973 
    974                 if (!printedInspecting) {
    975                     printedInspecting = true;
    976                     print_status("Inspecting APKs");
    977                 }
    978 
    979                 Apk apk;
    980                 err = inspect_apk(&apk, filename);
    981                 check_error(err);
    982 
    983                 for (size_t k=0; k<target->actions.size(); k++) {
    984                     string actionString = target->actions[k];
    985                     if (actionString == "*") {
    986                         if (apk.runner.length() == 0) {
    987                             print_error("Error: Test requested for apk that doesn't"
    988                                     " have an <instrumentation> tag: %s\n",
    989                                     target->module.name.c_str());
    990                             exit(1);
    991                         }
    992                         TestAction action;
    993                         action.packageName = apk.package;
    994                         action.runner = apk.runner;
    995                         action.target = target;
    996                         testActions.push_back(action);
    997                         target->testActionCount++;
    998                     } else if (apk.HasActivity(actionString)) {
    999                         ActivityAction action;
   1000                         action.packageName = apk.package;
   1001                         action.className = full_class_name(apk.package, actionString);
   1002                         activityActions.push_back(action);
   1003                     } else {
   1004                         if (apk.runner.length() == 0) {
   1005                             print_error("Error: Test requested for apk that doesn't"
   1006                                     " have an <instrumentation> tag: %s\n",
   1007                                     target->module.name.c_str());
   1008                             exit(1);
   1009                         }
   1010                         TestAction action;
   1011                         action.packageName = apk.package;
   1012                         action.runner = apk.runner;
   1013                         action.className = full_class_name(apk.package, actionString);
   1014                         action.target = target;
   1015                         testActions.push_back(action);
   1016                         target->testActionCount++;
   1017                     }
   1018                 }
   1019             }
   1020         }
   1021     }
   1022 
   1023     // Run the instrumentation tests
   1024     TestResults testResults;
   1025     if (testActions.size() > 0) {
   1026         print_status("Running tests");
   1027         testsRun = true;
   1028         for (size_t i=0; i<testActions.size(); i++) {
   1029             TestAction& action = testActions[i];
   1030             testResults.SetCurrentAction(&action);
   1031             err = run_instrumentation_test(action.packageName, action.runner, action.className,
   1032                     &testResults);
   1033             check_error(err);
   1034             if (action.passCount == 0 && action.failCount == 0) {
   1035                 action.target->actionsWithNoTests = true;
   1036             }
   1037             int total = action.passCount + action.failCount;
   1038             printf("%sRan %d test%s for %s. ", g_escapeClearLine,
   1039                     total, total > 1 ? "s" : "", action.target->name.c_str());
   1040             if (action.passCount == 0 && action.failCount == 0) {
   1041                 printf("%s%d passed, %d failed%s\n", g_escapeYellowBold, action.passCount,
   1042                         action.failCount, g_escapeEndColor);
   1043             } else if (action.failCount >  0) {
   1044                 printf("%d passed, %s%d failed%s\n", action.passCount, g_escapeRedBold,
   1045                         action.failCount, g_escapeEndColor);
   1046             } else {
   1047                 printf("%s%d passed%s, %d failed\n", g_escapeGreenBold, action.passCount,
   1048                         g_escapeEndColor, action.failCount);
   1049             }
   1050             if (!testResults.IsSuccess()) {
   1051                 printf("\n%sTest didn't finish successfully: %s%s\n", g_escapeRedBold,
   1052                         testResults.GetErrorMessage().c_str(), g_escapeEndColor);
   1053             }
   1054         }
   1055     }
   1056 
   1057     // Launch the activity
   1058     if (activityActions.size() > 0) {
   1059         print_status("Starting activity");
   1060 
   1061         if (activityActions.size() > 1) {
   1062             print_warning("Multiple activities specified.  Will only start the first one:");
   1063             for (size_t i=0; i<activityActions.size(); i++) {
   1064                 ActivityAction& action = activityActions[i];
   1065                 print_warning("   %s",
   1066                         pretty_component_name(action.packageName, action.className).c_str());
   1067             }
   1068         }
   1069 
   1070         const ActivityAction& action = activityActions[0];
   1071         string componentName = action.packageName + "/" + action.className;
   1072         err = run_adb("shell", "am", "start", componentName.c_str(), NULL);
   1073         check_error(err);
   1074     }
   1075 
   1076     //
   1077     // Print summary
   1078     //
   1079 
   1080     printf("\n%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
   1081 
   1082     // Build
   1083     if (goals.size() > 0) {
   1084         printf("%sBuilt:%s\n", g_escapeBold, g_escapeEndColor);
   1085         for (size_t i=0; i<goals.size(); i++) {
   1086             printf("   %s\n", goals[i].c_str());
   1087         }
   1088     }
   1089 
   1090     // Install
   1091     if (syncSystem) {
   1092         if (skipSync) {
   1093             printf("%sSkipped syncing /system partition%s\n", g_escapeBold, g_escapeEndColor);
   1094         } else {
   1095             printf("%sSynced /system partition%s\n", g_escapeBold, g_escapeEndColor);
   1096         }
   1097     }
   1098     if (installApks.size() > 0) {
   1099         bool printedTitle = false;
   1100         for (size_t i=0; i<installApks.size(); i++) {
   1101             const InstallApk& apk = installApks[i];
   1102             if (apk.installed) {
   1103                 if (!printedTitle) {
   1104                     printf("%sInstalled:%s\n", g_escapeBold, g_escapeEndColor);
   1105                     printedTitle = true;
   1106                 }
   1107                 printf("   %s\n", apk.file.filename.c_str());
   1108             }
   1109         }
   1110         printedTitle = false;
   1111         for (size_t i=0; i<installApks.size(); i++) {
   1112             const InstallApk& apk = installApks[i];
   1113             if (!apk.installed) {
   1114                 if (!printedTitle) {
   1115                     printf("%sSkipped install:%s\n", g_escapeBold, g_escapeEndColor);
   1116                     printedTitle = true;
   1117                 }
   1118                 printf("   %s\n", apk.file.filename.c_str());
   1119             }
   1120         }
   1121     }
   1122 
   1123     // Tests
   1124     bool hasErrors = false;
   1125     if (testsRun) {
   1126         printf("%sRan tests:%s\n", g_escapeBold, g_escapeEndColor);
   1127         size_t maxNameLength = 0;
   1128         for (size_t i=0; i<targets.size(); i++) {
   1129             Target* target = targets[i];
   1130             if (target->test) {
   1131                 size_t len = target->name.length();
   1132                 if (len > maxNameLength) {
   1133                     maxNameLength = len;
   1134                 }
   1135             }
   1136         }
   1137         string padding(maxNameLength, ' ');
   1138         for (size_t i=0; i<targets.size(); i++) {
   1139             Target* target = targets[i];
   1140             if (target->testActionCount > 0) {
   1141                 printf("   %s%s", target->name.c_str(), padding.c_str() + target->name.length());
   1142                 if (target->unknownFailureCount > 0) {
   1143                     printf("     %sUnknown failure, see above message.%s\n",
   1144                             g_escapeRedBold, g_escapeEndColor);
   1145                     hasErrors = true;
   1146                 } else if (target->actionsWithNoTests) {
   1147                     printf("     %s%d passed, %d failed%s\n", g_escapeYellowBold,
   1148                             target->testPassCount, target->testFailCount, g_escapeEndColor);
   1149                     hasErrors = true;
   1150                 } else if (target->testFailCount > 0) {
   1151                     printf("     %d passed, %s%d failed%s\n", target->testPassCount,
   1152                             g_escapeRedBold, target->testFailCount, g_escapeEndColor);
   1153                     hasErrors = true;
   1154                 } else {
   1155                     printf("     %s%d passed%s, %d failed\n", g_escapeGreenBold,
   1156                             target->testPassCount, g_escapeEndColor, target->testFailCount);
   1157                 }
   1158             }
   1159         }
   1160     }
   1161     if (activityActions.size() > 1) {
   1162         printf("%sStarted Activity:%s\n", g_escapeBold, g_escapeEndColor);
   1163         const ActivityAction& action = activityActions[0];
   1164         printf("   %s\n", pretty_component_name(action.packageName, action.className).c_str());
   1165     }
   1166 
   1167     printf("%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
   1168     return !hasErrors;
   1169 }
   1170 
   1171 /**
   1172  * Refresh module-info.
   1173  */
   1174 void
   1175 run_refresh()
   1176 {
   1177     int err;
   1178 
   1179     print_status("Initializing");
   1180     const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
   1181     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
   1182     const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
   1183     const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
   1184     const string buildOut = get_out_dir();
   1185     chdir_or_exit(buildTop.c_str());
   1186 
   1187     BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
   1188 
   1189     string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
   1190 
   1191     vector<string> goals;
   1192     goals.push_back(buildOut + "/target/product/" + buildDevice + "/module-info.json");
   1193 
   1194     print_status("Refreshing module-info.json");
   1195     err = build_goals(goals);
   1196     check_error(err);
   1197 }
   1198 
   1199 /**
   1200  * Implement tab completion of the target names from the all modules file.
   1201  */
   1202 void
   1203 run_tab_completion(const string& word)
   1204 {
   1205     const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
   1206     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
   1207     const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
   1208     const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
   1209     const string buildOut = get_out_dir();
   1210     chdir_or_exit(buildTop.c_str());
   1211 
   1212     BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
   1213 
   1214     string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
   1215 
   1216     map<string,Module> modules;
   1217     read_modules(buildOut, buildDevice, &modules, true);
   1218 
   1219     for (map<string,Module>::const_iterator it = modules.begin(); it != modules.end(); it++) {
   1220         if (starts_with(it->first, word)) {
   1221             printf("%s\n", it->first.c_str());
   1222         }
   1223     }
   1224 }
   1225 
   1226 /**
   1227  * Main entry point.
   1228  */
   1229 int
   1230 main(int argc, const char** argv)
   1231 {
   1232     GOOGLE_PROTOBUF_VERIFY_VERSION;
   1233     init_print();
   1234 
   1235     Options options;
   1236     parse_args(&options, argc, argv);
   1237 
   1238     if (options.runHelp) {
   1239         // Help
   1240         print_usage(stdout);
   1241         exit(0);
   1242     } else if (options.runRefresh) {
   1243         run_refresh();
   1244         exit(0);
   1245     } else if (options.runTab) {
   1246         run_tab_completion(options.tabPattern);
   1247         exit(0);
   1248     } else {
   1249         // Normal run
   1250         exit(run_phases(options.targets, options) ? 0 : 1);
   1251     }
   1252 
   1253     return 0;
   1254 }
   1255 
   1256