OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This file defines specific implementation of BrowserDistribution class for | 5 // This file defines specific implementation of BrowserDistribution class for |
6 // Google Chrome. | 6 // Google Chrome. |
7 | 7 |
8 #include "chrome/installer/util/google_chrome_distribution.h" | 8 #include "chrome/installer/util/google_chrome_distribution.h" |
9 | 9 |
10 #include <vector> | 10 #include <vector> |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 const wchar_t kCommandExecuteImplUuid[] = | 53 const wchar_t kCommandExecuteImplUuid[] = |
54 L"{5C65F4B0-3651-4514-B207-D10CB699B14B}"; | 54 L"{5C65F4B0-3651-4514-B207-D10CB699B14B}"; |
55 const wchar_t kDelegateExecuteLibUuid[] = | 55 const wchar_t kDelegateExecuteLibUuid[] = |
56 L"{4E805ED8-EBA0-4601-9681-12815A56EBFD}"; | 56 L"{4E805ED8-EBA0-4601-9681-12815A56EBFD}"; |
57 const wchar_t kDelegateExecuteLibVersion[] = L"1.0"; | 57 const wchar_t kDelegateExecuteLibVersion[] = L"1.0"; |
58 const wchar_t kICommandExecuteImplUuid[] = | 58 const wchar_t kICommandExecuteImplUuid[] = |
59 L"{0BA0D4E9-2259-4963-B9AE-A839F7CB7544}"; | 59 L"{0BA0D4E9-2259-4963-B9AE-A839F7CB7544}"; |
60 | 60 |
61 // The following strings are the possible outcomes of the toast experiment | 61 // The following strings are the possible outcomes of the toast experiment |
62 // as recorded in the |client| field. | 62 // as recorded in the |client| field. |
63 const wchar_t kToastExpControlGroup[] = L"01"; | 63 const wchar_t kToastExpControlGroup[] = L"01"; |
64 const wchar_t kToastExpCancelGroup[] = L"02"; | 64 const wchar_t kToastExpCancelGroup[] = L"02"; |
65 const wchar_t kToastExpUninstallGroup[] = L"04"; | 65 const wchar_t kToastExpUninstallGroup[] = L"04"; |
66 const wchar_t kToastExpTriesOkGroup[] = L"18"; | 66 const wchar_t kToastExpTriesOkGroup[] = L"18"; |
67 const wchar_t kToastExpTriesErrorGroup[] = L"28"; | 67 const wchar_t kToastExpTriesErrorGroup[] = L"28"; |
68 const wchar_t kToastActiveGroup[] = L"40"; | 68 const wchar_t kToastExpTriesOkDefaultGroup[] = L"48"; |
69 const wchar_t kToastUDDirFailure[] = L"40"; | 69 const wchar_t kToastActiveGroup[] = L"40"; |
70 const wchar_t kToastExpBaseGroup[] = L"80"; | 70 const wchar_t kToastUDDirFailure[] = L"40"; |
| 71 const wchar_t kToastExpBaseGroup[] = L"80"; |
71 | 72 |
72 // Substitute the locale parameter in uninstall URL with whatever | 73 // Substitute the locale parameter in uninstall URL with whatever |
73 // Google Update tells us is the locale. In case we fail to find | 74 // Google Update tells us is the locale. In case we fail to find |
74 // the locale, we use US English. | 75 // the locale, we use US English. |
75 string16 LocalizeUrl(const wchar_t* url) { | 76 string16 LocalizeUrl(const wchar_t* url) { |
76 string16 language; | 77 string16 language; |
77 if (!GoogleUpdateSettings::GetLanguage(&language)) | 78 if (!GoogleUpdateSettings::GetLanguage(&language)) |
78 language = L"en-US"; // Default to US English. | 79 language = L"en-US"; // Default to US English. |
79 return ReplaceStringPlaceholders(url, language.c_str(), NULL); | 80 return ReplaceStringPlaceholders(url, language.c_str(), NULL); |
80 } | 81 } |
(...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 if (last_write) | 606 if (last_write) |
606 CloseHandle((HANDLE) reg_key_handle); | 607 CloseHandle((HANDLE) reg_key_handle); |
607 } else { | 608 } else { |
608 // Write to HKCU. | 609 // Write to HKCU. |
609 GoogleUpdateSettings::SetClient(experiment_group); | 610 GoogleUpdateSettings::SetClient(experiment_group); |
610 } | 611 } |
611 } | 612 } |
612 | 613 |
613 bool GoogleChromeDistribution::GetExperimentDetails( | 614 bool GoogleChromeDistribution::GetExperimentDetails( |
614 UserExperiment* experiment, int flavor) { | 615 UserExperiment* experiment, int flavor) { |
| 616 struct FlavorDetails { |
| 617 int heading_id; |
| 618 int flags; |
| 619 }; |
615 // Maximum number of experiment flavors we support. | 620 // Maximum number of experiment flavors we support. |
616 static const int kMax = 4; | 621 static const int kMax = 4; |
617 // This struct determines which experiment flavors we show for each locale and | 622 // This struct determines which experiment flavors we show for each locale and |
618 // brand. | 623 // brand. |
619 // | 624 // |
620 // The big experiment in Dec 2009 used TGxx and THxx. | 625 // The big experiment in Dec 2009 used TGxx and THxx. |
621 // The big experiment in Feb 2010 used TKxx and TLxx. | 626 // The big experiment in Feb 2010 used TKxx and TLxx. |
622 // The big experiment in Apr 2010 used TMxx and TNxx. | 627 // The big experiment in Apr 2010 used TMxx and TNxx. |
623 // The big experiment in Oct 2010 used TVxx TWxx TXxx TYxx. | 628 // The big experiment in Oct 2010 used TVxx TWxx TXxx TYxx. |
624 // The big experiment in Feb 2011 used SJxx SKxx SLxx SMxx. | 629 // The big experiment in Feb 2011 used SJxx SKxx SLxx SMxx. |
625 // Note: the plugin infobar experiment uses PIxx codes. | 630 // Note: the plugin infobar experiment uses PIxx codes. |
626 using namespace attrition_experiments; | 631 using namespace attrition_experiments; |
| 632 |
627 static const struct UserExperimentDetails { | 633 static const struct UserExperimentDetails { |
628 const wchar_t* locale; // Locale to show this experiment for (* for all). | 634 const wchar_t* locale; // Locale to show this experiment for (* for all). |
629 const wchar_t* brands; // Brand codes show this experiment for (* for all). | 635 const wchar_t* brands; // Brand codes show this experiment for (* for all). |
630 int control_group; // Size of the control group, in percentages. | 636 int control_group; // Size of the control group, in percentages. |
631 const wchar_t prefix1; // The first letter for the experiment code. | 637 const wchar_t* prefix; // The two letter experiment code. The second letter |
632 const wchar_t prefix2; // The second letter for the experiment code. This | 638 // will be incremented with the flavor. |
633 // will be incremented by one for each additional | 639 FlavorDetails flavors[kMax]; |
634 // experiment flavor beyond the first. | 640 } kExperiments[] = { |
635 int flavors; // Numbers of flavors for this experiment. Should | 641 // The first match from top to bottom is used so this list should be ordered |
636 // always be positive and never exceed the number | 642 // most-specific rule first. |
637 // of headings (below). | 643 { L"*", L"CHMA", // All locales, CHMA brand. |
638 int headings[kMax]; // A list of IDs per experiment. 0 == no heading. | 644 25, // 25 percent control group. |
639 } kExperimentFlavors[] = { | 645 L"ZA", // Experiment is ZAxx, ZBxx, ZCxx, ZDxx etc. |
640 // This list should be ordered most-specific rule first (catch-all, like all | 646 // Three flavors. |
641 // brands or all locales should be last). | 647 { { IDS_TRY_TOAST_HEADING3, kDontBugMeAsButton | kUninstall | kWhyLink }, |
642 | 648 { IDS_TRY_TOAST_HEADING3, 0 }, |
643 // The experiment with the more compact bubble. This one is a bit special | 649 { IDS_TRY_TOAST_HEADING3, kMakeDefault }, |
644 // because it is split into two: CAxx is regular style bubble and CBxx is | 650 { 0, 0 }, |
645 // compact style bubble. See |compact_bubble| below. | 651 } |
646 {L"en-US", kBrief, 1, L'C', L'A', 2, { kEnUs3, kEnUs3, 0, 0 } }, | 652 }, |
647 | 653 { L"*", L"GGRV", // All locales, GGRV is enterprise. |
648 // Catch-all rules. | 654 0, // 0 percent control group. |
649 {kAll, kAll, 1, L'B', L'A', 1, {kEnUs3, 0, 0, 0} }, | 655 L"EA", // Experiment is EAxx, EBxx, etc. |
| 656 // No flavors means no experiment. |
| 657 { { 0, 0 }, |
| 658 { 0, 0 }, |
| 659 { 0, 0 }, |
| 660 { 0, 0 } |
| 661 } |
| 662 } |
650 }; | 663 }; |
651 | 664 |
652 string16 locale; | 665 string16 locale; |
653 GoogleUpdateSettings::GetLanguage(&locale); | 666 GoogleUpdateSettings::GetLanguage(&locale); |
654 if (locale.empty() || (locale == ASCIIToWide("en"))) | 667 if (locale.empty() || (locale == ASCIIToWide("en"))) |
655 locale = ASCIIToWide("en-US"); | 668 locale = ASCIIToWide("en-US"); |
656 | 669 |
657 string16 brand; | 670 string16 brand; |
658 if (!GoogleUpdateSettings::GetBrand(&brand)) | 671 if (!GoogleUpdateSettings::GetBrand(&brand)) |
659 brand = ASCIIToWide(""); // Could still be viable for catch-all rules. | 672 brand = ASCIIToWide(""); // Could still be viable for catch-all rules. |
660 if (brand == kEnterprise) | |
661 return false; | |
662 | 673 |
663 for (int i = 0; i < arraysize(kExperimentFlavors); ++i) { | 674 for (int i = 0; i < arraysize(kExperiments); ++i) { |
664 // A maximum of four flavors are supported at the moment. | 675 if (kExperiments[i].locale != locale && |
665 CHECK_LE(kExperimentFlavors[i].flavors, kMax); | 676 kExperiments[i].locale != ASCIIToWide("*")) |
666 CHECK_GT(kExperimentFlavors[i].flavors, 0); | |
667 // Make sure each experiment has valid headings. | |
668 for (int f = 0; f < kMax; ++f) { | |
669 if (f < kExperimentFlavors[i].flavors) { | |
670 CHECK_GT(kExperimentFlavors[i].headings[f], 0); | |
671 } else { | |
672 CHECK_EQ(kExperimentFlavors[i].headings[f], 0); | |
673 } | |
674 } | |
675 // The prefix has to be a valid two letter combo. | |
676 CHECK(kExperimentFlavors[i].prefix1 >= 'A'); | |
677 CHECK(kExperimentFlavors[i].prefix2 >= 'A'); | |
678 CHECK(kExperimentFlavors[i].prefix2 + | |
679 kExperimentFlavors[i].flavors - 1 <= 'Z'); | |
680 | |
681 if (kExperimentFlavors[i].locale != locale && | |
682 kExperimentFlavors[i].locale != ASCIIToWide("*")) | |
683 continue; | 677 continue; |
684 | 678 |
685 std::vector<string16> brand_codes; | 679 std::vector<string16> brand_codes; |
686 base::SplitString(kExperimentFlavors[i].brands, L',', &brand_codes); | 680 base::SplitString(kExperiments[i].brands, L',', &brand_codes); |
687 if (brand_codes.empty()) | 681 if (brand_codes.empty()) |
688 return false; | 682 return false; |
689 for (std::vector<string16>::iterator it = brand_codes.begin(); | 683 for (std::vector<string16>::iterator it = brand_codes.begin(); |
690 it != brand_codes.end(); ++it) { | 684 it != brand_codes.end(); ++it) { |
691 if (*it != brand && *it != L"*") | 685 if (*it != brand && *it != L"*") |
692 continue; | 686 continue; |
| 687 // We have found our match. |
| 688 const UserExperimentDetails& match = kExperiments[i]; |
| 689 // Find out how many flavors we have. Zero means no experiment. |
| 690 int num_flavors = 0; |
| 691 while (match.flavors[num_flavors].heading_id) { ++num_flavors; } |
| 692 if (!num_flavors) |
| 693 return false; |
693 | 694 |
694 // We have found our match. | |
695 if (flavor < 0) | 695 if (flavor < 0) |
696 flavor = base::RandInt(0, kExperimentFlavors[i].flavors - 1); | 696 flavor = base::RandInt(0, num_flavors - 1); |
697 experiment->flavor = flavor; | 697 experiment->flavor = flavor; |
698 experiment->heading = kExperimentFlavors[i].headings[flavor]; | 698 experiment->heading = match.flavors[flavor].heading_id; |
699 experiment->control_group = kExperimentFlavors[i].control_group; | 699 experiment->control_group = match.control_group; |
700 experiment->prefix.resize(2); | 700 const wchar_t prefix[] = { match.prefix[0], match.prefix[1] + flavor, 0 }; |
701 experiment->prefix[0] = kExperimentFlavors[i].prefix1; | 701 experiment->prefix = prefix; |
702 experiment->prefix[1] = kExperimentFlavors[i].prefix2 + flavor; | 702 experiment->flags = match.flavors[flavor].flags; |
703 experiment->compact_bubble = (brand == kBrief) && (flavor == 1); | |
704 return true; | 703 return true; |
705 } | 704 } |
706 } | 705 } |
707 | 706 |
708 return false; | 707 return false; |
709 } | 708 } |
710 | 709 |
711 // Currently we only have one experiment: the inactive user toast. Which only | 710 // Currently we only have one experiment: the inactive user toast. Which only |
712 // applies for users doing upgrades. | 711 // applies for users doing upgrades. |
713 | 712 |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
846 case chrome::RESULT_CODE_NORMAL_EXIT_CANCEL: | 845 case chrome::RESULT_CODE_NORMAL_EXIT_CANCEL: |
847 outcome = kToastExpCancelGroup; | 846 outcome = kToastExpCancelGroup; |
848 break; | 847 break; |
849 case chrome::RESULT_CODE_NORMAL_EXIT_EXP2: | 848 case chrome::RESULT_CODE_NORMAL_EXIT_EXP2: |
850 outcome = kToastExpUninstallGroup; | 849 outcome = kToastExpUninstallGroup; |
851 break; | 850 break; |
852 default: | 851 default: |
853 outcome = kToastExpTriesErrorGroup; | 852 outcome = kToastExpTriesErrorGroup; |
854 }; | 853 }; |
855 | 854 |
| 855 if (outcome == kToastExpTriesOkGroup) { |
| 856 // User tried chrome, but if it had the default group button it belongs |
| 857 // to a different outcome group. |
| 858 UserExperiment experiment; |
| 859 if (GetExperimentDetails(&experiment, flavor)) { |
| 860 outcome = experiment.flags & kMakeDefault ? kToastExpTriesOkDefaultGroup : |
| 861 kToastExpTriesOkGroup; |
| 862 } |
| 863 } |
| 864 |
856 // Write to the |client| key for the last time. | 865 // Write to the |client| key for the last time. |
857 SetClient(experiment_group + outcome, true); | 866 SetClient(experiment_group + outcome, true); |
858 | 867 |
859 if (outcome != kToastExpUninstallGroup) | 868 if (outcome != kToastExpUninstallGroup) |
860 return; | 869 return; |
861 | 870 |
862 // The user wants to uninstall. This is a best effort operation. Note that | 871 // The user wants to uninstall. This is a best effort operation. Note that |
863 // we waited for chrome to exit so the uninstall would not detect chrome | 872 // we waited for chrome to exit so the uninstall would not detect chrome |
864 // running. | 873 // running. |
865 bool system_level_toast = CommandLine::ForCurrentProcess()->HasSwitch( | 874 bool system_level_toast = CommandLine::ForCurrentProcess()->HasSwitch( |
866 installer::switches::kSystemLevelToast); | 875 installer::switches::kSystemLevelToast); |
867 | 876 |
868 CommandLine cmd(InstallUtil::GetChromeUninstallCmd(system_level_toast, | 877 CommandLine cmd(InstallUtil::GetChromeUninstallCmd(system_level_toast, |
869 GetType())); | 878 GetType())); |
870 base::LaunchProcess(cmd, base::LaunchOptions(), NULL); | 879 base::LaunchProcess(cmd, base::LaunchOptions(), NULL); |
871 } | 880 } |
872 #endif | 881 #endif |
OLD | NEW |