summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-31 03:59:20 +0000
committerrobertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-31 03:59:20 +0000
commitebcb5207a92da2acf2034d4e2d9054b76b41c6d5 (patch)
tree6d6f2244e08bf66427f9734cf35e9a29dfa6f3d8
parent716a6125dd1633606261ba49b30408a466a6fc44 (diff)
downloadchromium_src-ebcb5207a92da2acf2034d4e2d9054b76b41c6d5.zip
chromium_src-ebcb5207a92da2acf2034d4e2d9054b76b41c6d5.tar.gz
chromium_src-ebcb5207a92da2acf2034d4e2d9054b76b41c6d5.tar.bz2
Implementation of GCAPI reactivation.
Also, some cleanup in gcapi_tests such that it now only runs gtest tests by default. BUG=111453 TEST=gcapi_tests.exe Review URL: https://chromiumcodereview.appspot.com/9288056 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119841 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/chrome_installer.gypi6
-rw-r--r--chrome/installer/gcapi/gcapi.cc72
-rw-r--r--chrome/installer/gcapi/gcapi.def2
-rw-r--r--chrome/installer/gcapi/gcapi.h45
-rw-r--r--chrome/installer/gcapi/gcapi_reactivation.cc77
-rw-r--r--chrome/installer/gcapi/gcapi_reactivation.h19
-rw-r--r--chrome/installer/gcapi/gcapi_reactivation_test.cc186
-rw-r--r--chrome/installer/gcapi/gcapi_test.cc13
8 files changed, 413 insertions, 7 deletions
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi
index 6a9cf37..961c9a8 100644
--- a/chrome/chrome_installer.gypi
+++ b/chrome/chrome_installer.gypi
@@ -14,6 +14,7 @@
'target_name': 'gcapi_dll',
'type': 'loadable_module',
'dependencies': [
+ 'gcapi_lib',
'installer_util',
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/google_update/google_update.gyp:google_update',
@@ -22,9 +23,7 @@
'<(DEPTH)',
],
'sources': [
- 'installer/gcapi/gcapi.cc',
'installer/gcapi/gcapi.def',
- 'installer/gcapi/gcapi.h',
],
},
{
@@ -41,6 +40,8 @@
'sources': [
'installer/gcapi/gcapi.cc',
'installer/gcapi/gcapi.h',
+ 'installer/gcapi/gcapi_reactivation.cc',
+ 'installer/gcapi/gcapi_reactivation.h',
],
},
{
@@ -60,6 +61,7 @@
],
'sources': [
'installer/gcapi/gcapi_last_run_test.cc',
+ 'installer/gcapi/gcapi_reactivation_test.cc',
'installer/gcapi/gcapi_test.cc',
'installer/gcapi/gcapi_test.rc',
'installer/gcapi/resource.h',
diff --git a/chrome/installer/gcapi/gcapi.cc b/chrome/installer/gcapi/gcapi.cc
index bac5179..79d3a3c 100644
--- a/chrome/installer/gcapi/gcapi.cc
+++ b/chrome/installer/gcapi/gcapi.cc
@@ -29,6 +29,7 @@
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_handle.h"
+#include "chrome/installer/gcapi/gcapi_reactivation.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/util_constants.h"
@@ -539,3 +540,74 @@ int __stdcall GoogleChromeDaysSinceLastRun() {
return days_since_last_run;
}
+
+BOOL __stdcall CanOfferReactivation(const wchar_t* brand_code,
+ int previous_brand_codes_length,
+ const wchar_t** previous_brand_codes,
+ DWORD* error_code) {
+ DCHECK(error_code);
+
+ if (!brand_code ||
+ (previous_brand_codes_length > 0 && previous_brand_codes == NULL)) {
+ if (error_code)
+ *error_code = REACTIVATE_ERROR_INVALID_INPUT;
+ return FALSE;
+ }
+
+ bool has_system_install = IsChromeInstalled(HKEY_LOCAL_MACHINE);
+ bool has_user_install = IsChromeInstalled(HKEY_CURRENT_USER);
+
+ if (!has_system_install && !has_user_install) {
+ if (error_code)
+ *error_code = REACTIVATE_ERROR_NOTINSTALLED;
+ return FALSE;
+ }
+
+ int days_since_last_run = GoogleChromeDaysSinceLastRun();
+ if (days_since_last_run > 0 &&
+ days_since_last_run < kReactivationMinDaysDormant) {
+ if (error_code)
+ *error_code = REACTIVATE_ERROR_NOTDORMANT;
+ return FALSE;
+ }
+
+ // Make sure we haven't previously been reactivated by this brand code
+ // or any of the previous brand codes from this partner.
+ std::vector<std::wstring> reactivation_brands;
+ reactivation_brands.push_back(brand_code);
+ if (previous_brand_codes_length > 0 && previous_brand_codes != NULL) {
+ std::copy(previous_brand_codes,
+ previous_brand_codes + previous_brand_codes_length,
+ std::back_inserter(reactivation_brands));
+ }
+ if (HasBeenReactivatedByBrandCodes(reactivation_brands)) {
+ if (error_code)
+ *error_code = REACTIVATE_ERROR_ALREADY_REACTIVATED;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL __stdcall ReactivateChrome(wchar_t* brand_code,
+ int previous_brand_codes_length,
+ const wchar_t** previous_brand_codes,
+ DWORD* error_code) {
+ BOOL result = FALSE;
+ if (CanOfferReactivation(brand_code,
+ previous_brand_codes_length,
+ previous_brand_codes,
+ error_code)) {
+ if (SetReactivationBrandCode(brand_code)) {
+ // TODO(robertshield): Set Omaha reg key to add experiment label for
+ // tracking 7DA.
+ result = TRUE;
+ } else {
+ if (error_code)
+ *error_code = REACTIVATE_ERROR_REACTIVATION_FAILED;
+ }
+ }
+
+ return result;
+}
+
diff --git a/chrome/installer/gcapi/gcapi.def b/chrome/installer/gcapi/gcapi.def
index ad7286f..8785c25 100644
--- a/chrome/installer/gcapi/gcapi.def
+++ b/chrome/installer/gcapi/gcapi.def
@@ -9,3 +9,5 @@ EXPORTS
LaunchGoogleChrome PRIVATE
LaunchGoogleChromeWithDimensions @16 PRIVATE
GoogleChromeDaysSinceLastRun PRIVATE
+ CanOfferReactivation PRIVATE
+ ReactivateChrome PRIVATE
diff --git a/chrome/installer/gcapi/gcapi.h b/chrome/installer/gcapi/gcapi.h
index a9fd040..30a5226 100644
--- a/chrome/installer/gcapi/gcapi.h
+++ b/chrome/installer/gcapi/gcapi.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -17,6 +17,17 @@ extern "C" {
#define GCCC_ERROR_ALREADYOFFERED 0x10
#define GCCC_ERROR_INTEGRITYLEVEL 0x20
+// Error conditions for CanReactivateChrome().
+#define REACTIVATE_ERROR_NOTINSTALLED 0x01
+#define REACTIVATE_ERROR_NOTDORMANT 0x02
+#define REACTIVATE_ERROR_ALREADY_REACTIVATED 0x04
+#define REACTIVATE_ERROR_INVALID_INPUT 0x08
+#define REACTIVATE_ERROR_REACTIVATION_FAILED 0x10
+
+// The minimum number of days an installation can be dormant before reactivation
+// may be offered.
+const int kReactivationMinDaysDormant = 50;
+
// This function returns TRUE if Google Chrome should be offered.
// If the return is FALSE, the reasons DWORD explains why. If you don't care
// for the reason, you can pass NULL for reasons.
@@ -54,11 +65,41 @@ BOOL __stdcall LaunchGoogleChromeWithDimensions(int x,
// launched.
int __stdcall GoogleChromeDaysSinceLastRun();
-// Funtion pointer type declarations to use with GetProcAddress.
+// Returns true if a vendor with the specified |brand_code| may offer
+// reactivation at this time. If the vendor has previously used other brand
+// codes, they must pass them in an array of size |previous_brand_codes_length|
+// as |previous_brand_codes|. Returns false if the vendor may not offer
+// reactivation at this time, and places one of the REACTIVATE_ERROR_XXX values
+// in |error_code| if |error_code| is non-null.
+BOOL __stdcall CanOfferReactivation(const wchar_t* brand_code,
+ int previous_brand_codes_length,
+ const wchar_t** previous_brand_codes,
+ DWORD* error_code);
+
+// Attempts to reactivate Chrome for the specified |brand_code|. If the vendor
+// has previously used other brand codes, they must pass them in an array of
+// size |previous_brand_codes_length| as |previous_brand_codes|. Returns false
+// if reactivation fails, and places one of the REACTIVATE_ERROR_XXX values
+// in |error_code| if |error_code| is non-null.
+BOOL __stdcall ReactivateChrome(wchar_t* brand_code,
+ int previous_brand_codes_length,
+ const wchar_t** previous_brand_codes,
+ DWORD* error_code);
+
+// Function pointer type declarations to use with GetProcAddress.
typedef BOOL (__stdcall *GCCC_CompatibilityCheck)(BOOL, DWORD *);
typedef BOOL (__stdcall *GCCC_LaunchGC)(HANDLE *);
typedef BOOL (__stdcall *GCCC_LaunchGCWithDimensions)(int, int, int, int);
typedef int (__stdcall *GCCC_GoogleChromeDaysSinceLastRun)();
+typedef BOOL (__stdcall *GCCC_CanOfferReactivation)(const wchar_t*,
+ int,
+ const wchar_t**,
+ DWORD*);
+typedef BOOL (__stdcall *GCCC_ReactivateChrome)(const wchar_t*,
+ int,
+ const wchar_t**,
+ DWORD*);
+
} // extern "C"
#endif // CHROME_INSTALLER_GCAPI_GCAPI_H_
diff --git a/chrome/installer/gcapi/gcapi_reactivation.cc b/chrome/installer/gcapi/gcapi_reactivation.cc
new file mode 100644
index 0000000..6755e2f
--- /dev/null
+++ b/chrome/installer/gcapi/gcapi_reactivation.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/installer/gcapi/gcapi_reactivation.h"
+
+#include "base/time.h"
+#include "base/win/registry.h"
+#include "chrome/installer/util/google_update_constants.h"
+
+using base::Time;
+using base::win::RegKey;
+
+namespace {
+const wchar_t kReactivationHistoryKey[] = L"reactivation";
+
+std::wstring GetReactivationHistoryKeyPath() {
+ std::wstring reactivation_path(google_update::kRegPathClientState);
+ reactivation_path += L"\\";
+ reactivation_path += google_update::kChromeUpgradeCode;
+ reactivation_path += L"\\";
+ reactivation_path += kReactivationHistoryKey;
+ return reactivation_path;
+}
+} // namespace
+
+bool HasBeenReactivatedByBrandCodes(
+ const std::vector<std::wstring>& brand_codes) {
+ bool success = false;
+
+ RegKey reactivation_key(HKEY_CURRENT_USER,
+ GetReactivationHistoryKeyPath().c_str(),
+ KEY_QUERY_VALUE);
+ if (reactivation_key.Valid()) {
+ std::vector<std::wstring>::const_iterator brand_iter(brand_codes.begin());
+ for (; brand_iter != brand_codes.end(); ++brand_iter) {
+ if (reactivation_key.HasValue(brand_iter->c_str())) {
+ success = true;
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+bool SetReactivationBrandCode(const std::wstring& brand_code) {
+ bool success = false;
+
+ std::wstring path(google_update::kRegPathClientState);
+ path += L"\\";
+ path += google_update::kChromeUpgradeCode;
+
+ RegKey client_state_key(HKEY_CURRENT_USER, path.c_str(), KEY_SET_VALUE);
+ if (client_state_key.Valid()) {
+ success = client_state_key.WriteValue(
+ google_update::kRegRLZReactivationBrandField,
+ brand_code.c_str()) == ERROR_SUCCESS;
+ }
+
+ if (success) {
+ // Store this brand code in the reactivation history. Store it with a
+ // a currently un-used timestamp for future proofing.
+ RegKey reactivation_key(HKEY_CURRENT_USER,
+ GetReactivationHistoryKeyPath().c_str(),
+ KEY_WRITE);
+ if (reactivation_key.Valid()) {
+ int64 timestamp = Time::Now().ToInternalValue();
+ reactivation_key.WriteValue(brand_code.c_str(),
+ &timestamp,
+ sizeof(timestamp),
+ REG_QWORD);
+ }
+ }
+
+ return success;
+} \ No newline at end of file
diff --git a/chrome/installer/gcapi/gcapi_reactivation.h b/chrome/installer/gcapi/gcapi_reactivation.h
new file mode 100644
index 0000000..5ace0b8
--- /dev/null
+++ b/chrome/installer/gcapi/gcapi_reactivation.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_INSTALLER_GCAPI_GCAPI_REACTIVATION_H_
+#define CHROME_INSTALLER_GCAPI_GCAPI_REACTIVATION_H_
+#pragma once
+
+#include <windows.h>
+
+#include <string>
+#include <vector>
+
+bool HasBeenReactivatedByBrandCodes(
+ const std::vector<std::wstring>& brand_codes);
+
+bool SetReactivationBrandCode(const std::wstring& brand_code);
+
+#endif // CHROME_INSTALLER_GCAPI_GCAPI_REACTIVATION_H_
diff --git a/chrome/installer/gcapi/gcapi_reactivation_test.cc b/chrome/installer/gcapi/gcapi_reactivation_test.cc
new file mode 100644
index 0000000..9cadafc
--- /dev/null
+++ b/chrome/installer/gcapi/gcapi_reactivation_test.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
+#include "base/stringprintf.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/registry.h"
+#include "chrome/common/guid.h"
+#include "chrome/installer/gcapi/gcapi.h"
+#include "chrome/installer/gcapi/gcapi_reactivation.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::win::RegKey;
+
+
+class GCAPIReactivationTest : public ::testing::Test {
+ protected:
+ void SetUp() {
+ // Override keys - this is undone during destruction.
+ std::wstring hkcu_override = base::StringPrintf(
+ L"hkcu_override\\%ls", ASCIIToWide(guid::GenerateGUID()));
+ override_manager_.OverrideRegistry(HKEY_CURRENT_USER, hkcu_override);
+ }
+
+ bool SetChromeInstallMarker(HKEY hive) {
+ // Create the client state keys in the right places.
+ std::wstring reg_path(google_update::kRegPathClients);
+ reg_path += L"\\";
+ reg_path += google_update::kChromeUpgradeCode;
+ RegKey client_state(hive,
+ reg_path.c_str(),
+ KEY_CREATE_SUB_KEY | KEY_SET_VALUE);
+ return (client_state.Valid() &&
+ client_state.WriteValue(
+ google_update::kRegVersionField, L"1.2.3.4") == ERROR_SUCCESS);
+ }
+
+ bool SetLastRunTime(HKEY hive, int64 last_run_time) {
+ return SetLastRunTimeString(hive, base::Int64ToString16(last_run_time));
+ }
+
+ bool SetLastRunTimeString(HKEY hive, const string16& last_run_time_string) {
+ const wchar_t* base_path =
+ (hive == HKEY_LOCAL_MACHINE) ?
+ google_update::kRegPathClientStateMedium :
+ google_update::kRegPathClientState;
+ std::wstring path(base_path);
+ path += L"\\";
+ path += google_update::kChromeUpgradeCode;
+
+ RegKey client_state(hive, path.c_str(), KEY_SET_VALUE);
+ return (client_state.Valid() &&
+ client_state.WriteValue(
+ google_update::kRegLastRunTimeField,
+ last_run_time_string.c_str()) == ERROR_SUCCESS);
+ }
+
+ std::wstring GetReactivationString(HKEY hive) {
+ const wchar_t* base_path =
+ (hive == HKEY_LOCAL_MACHINE) ?
+ google_update::kRegPathClientStateMedium :
+ google_update::kRegPathClientState;
+ std::wstring path(base_path);
+ path += L"\\";
+ path += google_update::kChromeUpgradeCode;
+
+ RegKey client_state(hive, path.c_str(), KEY_QUERY_VALUE);
+ if (client_state.Valid()) {
+ std::wstring actual_brand;
+ if (client_state.ReadValue(google_update::kRegRLZReactivationBrandField,
+ &actual_brand) == ERROR_SUCCESS) {
+ return actual_brand;
+ }
+ }
+
+ return L"ERROR";
+ }
+
+ private:
+ registry_util::RegistryOverrideManager override_manager_;
+};
+
+TEST_F(GCAPIReactivationTest, CheckSetReactivationBrandCode) {
+ EXPECT_TRUE(SetReactivationBrandCode(L"GAGA"));
+ EXPECT_EQ(L"GAGA", GetReactivationString(HKEY_CURRENT_USER));
+
+ std::vector<std::wstring> check_codes;
+ check_codes.push_back(L"GAGA");
+ EXPECT_TRUE(HasBeenReactivatedByBrandCodes(check_codes));
+
+ check_codes.push_back(L"GOOGOO");
+ EXPECT_TRUE(HasBeenReactivatedByBrandCodes(check_codes));
+
+ check_codes.erase(check_codes.begin());
+ EXPECT_FALSE(HasBeenReactivatedByBrandCodes(check_codes));
+}
+
+TEST_F(GCAPIReactivationTest, CanOfferReactivation_Basic) {
+ const wchar_t* previous_brands[] = {L"GOOGOO", L"MAMA", L"DADA"};
+ DWORD error;
+
+ // We're not installed yet. Make sure CanOfferReactivation fails.
+ EXPECT_FALSE(CanOfferReactivation(L"GAGA", arraysize(previous_brands),
+ previous_brands, &error));
+ EXPECT_EQ(REACTIVATE_ERROR_NOTINSTALLED, error);
+
+ // Now pretend to be installed. CanOfferReactivation should pass.
+ EXPECT_TRUE(SetChromeInstallMarker(HKEY_CURRENT_USER));
+ EXPECT_TRUE(CanOfferReactivation(L"GAGA", arraysize(previous_brands),
+ previous_brands, &error));
+
+ // Now set a recent last_run value. CanOfferReactivation should fail again.
+ Time hkcu_last_run = Time::NowFromSystemTime() - TimeDelta::FromDays(20);
+ EXPECT_TRUE(SetLastRunTime(HKEY_CURRENT_USER,
+ hkcu_last_run.ToInternalValue()));
+ EXPECT_FALSE(CanOfferReactivation(L"GAGA", arraysize(previous_brands),
+ previous_brands, &error));
+ EXPECT_EQ(REACTIVATE_ERROR_NOTDORMANT, error);
+
+ // Now set a last_run value that exceeds the threshold.
+ hkcu_last_run = Time::NowFromSystemTime() -
+ TimeDelta::FromDays(kReactivationMinDaysDormant);
+ EXPECT_TRUE(SetLastRunTime(HKEY_CURRENT_USER,
+ hkcu_last_run.ToInternalValue()));
+ EXPECT_TRUE(CanOfferReactivation(L"GAGA", arraysize(previous_brands),
+ previous_brands, &error));
+
+ // Test some invalid inputs
+ EXPECT_FALSE(CanOfferReactivation(NULL, arraysize(previous_brands),
+ previous_brands, &error));
+ EXPECT_EQ(REACTIVATE_ERROR_INVALID_INPUT, error);
+ EXPECT_FALSE(CanOfferReactivation(L"GAGA", arraysize(previous_brands),
+ NULL, &error));
+ EXPECT_EQ(REACTIVATE_ERROR_INVALID_INPUT, error);
+
+ // One more valid one
+ EXPECT_TRUE(CanOfferReactivation(L"GAGA", 0, NULL, &error));
+
+ // Check that the previous brands check works:
+ EXPECT_TRUE(SetReactivationBrandCode(L"GOOGOO"));
+ EXPECT_FALSE(CanOfferReactivation(L"GAGA", arraysize(previous_brands),
+ previous_brands, &error));
+ EXPECT_EQ(REACTIVATE_ERROR_ALREADY_REACTIVATED, error);
+}
+
+TEST_F(GCAPIReactivationTest, Reactivation_Flow) {
+ const wchar_t* previous_brands[] = {L"GOOGOO", L"MAMA", L"DADA"};
+ DWORD error;
+
+ // Set us up as a candidate for reactivation.
+ EXPECT_TRUE(SetChromeInstallMarker(HKEY_CURRENT_USER));
+
+ Time hkcu_last_run = Time::NowFromSystemTime() -
+ TimeDelta::FromDays(kReactivationMinDaysDormant);
+ EXPECT_TRUE(SetLastRunTime(HKEY_CURRENT_USER,
+ hkcu_last_run.ToInternalValue()));
+
+ EXPECT_TRUE(ReactivateChrome(L"GAGA", arraysize(previous_brands),
+ previous_brands, &error));
+ EXPECT_EQ(L"GAGA", GetReactivationString(HKEY_CURRENT_USER));
+
+ // Make sure we can't reactivate again:
+ EXPECT_FALSE(ReactivateChrome(L"GAGA", arraysize(previous_brands),
+ previous_brands, &error));
+ EXPECT_EQ(REACTIVATE_ERROR_ALREADY_REACTIVATED, error);
+
+ // Should still be able to reactivate under other brands:
+ EXPECT_TRUE(ReactivateChrome(L"MAMA", arraysize(previous_brands),
+ previous_brands, &error));
+ EXPECT_EQ(L"MAMA", GetReactivationString(HKEY_CURRENT_USER));
+
+ // Validate that previous_brands are rejected:
+ EXPECT_FALSE(ReactivateChrome(L"PFFT", arraysize(previous_brands),
+ previous_brands, &error));
+ EXPECT_EQ(REACTIVATE_ERROR_ALREADY_REACTIVATED, error);
+ EXPECT_EQ(L"MAMA", GetReactivationString(HKEY_CURRENT_USER));
+}
diff --git a/chrome/installer/gcapi/gcapi_test.cc b/chrome/installer/gcapi/gcapi_test.cc
index 2100744..b7f08bb 100644
--- a/chrome/installer/gcapi/gcapi_test.cc
+++ b/chrome/installer/gcapi/gcapi_test.cc
@@ -4,6 +4,7 @@
#include <stdio.h>
+#include "base/command_line.h"
#include "chrome/installer/gcapi/gcapi.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -54,11 +55,17 @@ void call_dynamically() {
FreeLibrary(module);
}
+const char kManualLaunchTests[] = "launch-chrome";
+
int main(int argc, char* argv[]) {
+ CommandLine::Init(argc, argv);
+
testing::InitGoogleTest(&argc, argv);
RUN_ALL_TESTS();
- call_dynamically();
- call_statically();
- printf("LaunchChrome returned %d.\n", LaunchGoogleChrome());
+ if (CommandLine::ForCurrentProcess()->HasSwitch(kManualLaunchTests)) {
+ call_dynamically();
+ call_statically();
+ printf("LaunchChrome returned %d.\n", LaunchGoogleChrome());
+ }
}