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 
Target(bool b,bool i,bool t,const string & p)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 
Options()92 Options::Options()
93     :runHelp(false),
94      runTab(false),
95      noRestart(false),
96      reboot(false),
97      targets()
98 {
99 }
100 
~Options()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);
~InstallApkInstallApk114     ~InstallApk() {};
115 };
116 
InstallApk()117 InstallApk::InstallApk()
118 {
119 }
120 
InstallApk(const InstallApk & that)121 InstallApk::InstallApk(const InstallApk& that)
122     :file(that.file),
123      alwaysInstall(that.alwaysInstall),
124      installed(that.installed)
125 {
126 }
127 
InstallApk(const string & filename,bool always)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 
TestAction()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
OnTestStatus(TestStatus & status)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
OnSessionStatus(SessionStatus & status)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
SetCurrentAction(TestAction * action)279 TestResults::SetCurrentAction(TestAction* action)
280 {
281     m_currentAction = action;
282 }
283 
284 bool
IsSuccess()285 TestResults::IsSuccess()
286 {
287     return m_sessionStatus.result_code() == -1; // Activity.RESULT_OK.
288 }
289 
290 string
GetErrorMessage()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
print_usage(FILE * out)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
parse_args(Options * options,int argc,const char ** argv)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
get_required_env(const char * name,bool quiet)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
get_out_dir()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
check_device_property(const string & property,const string & expected)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
chdir_or_exit(const char * path)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
run_phases(vector<Target * > targets,const Options & options)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
run_tab_completion(const string & word)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
main(int argc,const char ** argv)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