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