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