1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "aapt.h"
18 #include "adb.h"
19 #include "make.h"
20 #include "print.h"
21 #include "util.h"
22 
23 #include <sstream>
24 #include <string>
25 #include <vector>
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 #include <google/protobuf/stubs/common.h>
33 
34 using namespace std;
35 
36 /**
37  * An entry from the command line for something that will be built, installed,
38  * and/or tested.
39  */
40 struct Target {
41     bool build;
42     bool install;
43     bool test;
44     string pattern;
45     string name;
46     vector<string> actions;
47     Module module;
48 
49     int testActionCount;
50 
51     int testPassCount;
52     int testFailCount;
53     bool actionsWithNoTests;
54 
55     Target(bool b, bool i, bool t, const string& p);
56 };
57 
Target(bool b,bool i,bool t,const string & p)58 Target::Target(bool b, bool i, bool t, const string& p)
59     :build(b),
60      install(i),
61      test(t),
62      pattern(p),
63      testActionCount(0),
64      testPassCount(0),
65      testFailCount(0),
66      actionsWithNoTests(false)
67 {
68 }
69 
70 /**
71  * Command line options.
72  */
73 struct Options {
74     // For help
75     bool runHelp;
76 
77     // For tab completion
78     bool runTab;
79     string tabPattern;
80 
81     // For build/install/test
82     bool noRestart;
83     bool reboot;
84     vector<Target*> targets;
85 
86     Options();
87     ~Options();
88 };
89 
Options()90 Options::Options()
91     :runHelp(false),
92      runTab(false),
93      noRestart(false),
94      reboot(false),
95      targets()
96 {
97 }
98 
~Options()99 Options::~Options()
100 {
101 }
102 
103 struct InstallApk
104 {
105     TrackedFile file;
106     bool alwaysInstall;
107     bool installed;
108 
109     InstallApk();
110     InstallApk(const InstallApk& that);
111     InstallApk(const string& filename, bool always);
~InstallApkInstallApk112     ~InstallApk() {};
113 };
114 
InstallApk()115 InstallApk::InstallApk()
116 {
117 }
118 
InstallApk(const InstallApk & that)119 InstallApk::InstallApk(const InstallApk& that)
120     :file(that.file),
121      alwaysInstall(that.alwaysInstall),
122      installed(that.installed)
123 {
124 }
125 
InstallApk(const string & filename,bool always)126 InstallApk::InstallApk(const string& filename, bool always)
127     :file(filename),
128      alwaysInstall(always),
129      installed(false)
130 {
131 }
132 
133 
134 /**
135  * Record for an test that is going to be launched.
136  */
137 struct TestAction {
138     TestAction();
139 
140     // The package name from the apk
141     string packageName;
142 
143     // The test runner class
144     string runner;
145 
146     // The test class, or none if all tests should be run
147     string className;
148 
149     // The original target that requested this action
150     Target* target;
151 
152     // The number of tests that passed
153     int passCount;
154 
155     // The number of tests that failed
156     int failCount;
157 };
158 
TestAction()159 TestAction::TestAction()
160     :passCount(0),
161      failCount(0)
162 {
163 }
164 
165 /**
166  * Record for an activity that is going to be launched.
167  */
168 struct ActivityAction {
169     // The package name from the apk
170     string packageName;
171 
172     // The test class, or none if all tests should be run
173     string className;
174 };
175 
176 /**
177  * Callback class for the am instrument command.
178  */
179 class TestResults: public InstrumentationCallbacks
180 {
181 public:
182     virtual void OnTestStatus(TestStatus& status);
183     virtual void OnSessionStatus(SessionStatus& status);
184 
185     /**
186      * Set the TestAction that the tests are for.
187      * It will be updated with statistics as the tests run.
188      */
189     void SetCurrentAction(TestAction* action);
190 
191 private:
192     TestAction* m_currentAction;
193 };
194 
195 void
OnTestStatus(TestStatus & status)196 TestResults::OnTestStatus(TestStatus& status)
197 {
198     bool found;
199 //    printf("OnTestStatus\n");
200 //    status.PrintDebugString();
201     int32_t resultCode = status.has_results() ? status.result_code() : 0;
202 
203     if (!status.has_results()) {
204         return;
205     }
206     const ResultsBundle &results = status.results();
207 
208     int32_t currentTestNum = get_bundle_int(results, &found, "current", NULL);
209     if (!found) {
210         currentTestNum = -1;
211     }
212 
213     int32_t testCount = get_bundle_int(results, &found, "numtests", NULL);
214     if (!found) {
215         testCount = -1;
216     }
217 
218     string className = get_bundle_string(results, &found, "class", NULL);
219     if (!found) {
220         return;
221     }
222 
223     string testName = get_bundle_string(results, &found, "test", NULL);
224     if (!found) {
225         return;
226     }
227 
228     if (resultCode == 0) {
229         // test passed
230         m_currentAction->passCount++;
231         m_currentAction->target->testPassCount++;
232     } else if (resultCode == 1) {
233         // test starting
234         ostringstream line;
235         line << "Running";
236         if (currentTestNum > 0) {
237             line << ": " << currentTestNum;
238             if (testCount > 0) {
239                 line << " of " << testCount;
240             }
241         }
242         line << ": " << m_currentAction->target->name << ':' << className << "\\#" << testName;
243         print_one_line("%s", line.str().c_str());
244     } else if (resultCode == -2) {
245         // test failed
246         m_currentAction->failCount++;
247         m_currentAction->target->testFailCount++;
248         printf("%s\n%sFailed: %s:%s\\#%s%s\n", g_escapeClearLine, g_escapeRedBold,
249                 m_currentAction->target->name.c_str(), className.c_str(),
250                 testName.c_str(), g_escapeEndColor);
251 
252         string stack = get_bundle_string(results, &found, "stack", NULL);
253         if (found) {
254             printf("%s\n", stack.c_str());
255         }
256     }
257 }
258 
259 void
OnSessionStatus(SessionStatus &)260 TestResults::OnSessionStatus(SessionStatus& /*status*/)
261 {
262     //status.PrintDebugString();
263 }
264 
265 void
SetCurrentAction(TestAction * action)266 TestResults::SetCurrentAction(TestAction* action)
267 {
268     m_currentAction = action;
269 }
270 
271 /**
272  * Prints the usage statement / help text.
273  */
274 static void
print_usage(FILE * out)275 print_usage(FILE* out) {
276     fprintf(out, "usage: bit OPTIONS PATTERN\n");
277     fprintf(out, "\n");
278     fprintf(out, "  Build, sync and test android code.\n");
279     fprintf(out, "\n");
280     fprintf(out, "  The -b -i and -t options allow you to specify which phases\n");
281     fprintf(out, "  you want to run. If none of those options are given, then\n");
282     fprintf(out, "  all phases are run. If any of these options are provided\n");
283     fprintf(out, "  then only the listed phases are run.\n");
284     fprintf(out, "\n");
285     fprintf(out, "  OPTIONS\n");
286     fprintf(out, "  -b     Run a build\n");
287     fprintf(out, "  -i     Install the targets\n");
288     fprintf(out, "  -t     Run the tests\n");
289     fprintf(out, "\n");
290     fprintf(out, "  -n     Don't reboot or restart\n");
291     fprintf(out, "  -r     If the runtime needs to be restarted, do a full reboot\n");
292     fprintf(out, "         instead\n");
293     fprintf(out, "\n");
294     fprintf(out, "  PATTERN\n");
295     fprintf(out, "  One or more targets to build, install and test. The target\n");
296     fprintf(out, "  names are the names that appear in the LOCAL_MODULE or\n");
297     fprintf(out, "  LOCAL_PACKAGE_NAME variables in Android.mk or Android.bp files.\n");
298     fprintf(out, "\n");
299     fprintf(out, "  Building and installing\n");
300     fprintf(out, "  -----------------------\n");
301     fprintf(out, "  The modules specified will be built and then installed. If the\n");
302     fprintf(out, "  files are on the system partition, they will be synced and the\n");
303     fprintf(out, "  attached device rebooted. If they are APKs that aren't on the\n");
304     fprintf(out, "  system partition they are installed with adb install.\n");
305     fprintf(out, "\n");
306     fprintf(out, "  For example:\n");
307     fprintf(out, "    bit framework\n");
308     fprintf(out, "      Builds framework.jar, syncs the system partition and reboots.\n");
309     fprintf(out, "\n");
310     fprintf(out, "    bit SystemUI\n");
311     fprintf(out, "      Builds SystemUI.apk, syncs the system partition and reboots.\n");
312     fprintf(out, "\n");
313     fprintf(out, "    bit CtsProtoTestCases\n");
314     fprintf(out, "      Builds this CTS apk, adb installs it, but does not run any\n");
315     fprintf(out, "      tests.\n");
316     fprintf(out, "\n");
317     fprintf(out, "  Running Unit Tests\n");
318     fprintf(out, "  ------------------\n");
319     fprintf(out, "  To run a unit test, list the test class names and optionally the\n");
320     fprintf(out, "  test method after the module.\n");
321     fprintf(out, "\n");
322     fprintf(out, "  For example:\n");
323     fprintf(out, "    bit CtsProtoTestCases:*\n");
324     fprintf(out, "      Builds this CTS apk, adb installs it, and runs all the tests\n");
325     fprintf(out, "      contained in that apk.\n");
326     fprintf(out, "\n");
327     fprintf(out, "    bit framework CtsProtoTestCases:*\n");
328     fprintf(out, "      Builds the framework and the apk, syncs and reboots, then\n");
329     fprintf(out, "      adb installs CtsProtoTestCases.apk, and runs all tests \n");
330     fprintf(out, "      contained in that apk.\n");
331     fprintf(out, "\n");
332     fprintf(out, "    bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\n");
333     fprintf(out, "    bit CtsProtoTestCases:android.util.proto.cts.ProtoOutputStreamBoolTest\n");
334     fprintf(out, "      Builds and installs CtsProtoTestCases.apk, and runs all the\n");
335     fprintf(out, "      tests in the ProtoOutputStreamBoolTest class.\n");
336     fprintf(out, "\n");
337     fprintf(out, "    bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite\n");
338     fprintf(out, "      Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
339     fprintf(out, "      test method on that class.\n");
340     fprintf(out, "\n");
341     fprintf(out, "    bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite,.ProtoOutputStreamBoolTest\\#testRepeated\n");
342     fprintf(out, "      Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
343     fprintf(out, "      and testRepeated test methods on that class.\n");
344     fprintf(out, "\n");
345     fprintf(out, "  Launching an Activity\n");
346     fprintf(out, "  ---------------------\n");
347     fprintf(out, "  To launch an activity, specify the activity class name after\n");
348     fprintf(out, "  the module name.\n");
349     fprintf(out, "\n");
350     fprintf(out, "  For example:\n");
351     fprintf(out, "    bit StatusBarTest:NotificationBuilderTest\n");
352     fprintf(out, "    bit StatusBarTest:.NotificationBuilderTest\n");
353     fprintf(out, "    bit StatusBarTest:com.android.statusbartest.NotificationBuilderTest\n");
354     fprintf(out, "      Builds and installs StatusBarTest.apk, launches the\n");
355     fprintf(out, "      com.android.statusbartest/.NotificationBuilderTest activity.\n");
356     fprintf(out, "\n");
357     fprintf(out, "\n");
358     fprintf(out, "usage: bit --tab ...\n");
359     fprintf(out, "\n");
360     fprintf(out, "  Lists the targets in a format for tab completion. To get tab\n");
361     fprintf(out, "  completion, add this to your bash environment:\n");
362     fprintf(out, "\n");
363     fprintf(out, "     complete -C \"bit --tab\" bit\n");
364     fprintf(out, "\n");
365     fprintf(out, "  Sourcing android's build/envsetup.sh will do this for you\n");
366     fprintf(out, "  automatically.\n");
367     fprintf(out, "\n");
368     fprintf(out, "\n");
369     fprintf(out, "usage: bit --help\n");
370     fprintf(out, "usage: bit -h\n");
371     fprintf(out, "\n");
372     fprintf(out, "  Print this help message\n");
373     fprintf(out, "\n");
374 }
375 
376 
377 /**
378  * Sets the appropriate flag* variables. If there is a problem with the
379  * commandline arguments, prints the help message and exits with an error.
380  */
381 static void
parse_args(Options * options,int argc,const char ** argv)382 parse_args(Options* options, int argc, const char** argv)
383 {
384     // Help
385     if (argc == 2 && (strcmp(argv[1],  "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
386         options->runHelp = true;
387         return;
388     }
389 
390     // Tab
391     if (argc >= 4 && strcmp(argv[1], "--tab") == 0) {
392         options->runTab = true;
393         options->tabPattern = argv[3];
394         return;
395     }
396 
397     // Normal usage
398     bool anyPhases = false;
399     bool gotPattern = false;
400     bool flagBuild = false;
401     bool flagInstall = false;
402     bool flagTest = false;
403     for (int i=1; i < argc; i++) {
404         string arg(argv[i]);
405         if (arg[0] == '-') {
406             for (size_t j=1; j<arg.size(); j++) {
407                 switch (arg[j]) {
408                     case '-':
409                         break;
410                     case 'b':
411                         if (gotPattern) {
412                             gotPattern = false;
413                             flagInstall = false;
414                             flagTest = false;
415                         }
416                         flagBuild = true;
417                         anyPhases = true;
418                         break;
419                     case 'i':
420                         if (gotPattern) {
421                             gotPattern = false;
422                             flagBuild = false;
423                             flagTest = false;
424                         }
425                         flagInstall = true;
426                         anyPhases = true;
427                         break;
428                     case 't':
429                         if (gotPattern) {
430                             gotPattern = false;
431                             flagBuild = false;
432                             flagInstall = false;
433                         }
434                         flagTest = true;
435                         anyPhases = true;
436                         break;
437                     case 'n':
438                         options->noRestart = true;
439                         break;
440                     case 'r':
441                         options->reboot = true;
442                         break;
443                     default:
444                         fprintf(stderr, "Unrecognized option '%c'\n", arg[j]);
445                         print_usage(stderr);
446                         exit(1);
447                         break;
448                 }
449             }
450         } else {
451             Target* target = new Target(flagBuild || !anyPhases, flagInstall || !anyPhases,
452                     flagTest || !anyPhases, arg);
453             size_t colonPos = arg.find(':');
454             if (colonPos == 0) {
455                 fprintf(stderr, "Test / activity supplied without a module to build: %s\n",
456                         arg.c_str());
457                 print_usage(stderr);
458                 delete target;
459                 exit(1);
460             } else if (colonPos == string::npos) {
461                 target->name = arg;
462             } else {
463                 target->name.assign(arg, 0, colonPos);
464                 size_t beginPos = colonPos+1;
465                 size_t commaPos;
466                 while (true) {
467                     commaPos = arg.find(',', beginPos);
468                     if (commaPos == string::npos) {
469                         if (beginPos != arg.size()) {
470                             target->actions.push_back(string(arg, beginPos, commaPos));
471                         }
472                         break;
473                     } else {
474                         if (commaPos != beginPos) {
475                             target->actions.push_back(string(arg, beginPos, commaPos-beginPos));
476                         }
477                         beginPos = commaPos+1;
478                     }
479                 }
480             }
481             options->targets.push_back(target);
482             gotPattern = true;
483         }
484     }
485     // If no pattern was supplied, give an error
486     if (options->targets.size() == 0) {
487         fprintf(stderr, "No PATTERN supplied.\n\n");
488         print_usage(stderr);
489         exit(1);
490     }
491 }
492 
493 /**
494  * Get an environment variable.
495  * Exits with an error if it is unset or the empty string.
496  */
497 static string
get_required_env(const char * name,bool quiet)498 get_required_env(const char* name, bool quiet)
499 {
500     const char* value = getenv(name);
501     if (value == NULL || value[0] == '\0') {
502         if (!quiet) {
503             fprintf(stderr, "%s not set. Did you source build/envsetup.sh,"
504                     " run lunch and do a build?\n", name);
505         }
506         exit(1);
507     }
508     return string(value);
509 }
510 
511 /**
512  * Get the out directory.
513  *
514  * This duplicates the logic in build/make/core/envsetup.mk (which hasn't changed since 2011)
515  * so that we don't have to wait for get_build_var make invocation.
516  */
517 string
get_out_dir()518 get_out_dir()
519 {
520     const char* out_dir = getenv("OUT_DIR");
521     if (out_dir == NULL || out_dir[0] == '\0') {
522         const char* common_base = getenv("OUT_DIR_COMMON_BASE");
523         if (common_base == NULL || common_base[0] == '\0') {
524             // We don't prefix with buildTop because we cd there and it
525             // makes all the filenames long when being pretty printed.
526             return "out";
527         } else {
528             char pwd[PATH_MAX];
529             if (getcwd(pwd, PATH_MAX) == NULL) {
530                 fprintf(stderr, "Your pwd is too long.\n");
531                 exit(1);
532             }
533             const char* slash = strrchr(pwd, '/');
534             if (slash == NULL) {
535                 slash = "";
536             }
537             string result(common_base);
538             result += slash;
539             return result;
540         }
541     }
542     return string(out_dir);
543 }
544 
545 /**
546  * Check that a system property on the device matches the expected value.
547  * Exits with an error if they don't.
548  */
549 static void
check_device_property(const string & property,const string & expected)550 check_device_property(const string& property, const string& expected)
551 {
552     int err;
553     string deviceValue = get_system_property(property, &err);
554     check_error(err);
555     if (deviceValue != expected) {
556         print_error("There is a mismatch between the build you just did and the device you");
557         print_error("are trying to sync it to in the %s system property", property.c_str());
558         print_error("   build:  %s", expected.c_str());
559         print_error("   device: %s", deviceValue.c_str());
560         exit(1);
561     }
562 }
563 
564 /**
565  * Run the build, install, and test actions.
566  */
567 void
run_phases(vector<Target * > targets,const Options & options)568 run_phases(vector<Target*> targets, const Options& options)
569 {
570     int err = 0;
571 
572     //
573     // Initialization
574     //
575 
576     print_status("Initializing");
577 
578     const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
579     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
580     const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
581     const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
582     const string buildDevice = get_build_var(buildTop, "TARGET_DEVICE", false);
583     const string buildId = get_build_var(buildTop, "BUILD_ID", false);
584     const string buildOut = get_out_dir();
585 
586     // TODO: print_command("cd", buildTop.c_str());
587     chdir(buildTop.c_str());
588 
589     // Get the modules for the targets
590     map<string,Module> modules;
591     read_modules(buildOut, buildDevice, &modules, false);
592     for (size_t i=0; i<targets.size(); i++) {
593         Target* target = targets[i];
594         map<string,Module>::iterator mod = modules.find(target->name);
595         if (mod != modules.end()) {
596             target->module = mod->second;
597         } else {
598             print_error("Error: Could not find module: %s", target->name.c_str());
599             err = 1;
600         }
601     }
602     if (err != 0) {
603         exit(1);
604     }
605 
606     // Choose the goals
607     vector<string> goals;
608     for (size_t i=0; i<targets.size(); i++) {
609         Target* target = targets[i];
610         if (target->build) {
611             goals.push_back(target->name);
612         }
613     }
614 
615     // Figure out whether we need to sync the system and which apks to install
616     string systemPath = buildOut + "/target/product/" + buildDevice + "/system/";
617     string dataPath = buildOut + "/target/product/" + buildDevice + "/data/";
618     bool syncSystem = false;
619     bool alwaysSyncSystem = false;
620     vector<InstallApk> installApks;
621     for (size_t i=0; i<targets.size(); i++) {
622         Target* target = targets[i];
623         if (target->install) {
624             for (size_t j=0; j<target->module.installed.size(); j++) {
625                 const string& file = target->module.installed[j];
626                 // System partition
627                 if (starts_with(file, systemPath)) {
628                     syncSystem = true;
629                     if (!target->build) {
630                         // If a system partition target didn't get built then
631                         // it won't change we will always need to do adb sync
632                         alwaysSyncSystem = true;
633                     }
634                     continue;
635                 }
636                 // Apk in the data partition
637                 if (starts_with(file, dataPath) && ends_with(file, ".apk")) {
638                     // Always install it if we didn't build it because otherwise
639                     // it will never have changed.
640                     installApks.push_back(InstallApk(file, !target->build));
641                     continue;
642                 }
643             }
644         }
645     }
646     map<string,FileInfo> systemFilesBefore;
647     if (syncSystem && !alwaysSyncSystem) {
648         get_directory_contents(systemPath, &systemFilesBefore);
649     }
650 
651     //
652     // Build
653     //
654 
655     // Run the build
656     if (goals.size() > 0) {
657         print_status("Building");
658         err = build_goals(goals);
659         check_error(err);
660     }
661 
662     //
663     // Install
664     //
665 
666     // Sync the system partition and reboot
667     bool skipSync = false;
668     if (syncSystem) {
669         print_status("Syncing /system");
670 
671         if (!alwaysSyncSystem) {
672             // If nothing changed and we weren't forced to sync, skip the reboot for speed.
673             map<string,FileInfo> systemFilesAfter;
674             get_directory_contents(systemPath, &systemFilesAfter);
675             skipSync = !directory_contents_differ(systemFilesBefore, systemFilesAfter);
676         }
677         if (skipSync) {
678             printf("Skipping sync because no files changed.\n");
679         } else {
680             // Do some sanity checks
681             check_device_property("ro.build.product", buildProduct);
682             check_device_property("ro.build.type", buildVariant);
683             check_device_property("ro.build.id", buildId);
684 
685             // Stop & Sync
686             if (!options.noRestart) {
687                 err = run_adb("shell", "stop", NULL);
688                 check_error(err);
689             }
690             err = run_adb("remount", NULL);
691             check_error(err);
692             err = run_adb("sync", "system", NULL);
693             check_error(err);
694 
695             if (!options.noRestart) {
696                 if (options.reboot) {
697                     print_status("Rebooting");
698 
699                     err = run_adb("reboot", NULL);
700                     check_error(err);
701                     err = run_adb("wait-for-device", NULL);
702                     check_error(err);
703                 } else {
704                     print_status("Restarting the runtime");
705 
706                     err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
707                     check_error(err);
708                     err = run_adb("shell", "start", NULL);
709                     check_error(err);
710                 }
711 
712                 while (true) {
713                     string completed = get_system_property("sys.boot_completed", &err);
714                     check_error(err);
715                     if (completed == "1") {
716                         break;
717                     }
718                     sleep(2);
719                 }
720                 sleep(1);
721                 err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
722                 check_error(err);
723             }
724         }
725     }
726 
727     // Install APKs
728     if (installApks.size() > 0) {
729         print_status("Installing APKs");
730         for (size_t i=0; i<installApks.size(); i++) {
731             InstallApk& apk = installApks[i];
732             if (!apk.file.fileInfo.exists || apk.file.HasChanged()) {
733                 // It didn't exist before or it changed, so int needs install
734                 err = run_adb("install", "-r", apk.file.filename.c_str(), NULL);
735                 check_error(err);
736                 apk.installed = true;
737             } else {
738                 printf("APK didn't change. Skipping install of %s\n", apk.file.filename.c_str());
739             }
740         }
741     }
742 
743     //
744     // Actions
745     //
746 
747     // Inspect the apks, and figure out what is an activity and what needs a test runner
748     bool printedInspecting = false;
749     vector<TestAction> testActions;
750     vector<ActivityAction> activityActions;
751     for (size_t i=0; i<targets.size(); i++) {
752         Target* target = targets[i];
753         if (target->test) {
754             for (size_t j=0; j<target->module.installed.size(); j++) {
755                 string filename = target->module.installed[j];
756 
757                 if (!ends_with(filename, ".apk")) {
758                     continue;
759                 }
760 
761                 if (!printedInspecting) {
762                     printedInspecting = true;
763                     print_status("Inspecting APKs");
764                 }
765 
766                 Apk apk;
767                 err = inspect_apk(&apk, filename);
768                 check_error(err);
769 
770                 for (size_t k=0; k<target->actions.size(); k++) {
771                     string actionString = target->actions[k];
772                     if (actionString == "*") {
773                         if (apk.runner.length() == 0) {
774                             print_error("Error: Test requested for apk that doesn't"
775                                     " have an <instrumentation> tag: %s\n",
776                                     target->module.name.c_str());
777                             exit(1);
778                         }
779                         TestAction action;
780                         action.packageName = apk.package;
781                         action.runner = apk.runner;
782                         action.target = target;
783                         testActions.push_back(action);
784                         target->testActionCount++;
785                     } else if (apk.HasActivity(actionString)) {
786                         ActivityAction action;
787                         action.packageName = apk.package;
788                         action.className = full_class_name(apk.package, actionString);
789                         activityActions.push_back(action);
790                     } else {
791                         if (apk.runner.length() == 0) {
792                             print_error("Error: Test requested for apk that doesn't"
793                                     " have an <instrumentation> tag: %s\n",
794                                     target->module.name.c_str());
795                             exit(1);
796                         }
797                         TestAction action;
798                         action.packageName = apk.package;
799                         action.runner = apk.runner;
800                         action.className = full_class_name(apk.package, actionString);
801                         action.target = target;
802                         testActions.push_back(action);
803                         target->testActionCount++;
804                     }
805                 }
806             }
807         }
808     }
809 
810     // Run the instrumentation tests
811     TestResults testResults;
812     if (testActions.size() > 0) {
813         print_status("Running tests");
814         for (size_t i=0; i<testActions.size(); i++) {
815             TestAction& action = testActions[i];
816             testResults.SetCurrentAction(&action);
817             err = run_instrumentation_test(action.packageName, action.runner, action.className,
818                     &testResults);
819             check_error(err);
820             if (action.passCount == 0 && action.failCount == 0) {
821                 action.target->actionsWithNoTests = true;
822             }
823             int total = action.passCount + action.failCount;
824             printf("%sRan %d test%s for %s. ", g_escapeClearLine,
825                     total, total > 1 ? "s" : "", action.target->name.c_str());
826             if (action.passCount == 0 && action.failCount == 0) {
827                 printf("%s%d passed, %d failed%s\n", g_escapeYellowBold, action.passCount,
828                         action.failCount, g_escapeEndColor);
829             } else if (action.failCount >  0) {
830                 printf("%d passed, %s%d failed%s\n", action.passCount, g_escapeRedBold,
831                         action.failCount, g_escapeEndColor);
832             } else {
833                 printf("%s%d passed%s, %d failed\n", g_escapeGreenBold, action.passCount,
834                         g_escapeEndColor, action.failCount);
835             }
836         }
837     }
838 
839     // Launch the activity
840     if (activityActions.size() > 0) {
841         print_status("Starting activity");
842 
843         if (activityActions.size() > 1) {
844             print_warning("Multiple activities specified.  Will only start the first one:");
845             for (size_t i=0; i<activityActions.size(); i++) {
846                 ActivityAction& action = activityActions[i];
847                 print_warning("   %s",
848                         pretty_component_name(action.packageName, action.className).c_str());
849             }
850         }
851 
852         const ActivityAction& action = activityActions[0];
853         string componentName = action.packageName + "/" + action.className;
854         err = run_adb("shell", "am", "start", componentName.c_str(), NULL);
855         check_error(err);
856     }
857 
858     //
859     // Print summary
860     //
861 
862     printf("\n%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
863 
864     // Build
865     if (goals.size() > 0) {
866         printf("%sBuilt:%s\n", g_escapeBold, g_escapeEndColor);
867         for (size_t i=0; i<goals.size(); i++) {
868             printf("   %s\n", goals[i].c_str());
869         }
870     }
871 
872     // Install
873     if (syncSystem) {
874         if (skipSync) {
875             printf("%sSkipped syncing /system partition%s\n", g_escapeBold, g_escapeEndColor);
876         } else {
877             printf("%sSynced /system partition%s\n", g_escapeBold, g_escapeEndColor);
878         }
879     }
880     if (installApks.size() > 0) {
881         bool printedTitle = false;
882         for (size_t i=0; i<installApks.size(); i++) {
883             const InstallApk& apk = installApks[i];
884             if (apk.installed) {
885                 if (!printedTitle) {
886                     printf("%sInstalled:%s\n", g_escapeBold, g_escapeEndColor);
887                     printedTitle = true;
888                 }
889                 printf("   %s\n", apk.file.filename.c_str());
890             }
891         }
892         printedTitle = false;
893         for (size_t i=0; i<installApks.size(); i++) {
894             const InstallApk& apk = installApks[i];
895             if (!apk.installed) {
896                 if (!printedTitle) {
897                     printf("%sSkipped install:%s\n", g_escapeBold, g_escapeEndColor);
898                     printedTitle = true;
899                 }
900                 printf("   %s\n", apk.file.filename.c_str());
901             }
902         }
903     }
904 
905     // Tests
906     if (testActions.size() > 0) {
907         printf("%sRan tests:%s\n", g_escapeBold, g_escapeEndColor);
908         size_t maxNameLength = 0;
909         for (size_t i=0; i<targets.size(); i++) {
910             Target* target = targets[i];
911             if (target->test) {
912                 size_t len = target->name.length();
913                 if (len > maxNameLength) {
914                     maxNameLength = len;
915                 }
916             }
917         }
918         string padding(maxNameLength, ' ');
919         for (size_t i=0; i<targets.size(); i++) {
920             Target* target = targets[i];
921             if (target->testActionCount > 0) {
922                 printf("   %s%s", target->name.c_str(), padding.c_str() + target->name.length());
923                 if (target->actionsWithNoTests) {
924                     printf("     %s%d passed, %d failed%s\n", g_escapeYellowBold,
925                             target->testPassCount, target->testFailCount, g_escapeEndColor);
926                 } else if (target->testFailCount > 0) {
927                     printf("     %d passed, %s%d failed%s\n", target->testPassCount,
928                             g_escapeRedBold, target->testFailCount, g_escapeEndColor);
929                 } else {
930                     printf("     %s%d passed%s, %d failed\n", g_escapeGreenBold,
931                             target->testPassCount, g_escapeEndColor, target->testFailCount);
932                 }
933             }
934         }
935     }
936     if (activityActions.size() > 1) {
937         printf("%sStarted Activity:%s\n", g_escapeBold, g_escapeEndColor);
938         const ActivityAction& action = activityActions[0];
939         printf("   %s\n", pretty_component_name(action.packageName, action.className).c_str());
940     }
941 
942     printf("%s--------------------------------------------%s\n", g_escapeBold, g_escapeEndColor);
943 }
944 
945 /**
946  * Implement tab completion of the target names from the all modules file.
947  */
948 void
run_tab_completion(const string & word)949 run_tab_completion(const string& word)
950 {
951     const string buildTop = get_required_env("ANDROID_BUILD_TOP", true);
952     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
953     const string buildOut = get_out_dir();
954 
955     chdir(buildTop.c_str());
956 
957     string buildDevice = sniff_device_name(buildOut, buildProduct);
958 
959     map<string,Module> modules;
960     read_modules(buildOut, buildDevice, &modules, true);
961 
962     for (map<string,Module>::const_iterator it = modules.begin(); it != modules.end(); it++) {
963         if (starts_with(it->first, word)) {
964             printf("%s\n", it->first.c_str());
965         }
966     }
967 }
968 
969 /**
970  * Main entry point.
971  */
972 int
main(int argc,const char ** argv)973 main(int argc, const char** argv)
974 {
975     GOOGLE_PROTOBUF_VERIFY_VERSION;
976     init_print();
977 
978     Options options;
979     parse_args(&options, argc, argv);
980 
981     if (options.runHelp) {
982         // Help
983         print_usage(stdout);
984         exit(0);
985     } else if (options.runTab) {
986         run_tab_completion(options.tabPattern);
987         exit(0);
988     } else {
989         // Normal run
990         run_phases(options.targets, options);
991     }
992 
993     return 0;
994 }
995 
996