Message
Message
h"
#include <cstdint>
#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <utility>
#include "base/containers/flat_map.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/task/sequenced_task_runner.h"
#include "build/build_config.h"
#include "chrome/enterprise_companion/device_management_storage/dm_storage.h"
#include "chrome/updater/device_management/dm_message.h"
#include "chrome/updater/device_management/dm_response_validator.h"
#include "chrome/updater/net/network.h"
#include "chrome/updater/policy/service.h"
#include "chrome/updater/updater_branding.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util/util.h"
#include "components/policy/core/common/policy_types.h"
#include "components/update_client/network.h"
#include "url/gurl.h"
namespace updater {
namespace {
// Content-type of DM requests.
constexpr char kDMContentType[] = "application/x-protobuf";
// String constants for the device and app type we report to the server.
constexpr char kParamAgent[] = "agent";
constexpr char kParamRequest[] = "request";
constexpr char kParamPlatform[] = "platform";
constexpr char kParamDeviceID[] = "deviceid";
constexpr char kParamAppType[] = "apptype";
constexpr char kValueAppType[] = "Chrome";
std::unique_ptr<update_client::NetworkFetcher> CreateNetworkFetcher()
const override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!network_fetcher_factory_) {
network_fetcher_factory_ = base::MakeRefCounted<NetworkFetcherFactory>(
policy_service_proxy_configuration_);
}
return network_fetcher_factory_->Create();
}
private:
SEQUENCE_CHECKER(sequence_checker_);
const GURL server_url_;
const std::optional<PolicyServiceProxyConfiguration>
policy_service_proxy_configuration_;
mutable scoped_refptr<update_client::NetworkFetcherFactory>
network_fetcher_factory_;
};
// Builds a DM request and sends it via the wrapped network fetcher. Raw fetch
// result will be translated into DM request result for external callback.
// Do not reuse this class for multiple requests, as the class maintains the
// intermediate state of the wrapped network request.
class DMFetch : public base::RefCountedThreadSafe<DMFetch> {
public:
enum class TokenType {
kEnrollmentToken,
kDMToken,
};
using Callback =
base::OnceCallback<void(DMClient::RequestResult result,
std::unique_ptr<std::string> response_body)>;
DMFetch(std::unique_ptr<DMClient::Configurator> config,
scoped_refptr<device_management_storage::DMStorage> storage);
DMFetch(const DMFetch&) = delete;
DMFetch& operator=(const DMFetch&) = delete;
// Returns the storage where this client saves the data from DM server.
scoped_refptr<device_management_storage::DMStorage> storage() const {
return storage_;
}
private:
friend class base::RefCountedThreadSafe<DMFetch>;
~DMFetch();
// Gets the full request URL to DM server for the given request type.
// Additional device specific values, such as device ID, platform etc. will
// be appended to the URL as query parameters.
GURL BuildURL(const std::string& request_type) const;
std::unique_ptr<DMClient::Configurator> config_;
scoped_refptr<device_management_storage::DMStorage> storage_;
std::unique_ptr<update_client::NetworkFetcher> network_fetcher_;
int http_status_code_ = 0;
Callback callback_;
SEQUENCE_CHECKER(sequence_checker_);
};
DMFetch::DMFetch(std::unique_ptr<DMClient::Configurator> config,
scoped_refptr<device_management_storage::DMStorage> storage)
: config_(std::move(config)), storage_(std::move(storage)) {}
DMFetch::~DMFetch() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
callback_ = std::move(callback);
if (result == DMClient::RequestResult::kSuccess) {
network_fetcher_ = config_->CreateNetworkFetcher();
if (!network_fetcher_) {
result = DMClient::RequestResult::kFetcherError;
}
}
if (result != DMClient::RequestResult::kSuccess) {
VLOG(1) << "DM request not sent: " << result;
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback_), result,
std::make_unique<std::string>()));
return;
}
network_fetcher_->PostRequest(
BuildURL(request_type), request_data, kDMContentType,
{{kAuthorizationHeader, BuildTokenString(token_type)}},
base::BindRepeating(&DMFetch::OnRequestStarted, base::Unretained(this)),
base::BindRepeating(&DMFetch::OnRequestProgress, base::Unretained(this)),
base::BindOnce(&DMFetch::OnRequestComplete, base::Unretained(this)));
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback_), result, std::move(response_body)));
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), result));
}
void OnDMPolicyFetchRequestComplete(
scoped_refptr<DMFetch> dm_fetch,
DMClient::PolicyFetchCallback callback,
std::unique_ptr<device_management_storage::CachedPolicyInfo> cached_info,
DMClient::RequestResult result,
std::unique_ptr<std::string> response_body) {
VLOG(2) << __func__ << ": result=" << result;
std::vector<PolicyValidationResult> validation_results;
scoped_refptr<device_management_storage::DMStorage> storage =
dm_fetch->storage();
if (result == DMClient::RequestResult::kSuccess) {
device_management_storage::DMPolicyMap policies = ParsePolicyFetchResponse(
*response_body, *cached_info, storage->GetDmToken(),
storage->GetDeviceID(), validation_results);
if ([Link]()) {
VLOG(1) << "No policy passes the validation, reset the policy cache.";
result = DMClient::RequestResult::kUnexpectedResponse;
storage->RemoveAllPolicies();
} else {
VLOG(1) << "Policy fetch request completed, got " << [Link]()
<< " new policies.";
if (!storage->PersistPolicies(policies)) {
result = DMClient::RequestResult::kSerializationError;
}
}
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), result, validation_results));
}
void OnDMPolicyValidationReportRequestComplete(
scoped_refptr<DMFetch> dm_fetch,
DMClient::PolicyValidationReportCallback callback,
DMClient::RequestResult result,
std::unique_ptr<std::string> response_body) {
VLOG(2) << __func__ << ": result=" << result;
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), result));
}
} // namespace
void DMClient::RegisterDevice(
std::unique_ptr<Configurator> config,
scoped_refptr<device_management_storage::DMStorage> storage,
RegisterCallback callback) {
VLOG(2) << __func__;
auto dm_fetch = base::MakeRefCounted<DMFetch>(std::move(config), storage);
dm_fetch->PostRequest(kRegistrationRequestType,
DMFetch::TokenType::kEnrollmentToken,
GetRegisterBrowserRequestData(),
base::BindOnce(OnDMRegisterRequestComplete, dm_fetch,
std::move(callback)));
}
void DMClient::FetchPolicy(
policy::PolicyFetchReason reason,
std::unique_ptr<Configurator> config,
scoped_refptr<device_management_storage::DMStorage> storage,
PolicyFetchCallback callback) {
VLOG(2) << __func__;
if (!storage->CanPersistPolicies()) {
VLOG(2) << "Cannot persist policies.";
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback),
DMClient::RequestResult::kSerializationError,
std::vector<PolicyValidationResult>()));
return;
}
void DMClient::ReportPolicyValidationErrors(
std::unique_ptr<Configurator> config,
scoped_refptr<device_management_storage::DMStorage> storage,
const PolicyValidationResult& validation_result,
PolicyValidationReportCallback callback) {
VLOG(2) << __func__;
auto dm_fetch = base::MakeRefCounted<DMFetch>(std::move(config), storage);
dm_fetch->PostRequest(
kValidationReportRequestType, DMFetch::TokenType::kDMToken,
GetPolicyValidationReportRequestData(validation_result),
base::BindOnce(&OnDMPolicyValidationReportRequestComplete, dm_fetch,
std::move(callback)));
}
std::unique_ptr<DMClient::Configurator> DMClient::CreateDefaultConfigurator(
const GURL& server_url,
std::optional<PolicyServiceProxyConfiguration>
policy_service_proxy_configuration) {
return std::make_unique<DefaultConfigurator>(
server_url, policy_service_proxy_configuration);
}
} // namespace updater
#include "chrome/updater/device_management/dm_client.h"
#include <cstdint>
#include <memory>
#include <optional>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "chrome/enterprise_companion/device_management_storage/dm_storage.h"
#include "chrome/updater/device_management/dm_message.h"
#include "chrome/updater/device_management/dm_policy_builder_for_testing.h"
#include "chrome/updater/device_management/dm_response_validator.h"
#include "chrome/updater/net/network.h"
#include "chrome/updater/policy/dm_policy_manager.h"
#include "chrome/updater/policy/service.h"
#include "chrome/updater/protos/omaha_settings.pb.h"
#include "chrome/updater/test/unit_test_util.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "components/update_client/network.h"
#include "net/base/url_util.h"
#include "net/http/http_status_code.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using base::test::RunClosure;
namespace updater {
namespace {
class TestTokenService
: public device_management_storage::TokenServiceInterface {
public:
TestTokenService(const std::string& enrollment_token,
const std::string& dm_token)
: enrollment_token_(enrollment_token), dm_token_(dm_token) {}
std::unique_ptr<update_client::NetworkFetcher> CreateNetworkFetcher()
const override {
return network_fetcher_factory_->Create();
}
private:
scoped_refptr<update_client::NetworkFetcherFactory> network_fetcher_factory_;
const GURL server_url_;
};
class DMRequestCallbackHandler
: public base::RefCountedThreadSafe<DMRequestCallbackHandler> {
public:
DMRequestCallbackHandler() = default;
MOCK_METHOD0(PostRequestCompleted, void(void));
if (init_cache_info) {
ASSERT_TRUE(storage_->CanPersistPolicies());
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/true, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
std::unique_ptr<device_management_storage::CachedPolicyInfo> info =
storage_->GetCachedPolicyInfo();
std::vector<PolicyValidationResult> validation_results;
DMPolicyMap policies = ParsePolicyFetchResponse(
dm_response->SerializeAsString(), *[Link](), storage_->GetDmToken(),
storage_->GetDeviceID(), validation_results);
ASSERT_FALSE([Link]());
ASSERT_TRUE(storage_->PersistPolicies(policies));
ASSERT_TRUE(validation_results.empty());
}
}
scoped_refptr<device_management_storage::DMStorage> GetStorage() {
return storage_;
}
protected:
virtual ~DMRequestCallbackHandler() = default;
base::ScopedTempDir storage_dir_;
scoped_refptr<device_management_storage::DMStorage> storage_;
private:
friend class base::RefCountedThreadSafe<DMRequestCallbackHandler>;
};
private:
~DMRegisterRequestCallbackHandler() override = default;
void OnRequestComplete(
DMClient::RequestResult result,
const std::vector<PolicyValidationResult>& validation_results) {
EXPECT_EQ(result, expected_result_);
if (expected_http_status_ != net::HTTP_OK ||
expected_result_ == DMClient::RequestResult::kNoDMToken) {
PostRequestCompleted();
return;
}
std::unique_ptr<device_management_storage::CachedPolicyInfo> info =
storage_->GetCachedPolicyInfo();
switch (expected_public_key_type_) {
case PublicKeyType::kTestKey1:
EXPECT_EQ(info->public_key(), GetTestKey1()->GetPublicKeyString());
break;
case PublicKeyType::kTestKey2:
EXPECT_EQ(info->public_key(), GetTestKey2()->GetPublicKeyString());
break;
case PublicKeyType::kNone:
default:
EXPECT_TRUE(info->public_key().empty());
break;
}
if (result == DMClient::RequestResult::kSuccess) {
std::optional<::wireless_android_enterprise_devicemanagement::
OmahaSettingsClientProto>
omaha_settings = GetOmahaPolicySettings(storage_);
EXPECT_TRUE(omaha_settings);
// Sample some of the policy values and check they are expected.
EXPECT_EQ(omaha_settings->proxy_mode(), "pac_script");
const ::wireless_android_enterprise_devicemanagement::ApplicationSettings&
chrome_settings = omaha_settings->application_settings()[0];
EXPECT_EQ(chrome_settings.app_guid(), test::kChromeAppId);
EXPECT_EQ(chrome_settings.update(),
::wireless_android_enterprise_devicemanagement::
AUTOMATIC_UPDATES_ONLY);
EXPECT_EQ(chrome_settings.target_version_prefix(), "81.");
}
EXPECT_EQ(expected_validation_results_, validation_results);
PostRequestCompleted();
}
private:
~DMPolicyFetchRequestCallbackHandler() override = default;
friend class base::RefCountedThreadSafe<DMPolicyFetchRequestCallbackHandler>;
std::vector<PolicyValidationResult> expected_validation_results_;
};
class DMValidationReportRequestCallbackHandler
: public DMRequestCallbackHandler {
public:
void OnRequestComplete(DMClient::RequestResult result) {
EXPECT_EQ(result, expected_result_);
PostRequestCompleted();
}
private:
~DMValidationReportRequestCallbackHandler() override = default;
friend class base::RefCountedThreadSafe<
DMValidationReportRequestCallbackHandler>;
};
} // namespace
std::string platform;
EXPECT_TRUE(
net::GetValueForKeyInQuery([Link](), "platform", &platform));
EXPECT_EQ(platform, "Test-Platform");
std::string device_id;
EXPECT_TRUE(
net::GetValueForKeyInQuery([Link](), "deviceid", &device_id));
EXPECT_EQ(device_id, "test-device-id");
EXPECT_EQ([Link]("Content-Type"), "application/x-protobuf");
std::string request_type;
EXPECT_TRUE(
net::GetValueForKeyInQuery([Link](), "request", &request_type));
EXPECT_EQ(request_type, GetExpectedRequestType());
EXPECT_EQ([Link]("Authorization"),
GetExpectedAuthorizationToken());
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(response_http_status_);
http_response->set_content_type("application/x-protobuf");
http_response->set_content(response_body_);
return http_response;
}
net::EmbeddedTestServer test_server_;
net::HttpStatusCode response_http_status_ = net::HTTP_OK;
std::string response_body_;
base::test::TaskEnvironment task_environment_;
};
scoped_refptr<DMRegisterRequestCallbackHandler> callback_handler_;
};
scoped_refptr<DMPolicyFetchRequestCallbackHandler> callback_handler_;
};
scoped_refptr<DMValidationReportRequestCallbackHandler> callback_handler_;
};
TEST_F(DMRegisterClientTest, Success) {
callback_handler_ =
base::MakeRefCounted<DMRegisterRequestCallbackHandler>(true);
callback_handler_->CreateStorage(/*init_dm_token=*/false,
/*init_cache_info=*/false);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kSuccess);
StartTestServerWithResponse(net::HTTP_OK, GetDefaultResponse());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMRegisterClientTest, Deregister) {
callback_handler_ =
base::MakeRefCounted<DMRegisterRequestCallbackHandler>(false);
callback_handler_->CreateStorage(/*init_dm_token=*/false,
/*init_cache_info=*/false);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kSuccess);
StartTestServerWithResponse(net::HTTP_GONE, "" /* response body */);
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMRegisterClientTest, DeregisterWithDeletion) {
callback_handler_ =
base::MakeRefCounted<DMRegisterRequestCallbackHandler>(true);
callback_handler_->CreateStorage(/*init_dm_token=*/false,
/*init_cache_info=*/false);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kNoDMToken);
enterprise_management::DeviceManagementResponse response;
response.add_error_detail(
enterprise_management::CBCM_DELETION_POLICY_PREFERENCE_DELETE_TOKEN);
StartTestServerWithResponse(net::HTTP_GONE, [Link]());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMRegisterClientTest, BadRequest) {
callback_handler_ =
base::MakeRefCounted<DMRegisterRequestCallbackHandler>(true);
callback_handler_->CreateStorage(/*init_dm_token=*/false,
/*init_cache_info=*/false);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kTestKey1);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kHttpError);
StartTestServerWithResponse(net::HTTP_BAD_REQUEST, "" /* response body */);
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMRegisterClientTest, AlreadyRegistered) {
callback_handler_ =
base::MakeRefCounted<DMRegisterRequestCallbackHandler>(true);
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/false);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kAlreadyRegistered);
StartTestServerWithResponse(net::HTTP_OK, GetDefaultResponse());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMRegisterClientTest, BadResponseData) {
callback_handler_ =
base::MakeRefCounted<DMRegisterRequestCallbackHandler>(true);
callback_handler_->CreateStorage(/*init_dm_token=*/false,
/*init_cache_info=*/false);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kNone);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kUnexpectedResponse);
StartTestServerWithResponse(net::HTTP_OK, "BadResponseData");
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMPolicyFetchClientTest, NoDMToken) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/false,
/*init_cache_info=*/false);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kTestKey1);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kNoDMToken);
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/true, /*rotate_to_new_key=*/true,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
StartTestServerWithResponse(net::HTTP_OK, dm_response->SerializeAsString());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMPolicyFetchClientTest, FirstRequest) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/false);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kTestKey1);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kSuccess);
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/true, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
StartTestServerWithResponse(net::HTTP_OK, dm_response->SerializeAsString());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMPolicyFetchClientTest, NoRotateKey) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/true);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kTestKey1);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kSuccess);
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/false, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
StartTestServerWithResponse(net::HTTP_OK, dm_response->SerializeAsString());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMPolicyFetchClientTest, RotateKey) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/true);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kSuccess);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kTestKey2);
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/false, /*rotate_to_new_key=*/true,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
StartTestServerWithResponse(net::HTTP_OK, dm_response->SerializeAsString());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMPolicyFetchClientTest, RejectKeyWithBadSignature) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/true);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kNone);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kUnexpectedResponse);
PolicyValidationResult expected_validation_result;
expected_validation_result.policy_type = "google/machine-level-omaha";
expected_validation_result.status =
PolicyValidationResult::Status::kValidationBadKeyVerificationSignature;
callback_handler_->AppendExpectedValidationResult(expected_validation_result);
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/false, /*rotate_to_new_key=*/true,
DMPolicyBuilderForTesting::SigningOption::kTamperKeySignature);
StartTestServerWithResponse(net::HTTP_OK, dm_response->SerializeAsString());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMPolicyFetchClientTest, RejectDataWithBadSignature) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/true);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kNone);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kUnexpectedResponse);
PolicyValidationResult expected_validation_result;
expected_validation_result.policy_type = "google/machine-level-omaha";
expected_validation_result.status =
PolicyValidationResult::Status::kValidationBadSignature;
callback_handler_->AppendExpectedValidationResult(expected_validation_result);
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/false, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kTamperDataSignature);
StartTestServerWithResponse(net::HTTP_OK, dm_response->SerializeAsString());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMPolicyFetchClientTest, Deregister) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/true);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kDeregistered);
callback_handler_->SetExpectedHttpStatus(net::HTTP_GONE);
PostRequest();
run_loop.Run();
EXPECT_TRUE(callback_handler_->GetStorage()->IsDeviceDeregistered());
}
TEST_F(DMPolicyFetchClientTest, DeregisterWithDeletion) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/true);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kNoDMToken);
callback_handler_->SetExpectedHttpStatus(net::HTTP_GONE);
enterprise_management::DeviceManagementResponse response;
response.add_error_detail(
enterprise_management::CBCM_DELETION_POLICY_PREFERENCE_DELETE_TOKEN);
StartTestServerWithResponse(net::HTTP_GONE, [Link]());
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
EXPECT_TRUE(callback_handler_->GetStorage()->GetDmToken().empty());
}
TEST_F(DMPolicyFetchClientTest, BadResponse) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/true);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kNone);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kUnexpectedResponse);
StartTestServerWithResponse(net::HTTP_OK, "Unexpected response data");
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMPolicyFetchClientTest, BadRequest) {
callback_handler_ =
base::MakeRefCounted<DMPolicyFetchRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/true);
callback_handler_->SetExpectedPublicKey(
DMRequestCallbackHandler::PublicKeyType::kTestKey1);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kHttpError);
StartTestServerWithResponse(net::HTTP_BAD_REQUEST, "" /* response body */);
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest();
run_loop.Run();
}
TEST_F(DMPolicyValidationReportClientTest, Success) {
callback_handler_ =
base::MakeRefCounted<DMValidationReportRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/false);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kSuccess);
StartTestServerWithResponse(net::HTTP_OK, "" /* response body */);
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PolicyValidationResult validation_result;
validation_result.policy_type = kGoogleUpdatePolicyType;
validation_result.policy_token = "TestPolicyToken";
validation_result.issues.emplace_back(
"test_policy", PolicyValueValidationIssue::Severity::kError,
"Policy value out of range.");
PostRequest(validation_result);
run_loop.Run();
}
TEST_F(DMPolicyValidationReportClientTest, NoDMToken) {
callback_handler_ =
base::MakeRefCounted<DMValidationReportRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/false,
/*init_cache_info=*/false);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kNoDMToken);
StartTestServerWithResponse(net::HTTP_OK, "" /* response body */);
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PolicyValidationResult validation_result;
validation_result.policy_type = kGoogleUpdatePolicyType;
validation_result.policy_token = "TestPolicyToken";
validation_result.issues.emplace_back(
"test_policy", PolicyValueValidationIssue::Severity::kError,
"Policy value out of range.");
PostRequest(validation_result);
run_loop.Run();
}
TEST_F(DMPolicyValidationReportClientTest, NoPayload) {
callback_handler_ =
base::MakeRefCounted<DMValidationReportRequestCallbackHandler>();
callback_handler_->CreateStorage(/*init_dm_token=*/true,
/*init_cache_info=*/false);
callback_handler_->SetExpectedRequestResult(
DMClient::RequestResult::kNoPayload);
StartTestServerWithResponse(net::HTTP_OK, "" /* response body */);
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
EXPECT_CALL(*callback_handler_, PostRequestCompleted())
.WillOnce(RunClosure(quit_closure));
PostRequest(PolicyValidationResult());
run_loop.Run();
}
TEST(DMClient, StreamRequestResultEnumValue) {
{
std::stringstream output;
output << DMClient::RequestResult::kSuccess;
EXPECT_EQ([Link](), "DMClient::RequestResult::kSuccess");
}
{
std::stringstream output;
output << DMClient::RequestResult::kNoDeviceID;
EXPECT_EQ([Link](), "DMClient::RequestResult::kNoDeviceID");
}
{
std::stringstream output;
output << DMClient::RequestResult::kAlreadyRegistered;
EXPECT_EQ([Link](), "DMClient::RequestResult::kAlreadyRegistered");
}
{
std::stringstream output;
output << DMClient::RequestResult::kNotManaged;
EXPECT_EQ([Link](), "DMClient::RequestResult::kNotManaged");
}
{
std::stringstream output;
output << DMClient::RequestResult::kDeregistered;
EXPECT_EQ([Link](), "DMClient::RequestResult::kDeregistered");
}
{
std::stringstream output;
output << DMClient::RequestResult::kNoDMToken;
EXPECT_EQ([Link](), "DMClient::RequestResult::kNoDMToken");
}
{
std::stringstream output;
output << DMClient::RequestResult::kFetcherError;
EXPECT_EQ([Link](), "DMClient::RequestResult::kFetcherError");
}
{
std::stringstream output;
output << DMClient::RequestResult::kNetworkError;
EXPECT_EQ([Link](), "DMClient::RequestResult::kNetworkError");
}
{
std::stringstream output;
output << DMClient::RequestResult::kHttpError;
EXPECT_EQ([Link](), "DMClient::RequestResult::kHttpError");
}
{
std::stringstream output;
output << DMClient::RequestResult::kSerializationError;
EXPECT_EQ([Link](), "DMClient::RequestResult::kSerializationError");
}
{
std::stringstream output;
output << DMClient::RequestResult::kUnexpectedResponse;
EXPECT_EQ([Link](), "DMClient::RequestResult::kUnexpectedResponse");
}
{
std::stringstream output;
output << DMClient::RequestResult::kNoPayload;
EXPECT_EQ([Link](), "DMClient::RequestResult::kNoPayload");
}
}
} // namespace updater
#include "chrome/updater/device_management/dm_response_validator.h"
#include <cstdint>
#include <memory>
#include <utility>
#include "chrome/enterprise_companion/device_management_storage/dm_storage.h"
#include "chrome/updater/device_management/dm_message.h"
#include "chrome/updater/device_management/dm_policy_builder_for_testing.h"
#include "chrome/updater/protos/omaha_settings.pb.h"
#include "chrome/updater/test/unit_test_util.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace updater {
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
GetDMResponseWithOmahaPolicy(
const edm::OmahaSettingsClientProto& omaha_settings) const;
};
void DMResponseValidatorTests::GetCachedInfoWithPublicKey(
device_management_storage::CachedPolicyInfo& cached_info) const {
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/true, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
EXPECT_EQ(dm_response->policy_response().responses_size(), 1);
const ::enterprise_management::PolicyFetchResponse& response =
dm_response->policy_response().responses(0);
std::string policy_fetch_response;
EXPECT_TRUE([Link](&policy_fetch_response));
cached_info.Populate(policy_fetch_response);
EXPECT_FALSE(cached_info.public_key().empty());
}
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
DMResponseValidatorTests::GetDMResponseWithOmahaPolicy(
const edm::OmahaSettingsClientProto& omaha_settings) const {
std::unique_ptr<DMPolicyBuilderForTesting> policy_builder =
DMPolicyBuilderForTesting::CreateInstanceWithOptions(
/*first_request=*/true, /*rotate_to_new_key=*/true,
DMPolicyBuilderForTesting::SigningOption::kSignNormally,
"test-dm-token", "test-device-id");
DMPolicyMap policy_map;
policy_map.emplace(kGoogleUpdatePolicyType,
omaha_settings.SerializeAsString());
return policy_builder->BuildDMResponseForPolicies(policy_map);
}
TEST_F(DMResponseValidatorTests, ValidationOKWithoutPublicKey) {
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/true, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
EXPECT_EQ(dm_response->policy_response().responses_size(), 1);
const ::enterprise_management::PolicyFetchResponse& response =
dm_response->policy_response().responses(0);
DMResponseValidator validator(device_management_storage::CachedPolicyInfo(),
"test-dm-token", "test-device-id");
PolicyValidationResult validation_result;
EXPECT_TRUE([Link](response, validation_result));
EXPECT_EQ(validation_result.status,
PolicyValidationResult::Status::kValidationOK);
EXPECT_TRUE(validation_result.[Link]());
}
TEST_F(DMResponseValidatorTests, ValidationOKWithPublicKey) {
// Cached info should be created before parsing next policy response.
device_management_storage::CachedPolicyInfo cached_info;
GetCachedInfoWithPublicKey(cached_info);
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/false, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
EXPECT_EQ(dm_response->policy_response().responses_size(), 1);
const ::enterprise_management::PolicyFetchResponse& response =
dm_response->policy_response().responses(0);
TEST_F(DMResponseValidatorTests, UnexpectedDMToken) {
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/true, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
EXPECT_EQ(dm_response->policy_response().responses_size(), 1);
const ::enterprise_management::PolicyFetchResponse& response =
dm_response->policy_response().responses(0);
DMResponseValidator validator(device_management_storage::CachedPolicyInfo(),
"wrong-dm-token", "test-device-id");
PolicyValidationResult validation_result;
EXPECT_FALSE([Link](response, validation_result));
EXPECT_EQ(validation_result.policy_type, "google/machine-level-omaha");
EXPECT_EQ(validation_result.status,
PolicyValidationResult::Status::kValidationBadDMToken);
EXPECT_TRUE(validation_result.[Link]());
}
TEST_F(DMResponseValidatorTests, UnexpectedDeviceID) {
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/true, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
EXPECT_EQ(dm_response->policy_response().responses_size(), 1);
const ::enterprise_management::PolicyFetchResponse& response =
dm_response->policy_response().responses(0);
DMResponseValidator validator(device_management_storage::CachedPolicyInfo(),
"test-dm-token", "unexpected-device-id");
PolicyValidationResult validation_result;
EXPECT_FALSE([Link](response, validation_result));
EXPECT_EQ(validation_result.policy_type, "google/machine-level-omaha");
EXPECT_EQ(validation_result.status,
PolicyValidationResult::Status::kValidationBadDeviceID);
EXPECT_TRUE(validation_result.[Link]());
}
TEST_F(DMResponseValidatorTests, NoCachedPublicKey) {
// Verify that client must have a cached public key other than the first
// request.
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/false, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kSignNormally);
EXPECT_EQ(dm_response->policy_response().responses_size(), 1);
const ::enterprise_management::PolicyFetchResponse& response =
dm_response->policy_response().responses(0);
DMResponseValidator validator(device_management_storage::CachedPolicyInfo(),
"test-dm-token", "test-device-id");
PolicyValidationResult validation_result;
EXPECT_FALSE([Link](response, validation_result));
EXPECT_EQ(validation_result.policy_type, "google/machine-level-omaha");
EXPECT_EQ(validation_result.status,
PolicyValidationResult::Status::kValidationBadSignature);
EXPECT_TRUE(validation_result.[Link]());
}
TEST_F(DMResponseValidatorTests, BadSignedPublicKey) {
// Cached info should be created before parsing next policy response.
device_management_storage::CachedPolicyInfo cached_info;
GetCachedInfoWithPublicKey(cached_info);
EXPECT_EQ(dm_response->policy_response().responses_size(), 1);
const ::enterprise_management::PolicyFetchResponse& response =
dm_response->policy_response().responses(0);
DMResponseValidator validator(cached_info, "test-dm-token", "test-device-id");
PolicyValidationResult validation_result;
EXPECT_FALSE([Link](response, validation_result));
EXPECT_EQ(validation_result.policy_type, "google/machine-level-omaha");
EXPECT_EQ(
validation_result.status,
PolicyValidationResult::Status::kValidationBadKeyVerificationSignature);
EXPECT_TRUE(validation_result.[Link]());
}
TEST_F(DMResponseValidatorTests, BadSignedPolicyData) {
// Validation should fail if policy data is not signed properly.
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDefaultTestingPolicyFetchDMResponse(
/*first_request=*/true, /*rotate_to_new_key=*/false,
DMPolicyBuilderForTesting::SigningOption::kTamperDataSignature);
EXPECT_EQ(dm_response->policy_response().responses_size(), 1);
const ::enterprise_management::PolicyFetchResponse& response =
dm_response->policy_response().responses(0);
DMResponseValidator validator(device_management_storage::CachedPolicyInfo(),
"test-dm-token", "test-device-id");
PolicyValidationResult validation_result;
EXPECT_FALSE([Link](response, validation_result));
EXPECT_EQ(validation_result.status,
PolicyValidationResult::Status::kValidationBadSignature);
EXPECT_TRUE(validation_result.[Link]());
}
TEST_F(DMResponseValidatorTests, OmahaPolicyWithBadValues) {
edm::OmahaSettingsClientProto omaha_settings;
omaha_settings.set_auto_update_check_period_minutes(43201);
omaha_settings.set_download_preference("InvalidDownloadPreference");
omaha_settings.mutable_updates_suppressed()->set_start_hour(25);
omaha_settings.mutable_updates_suppressed()->set_start_minute(-1);
omaha_settings.mutable_updates_suppressed()->set_duration_min(1000);
omaha_settings.set_proxy_mode("weird_proxy_mode");
omaha_settings.set_proxy_server("unexpected_proxy");
omaha_settings.set_proxy_pac_url("foo.c/[Link]");
omaha_settings.set_install_default(edm::INSTALL_DEFAULT_DISABLED);
omaha_settings.set_update_default(edm::MANUAL_UPDATES_ONLY);
edm::ApplicationSettings app;
app.set_app_guid(test::kChromeAppId);
app.set_install(edm::INSTALL_DISABLED);
app.set_update(edm::AUTOMATIC_UPDATES_ONLY);
app.set_target_channel("");
app.set_target_version_prefix("");
app.set_rollback_to_target_version(edm::ROLLBACK_TO_TARGET_VERSION_DISABLED);
omaha_settings.mutable_application_settings()->Add(std::move(app));
std::unique_ptr<::enterprise_management::DeviceManagementResponse>
dm_response = GetDMResponseWithOmahaPolicy(omaha_settings);
EXPECT_EQ(dm_response->policy_response().responses_size(), 1);
const ::enterprise_management::PolicyFetchResponse& response =
dm_response->policy_response().responses(0);
DMResponseValidator validator(device_management_storage::CachedPolicyInfo(),
"test-dm-token", "test-device-id");
PolicyValidationResult validation_result;
EXPECT_FALSE([Link](response, validation_result));
EXPECT_EQ(validation_result.policy_type, kGoogleUpdatePolicyType);
EXPECT_EQ(validation_result.status,
PolicyValidationResult::Status::kValidationOK);
EXPECT_EQ(validation_result.[Link](), size_t{10});
EXPECT_EQ(validation_result.issues[0].policy_name,
"auto_update_check_period_minutes");
EXPECT_EQ(validation_result.issues[0].severity,
PolicyValueValidationIssue::Severity::kError);
EXPECT_EQ(validation_result.issues[0].message,
"Value out of range (0 - 43200): 43201");
EXPECT_EQ(validation_result.issues[1].policy_name, "download_preference");
EXPECT_EQ(validation_result.issues[1].severity,
PolicyValueValidationIssue::Severity::kWarning);
EXPECT_EQ(validation_result.issues[1].message,
"Unrecognized download preference: InvalidDownloadPreference");
EXPECT_EQ(validation_result.issues[2].policy_name,
"updates_suppressed.start_hour");
EXPECT_EQ(validation_result.issues[2].severity,
PolicyValueValidationIssue::Severity::kError);
EXPECT_EQ(validation_result.issues[2].message,
"Value out of range(0 - 23): 25");
EXPECT_EQ(validation_result.issues[3].policy_name,
"updates_suppressed.start_minute");
EXPECT_EQ(validation_result.issues[3].severity,
PolicyValueValidationIssue::Severity::kError);
EXPECT_EQ(validation_result.issues[3].message,
"Value out of range(0 - 59): -1");
EXPECT_EQ(validation_result.issues[4].policy_name,
"updates_suppressed.duration_min");
EXPECT_EQ(validation_result.issues[4].severity,
PolicyValueValidationIssue::Severity::kError);
EXPECT_EQ(validation_result.issues[4].message,
"Value out of range(0 - 960): 1000");
EXPECT_EQ(validation_result.issues[5].policy_name, "proxy_mode");
EXPECT_EQ(validation_result.issues[5].severity,
PolicyValueValidationIssue::Severity::kWarning);
EXPECT_EQ(validation_result.issues[5].message,
"Unrecognized proxy mode: weird_proxy_mode");
EXPECT_EQ(validation_result.issues[6].policy_name, "proxy_server");
EXPECT_EQ(validation_result.issues[6].severity,
PolicyValueValidationIssue::Severity::kWarning);
EXPECT_EQ(validation_result.issues[6].message,
"Proxy server setting [unexpected_proxy] is ignored because proxy "
"mode is not [fixed_servers]");
EXPECT_EQ(validation_result.issues[7].policy_name, "proxy_pac_url");
EXPECT_EQ(validation_result.issues[7].severity,
PolicyValueValidationIssue::Severity::kWarning);
EXPECT_EQ(validation_result.issues[7].message,
"Proxy PAC URL setting [foo.c/[Link]] is ignored because proxy "
"mode is not [pac_script]");
EXPECT_EQ(validation_result.issues[8].policy_name, "target_channel");
EXPECT_EQ(validation_result.issues[8].severity,
PolicyValueValidationIssue::Severity::kWarning);
EXPECT_EQ(validation_result.issues[8].message,
"{8A69D345-D564-463C-AFF1-A69D9E530F96} empty policy value");
EXPECT_EQ(validation_result.issues[9].policy_name, "target_version_prefix");
EXPECT_EQ(validation_result.issues[9].severity,
PolicyValueValidationIssue::Severity::kWarning);
EXPECT_EQ(validation_result.issues[9].message,
"{8A69D345-D564-463C-AFF1-A69D9E530F96} empty policy value");
}
} // namespace updater
#include "chrome/updater/ipc/update_service_proxy_posix.h"
#include <algorithm>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/cancelable_callback.h"
#include "base/check.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "base/version.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/ipc/ipc_names.h"
#include "chrome/updater/ipc/update_service_dialer.h"
#include "chrome/updater/ipc/update_service_proxy.h"
#include "chrome/updater/mojom/updater_service.mojom.h"
#include "chrome/updater/registration_data.h"
#include "chrome/updater/service_proxy_factory.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/util/posix_util.h"
#include "components/named_mojo_ipc_server/named_mojo_ipc_server_client_util.h"
#include "components/policy/core/common/policy_types.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/platform/named_platform_channel.h"
#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
#include "mojo/public/cpp/system/isolated_connection.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace updater {
namespace {
// The maximum amount of time to poll the server's socket for a connection.
constexpr base::TimeDelta kConnectionTimeout = base::Minutes(3);
return state;
}
return app_state;
}
private:
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_change_callback_;
base::OnceCallback<void(UpdateService::Result)> complete_callback_;
};
void Connect(
UpdaterScope scope,
int tries,
base::Time deadline,
base::OnceCallback<void(std::optional<mojo::PlatformChannelEndpoint>)>
connected_callback) {
if (base::Time::Now() > deadline) {
VLOG(1) << "Failed to connect to UpdateService remote. "
"Connection timed out.";
std::move(connected_callback).Run(std::nullopt);
return;
}
std::optional<mojo::PlatformChannelEndpoint> endpoint =
ConnectMojo(scope, tries);
if (!endpoint) {
VLOG(1) << "Failed to connect to UpdateService remote. "
"No updater exists.";
std::move(connected_callback).Run(std::nullopt);
return;
}
if (endpoint->is_valid()) {
std::move(connected_callback).Run(std::move(endpoint));
return;
}
base::ThreadPool::PostDelayedTask(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&Connect, scope, tries + 1, deadline,
std::move(connected_callback)),
base::Milliseconds(30 * tries));
}
} // namespace
UpdateServiceProxyImpl::UpdateServiceProxyImpl(
UpdaterScope scope,
base::TimeDelta get_version_timeout)
: scope_(scope), get_version_timeout_(get_version_timeout) {}
void UpdateServiceProxyImpl::GetVersion(
base::OnceCallback<void(base::expected<base::Version, RpcError>)>
callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->GetVersion(base::BindOnce(
[](base::OnceCallback<void(base::expected<base::Version, RpcError>)>
callback,
std::unique_ptr<base::CancelableOnceClosure> timeout_callback,
const std::string& version) {
timeout_callback->Cancel();
std::move(callback).Run(base::Version(version));
},
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(callback), base::unexpected(kErrorIpcDisconnect)),
std::move(timeout_callback)));
}
void UpdateServiceProxyImpl::FetchPolicies(
policy::PolicyFetchReason reason,
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->FetchPolicies(reason, ToMojoCallback(std::move(callback)));
}
void UpdateServiceProxyImpl::RegisterApp(
const RegistrationRequest& request,
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->RegisterApp(MakeRegistrationRequest(request),
ToMojoCallback(std::move(callback)));
}
void UpdateServiceProxyImpl::GetAppStates(
base::OnceCallback<void(base::expected<std::vector<UpdateService::AppState>,
RpcError>)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->GetAppStates(
base::BindOnce([](std::vector<mojom::AppStatePtr> app_states_mojo) {
std::vector<updater::UpdateService::AppState> app_states;
std::ranges::transform(app_states_mojo, std::back_inserter(app_states),
&MakeAppState);
return app_states;
}).Then(ToMojoCallback(std::move(callback))));
}
void UpdateServiceProxyImpl::RunPeriodicTasks(
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->RunPeriodicTasks(base::BindOnce(
[](base::OnceCallback<void(int)> callback) {
std::move(callback).Run(kErrorOk);
},
ToMojoCallback(std::move(callback))));
}
void UpdateServiceProxyImpl::CheckForUpdate(
const std::string& app_id,
UpdateService::Priority priority,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->CheckForUpdate(
app_id, static_cast<mojom::UpdateService::Priority>(priority),
static_cast<mojom::UpdateService::PolicySameVersionUpdate>(
policy_same_version_update),
language, MakeStateChangeObserver(state_update, std::move(callback)));
}
void UpdateServiceProxyImpl::Update(
const std::string& app_id,
const std::string& install_data_index,
UpdateService::Priority priority,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->Update(app_id, install_data_index,
static_cast<mojom::UpdateService::Priority>(priority),
static_cast<mojom::UpdateService::PolicySameVersionUpdate>(
policy_same_version_update),
/*do_update_check_only=*/false, language,
MakeStateChangeObserver(state_update, std::move(callback)));
}
void UpdateServiceProxyImpl::UpdateAll(
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->UpdateAll(
MakeStateChangeObserver(state_update, std::move(callback)));
}
void UpdateServiceProxyImpl::Install(
const RegistrationRequest& registration,
const std::string& client_install_data,
const std::string& install_data_index,
UpdateService::Priority priority,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->Install(
MakeRegistrationRequest(registration), client_install_data,
install_data_index, static_cast<mojom::UpdateService::Priority>(priority),
language, MakeStateChangeObserver(state_update, std::move(callback)));
}
void UpdateServiceProxyImpl::RunInstaller(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
EnsureConnecting();
remote_->RunInstaller(
app_id, installer_path, install_args, install_data, install_settings,
language, MakeStateChangeObserver(state_update, std::move(callback)));
}
void UpdateServiceProxyImpl::OnConnected(
mojo::PendingReceiver<mojom::UpdateService> pending_receiver,
std::optional<mojo::PlatformChannelEndpoint> endpoint) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!endpoint) {
remote_.reset();
return;
}
connection_ = std::move(connection);
void UpdateServiceProxyImpl::OnDisconnected() {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
connection_.reset();
remote_.reset();
}
UpdateServiceProxyImpl::~UpdateServiceProxyImpl() {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void UpdateServiceProxyImpl::EnsureConnecting() {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (remote_) {
return;
}
base::ThreadPool::PostTask(
FROM_HERE, {base::MayBlock()},
base::BindOnce(
&Connect, scope_, 0, base::Time::Now() + kConnectionTimeout,
base::BindPostTaskToCurrentDefault(base::BindOnce(
&UpdateServiceProxyImpl::OnConnected, weak_factory_.GetWeakPtr(),
remote_.BindNewPipeAndPassReceiver()))));
}
} // namespace updater
#ifndef CHROME_UPDATER_IPC_UPDATE_SERVICE_PROXY_WIN_H_
#define CHROME_UPDATER_IPC_UPDATE_SERVICE_PROXY_WIN_H_
#include <windows.h>
#include <string>
#include <vector>
#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/types/expected.h"
#include "chrome/updater/update_service.h"
namespace base {
class Version;
}
namespace policy {
enum class PolicyFetchReason;
} // namespace policy
namespace updater {
struct RegistrationRequest;
enum class UpdaterScope;
class UpdateServiceProxyImplImpl;
private:
friend class base::RefCountedThreadSafe<UpdateServiceProxyImpl>;
~UpdateServiceProxyImpl();
SEQUENCE_CHECKER(sequence_checker_);
scoped_refptr<UpdateServiceProxyImplImpl> impl_;
};
} // namespace updater
#endif // CHROME_UPDATER_IPC_UPDATE_SERVICE_PROXY_WIN_H_
#include "chrome/updater/configurator.h"
#include <algorithm>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/enterprise_util.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/memory/scoped_refptr.h"
#include "base/rand_util.h"
#include "base/sequence_checker.h"
#include "base/strings/to_string.h"
#include "base/time/time.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/updater/activity.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/crx_downloader_factory.h"
#include "chrome/updater/external_constants.h"
#include "chrome/updater/net/network.h"
#include "chrome/updater/persisted_data.h"
#include "chrome/updater/policy/service.h"
#include "chrome/updater/prefs.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/util/util.h"
#include "components/crash/core/common/crash_key.h"
#include "components/crx_file/crx_verifier.h"
#include "components/prefs/pref_service.h"
#include "components/update_client/network.h"
#include "components/update_client/patch/in_process_patcher.h"
#include "components/update_client/patcher.h"
#include "components/update_client/protocol_handler.h"
#include "components/update_client/unzip/in_process_unzipper.h"
#include "components/update_client/unzipper.h"
#include "components/version_info/version_info.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_WIN)
#include "base/win/win_util.h"
#endif
namespace updater {
Configurator::Configurator(scoped_refptr<UpdaterPrefs> prefs,
scoped_refptr<ExternalConstants> external_constants,
bool is_ceca_experiment_enabled)
: prefs_(prefs),
external_constants_(external_constants),
persisted_data_(base::MakeRefCounted<PersistedData>(
GetUpdaterScope(),
prefs->GetPrefService(),
std::make_unique<ActivityDataService>(GetUpdaterScope()))),
policy_service_(
base::MakeRefCounted<PolicyService>(external_constants,
persisted_data_,
is_ceca_experiment_enabled)),
unzip_factory_(
base::MakeRefCounted<update_client::InProcessUnzipperFactory>()),
patch_factory_(
base::MakeRefCounted<update_client::InProcessPatcherFactory>()),
is_managed_device_([] {
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
return base::IsManagedOrEnterpriseDevice();
#else
return std::nullopt;
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
}()) {
#if BUILDFLAG(IS_LINUX)
// On Linux creating the NetworkFetcherFactory requires performing blocking IO
// to load an external library. This should be done when the configurator is
// created.
GetNetworkFetcherFactory();
#endif
static crash_reporter::CrashKeyString<6> crash_key_managed("managed");
crash_key_managed.Set(is_managed_device_ ? base::ToString(*is_managed_device_)
: "n/a");
}
Configurator::~Configurator() = default;
scoped_refptr<update_client::NetworkFetcherFactory>
Configurator::GetNetworkFetcherFactory() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!network_fetcher_factory_) {
network_fetcher_factory_ = base::MakeRefCounted<NetworkFetcherFactory>(
PolicyServiceProxyConfiguration::Get(policy_service_));
}
return network_fetcher_factory_;
}
scoped_refptr<update_client::CrxDownloaderFactory>
Configurator::GetCrxDownloaderFactory() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!crx_downloader_factory_) {
crx_downloader_factory_ =
updater::MakeCrxDownloaderFactory(GetNetworkFetcherFactory());
}
return crx_downloader_factory_;
}
scoped_refptr<update_client::UnzipperFactory>
Configurator::GetUnzipperFactory() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return unzip_factory_;
}
scoped_refptr<update_client::PatcherFactory> Configurator::GetPatcherFactory() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return patch_factory_;
}
std::unique_ptr<update_client::ProtocolHandlerFactory>
Configurator::GetProtocolHandlerFactory() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return std::make_unique<update_client::ProtocolHandlerFactoryJSON>();
}
update_client::UpdaterStateProvider Configurator::GetUpdaterStateProvider()
const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return base::BindRepeating([](bool /*is_machine*/) {
return update_client::UpdaterStateAttributes();
});
}
} // namespace updater
#include "chrome/updater/external_constants_override.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "base/json/json_file_value_serializer.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/external_constants.h"
#include "chrome/updater/external_constants_default.h"
#include "chrome/updater/updater_branding.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util/util.h"
#include "components/crx_file/crx_verifier.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_MAC)
#include "base/apple/foundation_util.h"
#elif BUILDFLAG(IS_WIN)
#include "base/path_service.h"
#endif
namespace {
std::vector<GURL> GURLVectorFromStringList(
const base::Value::List& update_url_list) {
std::vector<GURL> ret;
[Link](update_url_list.size());
for (const base::Value& url : update_url_list) {
CHECK(url.is_string()) << "Non-string Value in update URL list";
ret.push_back(GURL([Link]()));
}
return ret;
}
// The test binary only ever needs to contact localhost during integration
// tests. To reduce the program's utility as a mule, crash if there is a
// non-localhost override.
GURL CheckURL(const GURL& url) {
CHECK(url.is_empty() || [Link]() == "localhost" ||
[Link]() == "[Link]" || [Link]() == "not_exist")
<< "Illegal URL override: " << url;
return url;
}
} // anonymous namespace
namespace updater {
ExternalConstantsOverrider::ExternalConstantsOverrider(
base::Value::Dict override_values,
scoped_refptr<ExternalConstants> next_provider)
: ExternalConstants(std::move(next_provider)),
override_values_(std::move(override_values)) {}
ExternalConstantsOverrider::~ExternalConstantsOverrider() = default;
return use_cup_value->GetBool();
}
return std::make_optional(is_managed->GetBool());
}
// static
scoped_refptr<ExternalConstantsOverrider>
ExternalConstantsOverrider::FromDefaultJSONFile(
scoped_refptr<ExternalConstants> next_provider) {
const std::optional<base::FilePath> override_file_path =
GetOverrideFilePath(GetUpdaterScope());
if (!override_file_path) {
LOG(ERROR) << "Cannot find override file path.";
return nullptr;
}
JSONFileValueDeserializer parser(*override_file_path,
base::JSON_ALLOW_TRAILING_COMMAS);
int error_code = 0;
std::string error_message;
std::unique_ptr<base::Value> parsed_value(
[Link](&error_code, &error_message));
if (error_code || !parsed_value) {
VLOG(2) << "Could not parse " << override_file_path << ": error "
<< error_code << ": " << error_message;
return nullptr;
}
if (!parsed_value->is_dict()) {
LOG(ERROR) << "Invalid data in " << override_file_path << ": not a dict";
return nullptr;
}
return base::MakeRefCounted<ExternalConstantsOverrider>(
std::move(*parsed_value).TakeDict(), next_provider);
}
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/time/time.h"
#include "base/values.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/updater/action_handler.h"
#include "chrome/updater/app/app_utils.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/update_usage_stats_task.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/util/util.h"
#include "components/crx_file/crx_verifier.h"
#include "components/update_client/update_client_errors.h"
#include "components/update_client/utils.h"
namespace updater {
namespace {
} // namespace
Installer::Installer(
const std::string& app_id,
const std::string& client_install_data,
const std::string& install_data_index,
const std::string& install_source,
const std::string& target_channel,
const std::string& target_version_prefix,
bool rollback_allowed,
bool update_disabled,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
scoped_refptr<PersistedData> persisted_data,
crx_file::VerifierFormat crx_verifier_format)
: updater_scope_(GetUpdaterScope()),
app_id_(app_id),
client_install_data_(client_install_data),
install_data_index_(install_data_index),
install_source_(install_source),
rollback_allowed_(rollback_allowed),
target_channel_(target_channel),
target_version_prefix_(target_version_prefix),
update_disabled_(update_disabled),
policy_same_version_update_(policy_same_version_update),
persisted_data_(persisted_data),
crx_verifier_format_(crx_verifier_format),
usage_stats_enabled_(IsUpdaterOrCompanionApp(app_id) &&
persisted_data->GetUsageStatsEnabled()),
app_info_(AppInfo(GetUpdaterScope(), app_id, {}, {}, {}, {}, {})) {}
Installer::~Installer() = default;
void Installer::MakeCrxComponent(
base::OnceCallback<void(update_client::CrxComponent)> callback) {
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(
&MakeAppInfo, updater_scope_, app_id_,
persisted_data_->GetProductVersion(app_id_),
persisted_data_->GetProductVersionPath(app_id_),
persisted_data_->GetProductVersionKey(app_id_),
persisted_data_->GetAP(app_id_), persisted_data_->GetAPPath(app_id_),
persisted_data_->GetAPKey(app_id_), persisted_data_->GetLang(app_id_),
persisted_data_->GetBrandCode(app_id_),
persisted_data_->GetBrandPath(app_id_), "KSBrandID",
persisted_data_->GetExistenceCheckerPath(app_id_)),
base::BindOnce(&Installer::MakeCrxComponentFromAppInfo, this,
std::move(callback)));
}
void Installer::MakeCrxComponentFromAppInfo(
base::OnceCallback<void(update_client::CrxComponent)> callback,
const AppInfo& app_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
app_info_ = app_info;
update_client::CrxComponent component;
[Link] = scoped_refptr<Installer>(this);
component.action_handler = MakeActionHandler();
component.requires_network_encryption = false;
component.crx_format_requirement = crx_verifier_format_;
component.app_id = app_id_;
// Query server for install data only when the client does not specify one.
if (client_install_data_.empty()) {
component.install_data_index = install_data_index_;
}
[Link] = app_info_.ap;
[Link] = app_info_.lang;
[Link] = app_info_.brand;
[Link] = app_id_;
[Link] = app_info_.version;
[Link] = persisted_data_->GetFingerprint(app_id_);
[Link] = target_channel_;
component.rollback_allowed = rollback_allowed_;
component.same_version_update_allowed =
policy_same_version_update_ ==
UpdateService::PolicySameVersionUpdate::kAllowed;
component.target_version_prefix = target_version_prefix_;
component.updates_enabled = !update_disabled_;
component.install_source = install_source_;
std::move(callback).Run(component);
}
Installer::Result Installer::InstallHelper(
const base::FilePath& unpack_path,
std::unique_ptr<InstallParams> install_params,
ProgressCallback progress_callback) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::WILL_BLOCK);
VLOG(1) << "Installing update for " << app_id_;
// Resolve the path to an installer file, which is included in the CRX, and
// specified by the |run| attribute in the manifest object of an update
// response.
if (!install_params || install_params->[Link]()) {
return Result(GOOPDATEINSTALL_E_FILENAME_INVALID,
kErrorMissingInstallParams);
}
void Installer::InstallWithSyncPrimitives(
const base::FilePath& unpack_path,
std::unique_ptr<InstallParams> install_params,
ProgressCallback progress_callback,
Callback callback) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::WILL_BLOCK);
const auto result = InstallHelper(unpack_path, std::move(install_params),
std::move(progress_callback));
std::move(callback).Run(result);
}
std::optional<base::FilePath> Installer::GetInstalledFile(
const std::string& file) {
return std::nullopt;
}
bool Installer::Uninstall() {
return false;
}
} // namespace updater
#include "chrome/updater/persisted_data.h"
#include <memory>
#include <string>
#include "base/containers/contains.h"
#include "base/files/file_path.h"
#include "base/time/time.h"
#include "base/version.h"
#include "chrome/updater/activity.h"
#include "chrome/updater/registration_data.h"
#include "chrome/updater/test/test_scope.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "components/update_client/update_client.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/win/registry.h"
#include "chrome/updater/util/win_util.h"
#include "chrome/updater/win/win_constants.h"
#endif
namespace updater {
TEST(PersistedDataTest, Simple) {
auto pref = std::make_unique<TestingPrefServiceSimple>();
update_client::RegisterPrefs(pref->registry());
RegisterPersistedDataPrefs(pref->registry());
auto metadata = base::MakeRefCounted<PersistedData>(
GetUpdaterScopeForTesting(), [Link](), nullptr);
EXPECT_FALSE(metadata->GetProductVersion("someappid").IsValid());
EXPECT_TRUE(metadata->GetFingerprint("someappid").empty());
EXPECT_TRUE(metadata->GetAppIds().empty());
metadata->SetProductVersion("someappid", base::Version("1.0"));
EXPECT_EQ("1.0", metadata->GetProductVersion("someappid").GetString());
metadata->SetFingerprint("someappid", "fp1");
EXPECT_EQ("fp1", metadata->GetFingerprint("someappid"));
TEST(PersistedDataTest, MixedCase) {
auto pref = std::make_unique<TestingPrefServiceSimple>();
update_client::RegisterPrefs(pref->registry());
RegisterPersistedDataPrefs(pref->registry());
auto metadata = base::MakeRefCounted<PersistedData>(
GetUpdaterScopeForTesting(), [Link](), nullptr);
metadata->SetProductVersion("someappid", base::Version("1.0"));
metadata->SetProductVersion("SOMEAPPID2", base::Version("2.0"));
EXPECT_EQ("1.0", metadata->GetProductVersion("someAPPID").GetString());
EXPECT_EQ("1.0", metadata->GetProductVersion("someappid").GetString());
EXPECT_EQ("2.0", metadata->GetProductVersion("someAPPID2").GetString());
EXPECT_EQ("2.0", metadata->GetProductVersion("someappid2").GetString());
}
TEST(PersistedDataTest, SharedPref) {
auto pref = std::make_unique<TestingPrefServiceSimple>();
update_client::RegisterPrefs(pref->registry());
auto metadata = base::MakeRefCounted<PersistedData>(
GetUpdaterScopeForTesting(), [Link](), nullptr);
metadata->SetProductVersion("someappid", base::Version("1.0"));
EXPECT_EQ("1.0", metadata->GetProductVersion("someappid").GetString());
// Now, create a new PersistedData reading from the same path, verify
// that it loads the value.
metadata = base::MakeRefCounted<PersistedData>(GetUpdaterScopeForTesting(),
[Link](), nullptr);
EXPECT_EQ("1.0", metadata->GetProductVersion("someappid").GetString());
}
TEST(PersistedDataTest, RemoveAppId) {
auto pref = std::make_unique<TestingPrefServiceSimple>();
update_client::RegisterPrefs(pref->registry());
auto metadata = base::MakeRefCounted<PersistedData>(
GetUpdaterScopeForTesting(), [Link](), nullptr);
RegistrationRequest data;
data.app_id = "someappid";
[Link] = "somelang";
data.brand_code = "somebrand";
[Link] = "arandom-ap=likethis";
[Link] = base::Version("1.0");
data.existence_checker_path =
base::FilePath(FILE_PATH_LITERAL("some/file/path"));
metadata->RegisterApp(data);
data.app_id = "someappid2";
[Link] = "somelang";
data.brand_code = "somebrand";
[Link] = "arandom-ap=likethis";
[Link] = base::Version("2.0");
data.existence_checker_path =
base::FilePath(FILE_PATH_LITERAL("some/file/path"));
metadata->RegisterApp(data);
EXPECT_EQ(size_t{2}, metadata->GetAppIds().size());
metadata->RemoveApp("someAPPID");
EXPECT_EQ(size_t{1}, metadata->GetAppIds().size());
metadata->RemoveApp("someappid2");
EXPECT_TRUE(metadata->GetAppIds().empty());
}
TEST(PersistedDataTest, RegisterApp_SetFirstActive) {
auto pref = std::make_unique<TestingPrefServiceSimple>();
update_client::RegisterPrefs(pref->registry());
auto metadata = base::MakeRefCounted<PersistedData>(
GetUpdaterScopeForTesting(), [Link](), nullptr);
RegistrationRequest data;
data.app_id = "someappid";
[Link] = "somelang";
data.brand_code = "somebrand";
[Link] = "arandom-ap=likethis";
[Link] = base::Version("1.0");
data.existence_checker_path =
base::FilePath(FILE_PATH_LITERAL("some/file/path"));
metadata->RegisterApp(data);
EXPECT_EQ(metadata->GetDateLastActive("someappid"), -1);
EXPECT_EQ(metadata->GetDateLastRollCall("someappid"), -1);
[Link] = base::Version("2.0");
[Link] = 1221;
[Link] = 1221;
metadata->RegisterApp(data);
EXPECT_EQ(metadata->GetDateLastActive("someappid"), 1221);
EXPECT_EQ(metadata->GetDateLastRollCall("someappid"), 1221);
[Link] = base::Version("3.0");
[Link] = std::nullopt;
[Link] = std::nullopt;
metadata->RegisterApp(data);
EXPECT_EQ(metadata->GetDateLastActive("someappid"), 1221);
EXPECT_EQ(metadata->GetDateLastRollCall("someappid"), 1221);
}
#if BUILDFLAG(IS_WIN)
TEST(PersistedDataTest, LastOSVersion) {
auto pref = std::make_unique<TestingPrefServiceSimple>();
update_client::RegisterPrefs(pref->registry());
RegisterPersistedDataPrefs(pref->registry());
auto metadata = base::MakeRefCounted<PersistedData>(
GetUpdaterScopeForTesting(), [Link](), nullptr);
EXPECT_EQ(metadata->GetLastOSVersion(), std::nullopt);
// This will persist the current OS version into the persisted data.
metadata->SetLastOSVersion();
EXPECT_NE(metadata->GetLastOSVersion(), std::nullopt);
OSVERSIONINFOEX os = {};
[Link] = sizeof(OSVERSIONINFOEX);
EXPECT_EQ(metadata_os.dwOSVersionInfoSize, [Link]);
EXPECT_EQ(metadata_os.dwMajorVersion, [Link]);
EXPECT_EQ(metadata_os.dwMinorVersion, [Link]);
EXPECT_EQ(metadata_os.dwBuildNumber, [Link]);
EXPECT_EQ(metadata_os.dwPlatformId, [Link]);
EXPECT_STREQ(metadata_os.szCSDVersion, [Link]);
EXPECT_EQ(metadata_os.wServicePackMajor, [Link]);
EXPECT_EQ(metadata_os.wServicePackMinor, [Link]);
EXPECT_EQ(metadata_os.wSuiteMask, [Link]);
EXPECT_EQ(metadata_os.wProductType, [Link]);
}
TEST(PersistedDataTest, SetEulaRequired) {
auto pref = std::make_unique<TestingPrefServiceSimple>();
update_client::RegisterPrefs(pref->registry());
RegisterPersistedDataPrefs(pref->registry());
auto metadata = base::MakeRefCounted<PersistedData>(
GetUpdaterScopeForTesting(), [Link](), nullptr);
EXPECT_FALSE(metadata->GetEulaRequired());
// This will set "eula_required=true" in the persisted data and also persist
// `eulaaccepted=0` in the registry.
metadata->SetEulaRequired(/*eula_required=*/true);
EXPECT_TRUE(metadata->GetEulaRequired());
DWORD eula_accepted = 0;
const HKEY root = UpdaterScopeToHKeyRoot(GetUpdaterScopeForTesting());
EXPECT_EQ(base::win::RegKey(root, UPDATER_KEY, Wow6432(KEY_READ))
.ReadValueDW(L"eulaaccepted", &eula_accepted),
ERROR_SUCCESS);
EXPECT_EQ(eula_accepted, 0ul);
// This will set "eula_required=false" in the persisted data and also delete
// the `eulaaccepted` value in the registry.
metadata->SetEulaRequired(/*eula_required=*/false);
EXPECT_FALSE(metadata->GetEulaRequired());
EXPECT_FALSE(base::win::RegKey(root, UPDATER_KEY, Wow6432(KEY_READ))
.HasValue(L"eulaaccepted"));
}
#endif
private:
void DeleteValuesInRegistry() {
for (const auto value : {kRegValueBrandCode, kRegValueLang}) {
base::win::RegKey(UpdaterScopeToHKeyRoot(GetUpdaterScopeForTesting()),
GetAppClientStateKey(L"someappid").c_str(),
Wow6432(KEY_SET_VALUE))
.DeleteValue(value);
}
}
#endif
};
TEST_F(PersistedDataRegistrationRequestTest, RegistrationRequest) {
auto pref = std::make_unique<TestingPrefServiceSimple>();
update_client::RegisterPrefs(pref->registry());
auto metadata = base::MakeRefCounted<PersistedData>(
GetUpdaterScopeForTesting(), [Link](), nullptr);
RegistrationRequest data;
data.app_id = "someappid";
[Link] = "somelang";
data.brand_code = "somebrand";
[Link] = "arandom-ap=likethis";
[Link] = base::Version("1.0");
data.existence_checker_path =
base::FilePath(FILE_PATH_LITERAL("some/file/path"));
[Link] = "testcohort";
data.cohort_name = "testcohortname";
data.cohort_hint = "testcohorthint";
metadata->RegisterApp(data);
EXPECT_TRUE(metadata->GetProductVersion("someappid").IsValid());
EXPECT_EQ("1.0", metadata->GetProductVersion("someappid").GetString());
EXPECT_EQ(FILE_PATH_LITERAL("some/file/path"),
metadata->GetExistenceCheckerPath("someappid").value());
EXPECT_EQ("arandom-ap=likethis", metadata->GetAP("someappid"));
EXPECT_EQ("somelang", metadata->GetLang("someappid"));
EXPECT_EQ("somebrand", metadata->GetBrandCode("someappid"));
#if BUILDFLAG(IS_WIN)
EXPECT_EQ(
base::win::RegKey(UpdaterScopeToHKeyRoot(GetUpdaterScopeForTesting()),
GetAppClientStateKey(L"someappid").c_str(),
Wow6432(KEY_SET_VALUE))
.WriteValue(kRegValueBrandCode, L"nbrnd"),
ERROR_SUCCESS);
EXPECT_EQ(metadata->GetBrandCode("someappid"), "nbrnd");
#endif
EXPECT_EQ("testcohort", metadata->GetCohort("someappid"));
EXPECT_EQ("testcohortname", metadata->GetCohortName("someappid"));
EXPECT_EQ("testcohorthint", metadata->GetCohortHint("someappid"));
#if BUILDFLAG(IS_WIN)
base::win::RegKey key;
EXPECT_EQ([Link](UpdaterScopeToHKeyRoot(GetUpdaterScopeForTesting()),
GetAppClientStateKey(L"someappid").c_str(),
Wow6432(KEY_QUERY_VALUE)),
ERROR_SUCCESS);
std::wstring ap;
EXPECT_EQ([Link](L"ap", &ap), ERROR_SUCCESS);
EXPECT_EQ(ap, L"arandom-ap=likethis");
#endif
}
TEST_F(PersistedDataRegistrationRequestTest, RegistrationRequestPartial) {
auto pref = std::make_unique<TestingPrefServiceSimple>();
update_client::RegisterPrefs(pref->registry());
auto metadata = base::MakeRefCounted<PersistedData>(
GetUpdaterScopeForTesting(), [Link](), nullptr);
RegistrationRequest data;
data.app_id = "someappid";
[Link] = "somelang";
data.brand_code = "somebrand";
[Link] = "arandom-ap=likethis";
[Link] = base::Version("1.0");
data.existence_checker_path =
base::FilePath(FILE_PATH_LITERAL("some/file/path"));
metadata->RegisterApp(data);
EXPECT_TRUE(metadata->GetProductVersion("someappid").IsValid());
EXPECT_EQ("1.0", metadata->GetProductVersion("someappid").GetString());
EXPECT_EQ(FILE_PATH_LITERAL("some/file/path"),
metadata->GetExistenceCheckerPath("someappid").value());
EXPECT_EQ("arandom-ap=likethis", metadata->GetAP("someappid"));
EXPECT_EQ("somelang", metadata->GetLang("someappid"));
EXPECT_EQ("somebrand", metadata->GetBrandCode("someappid"));
RegistrationRequest data2;
data2.app_id = data.app_id;
[Link] = "different_ap";
metadata->RegisterApp(data2);
EXPECT_EQ("1.0", metadata->GetProductVersion(data.app_id).GetString());
EXPECT_EQ(FILE_PATH_LITERAL("some/file/path"),
metadata->GetExistenceCheckerPath(data.app_id).value());
EXPECT_EQ("different_ap", metadata->GetAP(data.app_id));
EXPECT_EQ("somelang", metadata->GetLang("someappid"));
EXPECT_EQ("somebrand", metadata->GetBrandCode(data.app_id));
RegistrationRequest data3;
data3.app_id = "someappid3";
data3.brand_code = "somebrand";
[Link] = base::Version("1.0");
metadata->RegisterApp(data3);
EXPECT_TRUE(metadata->GetProductVersion("someappid3").IsValid());
EXPECT_EQ("1.0", metadata->GetProductVersion("someappid3").GetString());
EXPECT_EQ(FILE_PATH_LITERAL(""),
metadata->GetExistenceCheckerPath("someappid3").value());
EXPECT_EQ("", metadata->GetAP("someappid3"));
EXPECT_EQ("", metadata->GetLang("someappid3"));
EXPECT_EQ("somebrand", metadata->GetBrandCode("someappid3"));
}
#include <algorithm>
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/strings/escape.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/types/cxx23_to_underlying.h"
#include "base/types/expected.h"
#include "base/uuid.h"
#include "build/build_config.h"
#include "chrome/updater/certificate_tag.h"
#if BUILDFLAG(IS_MAC)
#include <sys/types.h>
#include <sys/xattr.h>
#endif // BUILDFLAG(IS_MAC)
namespace updater::tagging {
namespace {
// Maximum length for the binary representation of a tag, including its magic
// signature and length bytes.
constexpr size_t kMaxBinaryTagBytes =
kMaxTagStringBytes + 2 + sizeof(kTagMagicUtf8);
#endif // BUILDFLAG(IS_MAC)
// The name of the bundle being installed. If not specified, the first app's
// appname is used.
constexpr std::string_view kTagArgBundleName = "bundlename";
// Flag denoting that the user has agreed to provide usage stats, crashreports
// etc.
constexpr std::string_view kTagArgUsageStats = "usagestats";
// A unique value for this installation session. It can be used to follow the
// progress from the website to installation completion.
constexpr std::string_view kTagArgInstallationId = "iid";
// The brand code used for branding. This value sets the initial brand for the
// updater and the client app. If a brand value already exists on the system,
// the new brand value is ignored.
constexpr std::string_view kTagArgBrandCode = "brand";
// Runtime Mode: "runtime" argument in the tag tells the updater to install
// itself and stay on the system without any associated application for at least
// `kMaxServerStartsBeforeFirstReg` wakes. This feature is used to expose the
// COM API to a process that will install applications via that API.
// Example:
// "runtime=true&needsadmin=true"
constexpr std::string_view kTagArgRuntimeMode = "runtime";
// Enrollment token: "etoken" argument in the tag tells the per-machine updater
// to register the machine to the device management server. The value must be a
// GUID.
// Example:
// "etoken=5d086552-4514-4dfb-8a3e-337024ec35ac"
constexpr std::string_view kTagArgErollmentToken = "etoken";
if (base::EqualsCaseInsensitiveASCII("true", str)) {
return NeedsAdmin::kYes;
}
if (base::EqualsCaseInsensitiveASCII("prefers", str)) {
return NeedsAdmin::kPrefers;
}
return std::nullopt;
}
if (base::EqualsCaseInsensitiveASCII("true", str)) {
return true;
}
return std::nullopt;
}
namespace global_attributes {
args.bundle_name = value;
return ErrorCode::kSuccess;
}
args.experiment_labels = value;
return ErrorCode::kSuccess;
}
if (browser_type < 0) {
return ErrorCode::kGlobal_BrowserTypeIsInvalid;
}
args.browser_type =
browser_type < base::to_underlying(TagArgs::BrowserType::kMax)
? TagArgs::BrowserType(browser_type)
: TagArgs::BrowserType::kUnknown;
return ErrorCode::kSuccess;
}
[Link] = [Link]();
return ErrorCode::kSuccess;
}
if (tristate == 0) {
args.usage_stats_enable = false;
} else if (tristate == 1) {
args.usage_stats_enable = true;
} else if (tristate == 2) {
args.usage_stats_enable = std::nullopt;
} else {
return ErrorCode::kGlobal_UsageStatsValueIsInvalid;
}
return ErrorCode::kSuccess;
}
[Link].push_back(AppArgs(value));
return ErrorCode::kSuccess;
}
return ErrorCode::kGlobal_RuntimeModeValueIsInvalid;
}
} // namespace global_attributes
namespace app_attributes {
args.experiment_labels = value;
return ErrorCode::kSuccess;
}
args.app_name = value;
return ErrorCode::kSuccess;
}
args.needs_admin = needs_admin.value();
return ErrorCode::kSuccess;
}
} // namespace app_attributes
namespace runtime_mode_attributes {
args.needs_admin = needs_admin.value();
return ErrorCode::kSuccess;
}
} // namespace runtime_mode_attributes
namespace installer_data_attributes {
// Search for the given appid specified by |value| in |[Link]| and write its
// index to |current_app_index|.
ErrorCode FindAppIdInTagArgs(std::string_view value,
TagArgs& args,
std::optional<size_t>& current_app_index) {
if (!base::IsStringASCII(value)) {
return ErrorCode::kApp_AppIdIsNotValid;
}
if (!current_app_index.has_value()) {
return ErrorCode::kAppInstallerData_AppIdNotFound;
}
return ErrorCode::kSuccess;
}
[Link][current_app_index.value()].encoded_installer_data = value;
return ErrorCode::kSuccess;
}
} // namespace installer_data_attributes
namespace query_string {
} // namespace query_string
if ([Link]()) {
return ErrorCode::kAttributeMustHaveValue;
}
// The bundle name inherits the first app's name, if not set.
if (args.bundle_name.empty() && ![Link]()) {
args.bundle_name = [Link][0].app_name;
}
args.tag_string = tag;
[Link] = attributes;
return ErrorCode::kSuccess;
}
return ErrorCode::kSuccess;
}
std::vector<uint8_t> buffer(bytes_to_read);
return [Link](offset, base::span(buffer)) ? buffer
: std::vector<uint8_t>();
}
} // namespace
namespace internal {
std::vector<uint8_t>::const_iterator AdvanceIt(
std::vector<uint8_t>::const_iterator it,
size_t distance,
std::vector<uint8_t>::const_iterator end) {
if (it >= end) {
return end;
}
ptrdiff_t dist_to_end = 0;
if (!base::CheckedNumeric<ptrdiff_t>(end - it).AssignIfValid(&dist_to_end)) {
return end;
}
ptrdiff_t dist_to_end = 0;
if (!base::CheckedNumeric<ptrdiff_t>(end - it).AssignIfValid(&dist_to_end)) {
return false;
}
AppArgs::~AppArgs() = default;
AppArgs::AppArgs(const AppArgs&) = default;
AppArgs& AppArgs::operator=(const AppArgs&) = default;
AppArgs::AppArgs(AppArgs&&) = default;
AppArgs& AppArgs::operator=(AppArgs&&) = default;
TagArgs::TagArgs() = default;
TagArgs::~TagArgs() = default;
TagArgs::TagArgs(const TagArgs&) = default;
TagArgs& TagArgs::operator=(const TagArgs&) = default;
TagArgs::TagArgs(TagArgs&&) = default;
TagArgs& TagArgs::operator=(TagArgs&&) = default;
if (!app_installer_data_args.has_value()) {
return ErrorCode::kSuccess;
}
if (!IsValidArgs(app_installer_data_args.value())) {
return ErrorCode::kTagIsInvalid;
}
std::vector<uint8_t>::const_iterator magic_str =
std::find_end(begin, end, magic_begin, magic_end);
if (magic_str == end) {
return std::string();
}
std::vector<uint8_t>::const_iterator taglen_buf =
internal::AdvanceIt(magic_str, magic_end - magic_begin, end);
// Checks that the stored tag length is found within the binary.
if (!internal::CheckRange(taglen_buf, sizeof(uint16_t), end)) {
return std::string();
}
std::vector<uint8_t>::const_iterator tag_buf =
internal::AdvanceIt(taglen_buf, sizeof(uint16_t), end);
if (tag_buf == end) {
return std::string();
}
std::unique_ptr<tagging::BinaryInterface> CreateBinary(
const base::FilePath& file,
base::span<const uint8_t> contents) {
if ([Link](FILE_PATH_LITERAL(".exe"))) {
return CreatePEBinary(contents);
} else if ([Link](FILE_PATH_LITERAL(".msi"))) {
return CreateMSIBinary(contents);
} else {
std::unique_ptr<BinaryInterface> binary = CreatePEBinary(contents);
if (!binary) {
binary = CreateMSIBinary(contents);
}
return binary;
}
}
base::MemoryMappedFile mapped_file;
if (!mapped_file.Initialize(file)) {
LOG(ERROR) << __func__ << ": Unknown or empty file: " << file;
return {};
}
std::unique_ptr<tagging::BinaryInterface> bin =
CreateBinary(file, mapped_file.bytes());
if (!bin) {
LOG(ERROR) << __func__ << ": Could not parse binary: " << file;
return {};
}
if (padded_length > 0) {
size_t new_size = 0;
if (base::CheckAdd(tag_contents.size(), padded_length)
.AssignIfValid(&new_size)) {
tag_contents.resize(new_size);
} else {
LOG(ERROR) << __func__ << "Failed to pad the tag contents.";
return false;
}
}
#if BUILDFLAG(IS_MAC)
#endif // BUILDFLAG(IS_MAC)
} // namespace updater::tagging
#include "chrome/updater/tag.h"
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/types/cxx23_to_underlying.h"
#include "chrome/updater/test/unit_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using updater::tagging::AppArgs;
using updater::tagging::ErrorCode;
using updater::tagging::NeedsAdmin;
using updater::tagging::RuntimeModeArgs;
using updater::tagging::TagArgs;
private:
TagArgs inner_;
};
private:
AppArgs inner_;
};
private:
RuntimeModeArgs inner_;
};
void VerifyTagParseSuccess(
std::string_view tag,
std::optional<std::string_view> app_installer_data_args,
const TagArgs& expected) {
TagArgs actual;
ASSERT_EQ(ErrorCode::kSuccess, Parse(tag, app_installer_data_args, actual));
updater::test::ExpectTagArgsEqual(actual, expected);
}
} // namespace
namespace updater {
using tagging::AppArgs;
using tagging::ErrorCode;
using tagging::Parse;
using tagging::TagArgs;
TEST(TagParserTest, InvalidValueNameIsSupersetOfValidName) {
VerifyTagParseFail(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname1=Hello",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, AppNameSpaceForValue) {
VerifyTagParseFail(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname= ",
std::nullopt, ErrorCode::kAttributeMustHaveValue);
}
TEST(TagParserTest, AppNameEncodedSpaceForValue) {
VerifyTagParseFail(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname=%20",
std::nullopt, ErrorCode::kApp_AppNameCannotBeWhitespace);
}
TEST(TagParserTest, AppNameValid) {
VerifyTagParseSuccess(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname=Test",
std::nullopt,
TagArgsBuilder()
.WithBundleName("Test")
.WithApp(AppArgsBuilder("d0324988-da8a-49e5-bce5-925fcd04eab7")
.WithAppName("Test")
.Build())
.Build());
}
// This must work because the enterprise MSI code assumes spaces are allowed.
TEST(TagParserTest, AppNameWithSpace) {
VerifyTagParseSuccess(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname=Test App",
std::nullopt,
TagArgsBuilder()
.WithBundleName("Test App")
.WithApp(AppArgsBuilder("d0324988-da8a-49e5-bce5-925fcd04eab7")
.WithAppName("Test App")
.Build())
.Build());
}
TEST(TagParserTest, AppNameWithSpaceAtEnd) {
VerifyTagParseSuccess(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname= T Ap p ",
std::nullopt,
TagArgsBuilder()
.WithBundleName("T Ap p")
.WithApp(AppArgsBuilder("d0324988-da8a-49e5-bce5-925fcd04eab7")
.WithAppName("T Ap p")
.Build())
.Build());
}
TEST(TagParserTest, AppNameWithEncodedSpacesAtEnd) {
VerifyTagParseSuccess(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname=%20T%20Ap%20p%20",
std::nullopt,
TagArgsBuilder()
.WithBundleName("T Ap p")
.WithApp(AppArgsBuilder("d0324988-da8a-49e5-bce5-925fcd04eab7")
.WithAppName("T Ap p")
.Build())
.Build());
}
TEST(TagParserTest, AppNameWithMultipleSpaces) {
VerifyTagParseSuccess(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname= T Ap p",
std::nullopt,
TagArgsBuilder()
.WithBundleName("T Ap p")
.WithApp(AppArgsBuilder("d0324988-da8a-49e5-bce5-925fcd04eab7")
.WithAppName("T Ap p")
.Build())
.Build());
}
TEST(TagParserTest, AppNameUnicode) {
std::string non_ascii_name = "रहा";
VerifyTagParseSuccess(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname=%E0%A4%B0%E0%A4%B9%E0%A4%BE",
std::nullopt,
TagArgsBuilder()
.WithBundleName(non_ascii_name)
.WithApp(AppArgsBuilder("d0324988-da8a-49e5-bce5-925fcd04eab7")
.WithAppName(non_ascii_name)
.Build())
.Build());
}
TEST(TagParserTest, AppNameUnicode2) {
std::string non_ascii_name = "स्थापित कर रहा है।";
std::string escaped(
"%E0%A4%B8%E0%A5%8D%E0%A4%A5%E0%A4%BE%E0%A4%AA%E0%A4%BF"
"%E0%A4%A4%20%E0%A4%95%E0%A4%B0%20%E0%A4%B0%E0%A4%B9%E0"
"%A4%BE%20%E0%A4%B9%E0%A5%88%E0%A5%A4");
std::stringstream tag;
tag << "appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&";
tag << "appname=" << escaped;
VerifyTagParseSuccess(
[Link](), std::nullopt,
TagArgsBuilder()
.WithBundleName(non_ascii_name)
.WithApp(AppArgsBuilder("d0324988-da8a-49e5-bce5-925fcd04eab7")
.WithAppName(non_ascii_name)
.Build())
.Build());
}
TEST(TagParserTest, AppIdValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B", std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.Build());
}
TEST(TagParserTest, AppIdNotASCII) {
VerifyTagParseFail("appguid=रहा", std::nullopt,
ErrorCode::kApp_AppIdIsNotValid);
}
// Most tests here do not reflect this, but appids can be non-GUID ASCII
// strings.
TEST(TagParserTest, AppIdNotAGuid) {
VerifyTagParseSuccess(
"appguid=non-guid-id", std::nullopt,
TagArgsBuilder().WithApp(AppArgsBuilder("non-guid-id").Build()).Build());
}
TEST(TagParserTest, AppIdCaseInsensitive) {
VerifyTagParseSuccess(
"appguid=ShouldBeCaseInsensitive", std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("shouldbecaseinsensitive").Build())
.Build());
}
TEST(TagParserTest, NoRuntimeModeOrAppOnlyNeedsAdminValue) {
VerifyTagParseFail("needsadmin=true", std::nullopt,
ErrorCode::kApp_AppIdNotSpecified);
}
TEST(TagParserTest, NeedsAdminInvalid) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"needsadmin=Hello",
std::nullopt, ErrorCode::kApp_NeedsAdminValueIsInvalid);
}
TEST(TagParserTest, NeedsAdminSpaceForValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"needsadmin= ",
std::nullopt, ErrorCode::kAttributeMustHaveValue);
}
TEST(TagParserTest, NeedsAdminTrueUpperCaseT) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"needsadmin=True",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithNeedsAdmin(NeedsAdmin::kYes)
.Build())
.Build());
}
TEST(TagParserTest, NeedsAdminTrueLowerCaseT) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"needsadmin=true",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithNeedsAdmin(NeedsAdmin::kYes)
.Build())
.Build());
}
TEST(TagParserTest, NeedsFalseUpperCaseF) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"needsadmin=False",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithNeedsAdmin(NeedsAdmin::kNo)
.Build())
.Build());
}
TEST(TagParserTest, NeedsAdminFalseLowerCaseF) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"needsadmin=false",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithNeedsAdmin(NeedsAdmin::kNo)
.Build())
.Build());
}
//
// Test the handling of the contents of the extra arguments.
//
TEST(TagParserTest, AssignmentOnly) {
VerifyTagParseFail("=", std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, ExtraAssignment1) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1=",
std::nullopt, ErrorCode::kGlobal_UsageStatsValueIsInvalid);
}
TEST(TagParserTest, ExtraAssignment2) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"=usagestats=1",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, ExtraAssignment3) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1&=",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, ExtraAssignment4) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"=&usagestats=1",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, ValueWithoutName) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"=hello",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, NameWithoutValueBeforeNextArgument) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=&client=hello",
std::nullopt, ErrorCode::kAttributeMustHaveValue);
}
TEST(TagParserTest, NameWithoutArgumentSeparatorAfterIntValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1client=hello",
std::nullopt, ErrorCode::kGlobal_UsageStatsValueIsInvalid);
}
TEST(TagParserTest, NameWithoutArgumentSeparatorAfterStringValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=yesclient=hello",
std::nullopt, ErrorCode::kGlobal_UsageStatsValueIsInvalid);
}
TEST(TagParserTest, TagHasDoubleAmpersand) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1&&client=hello",
{"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"installerdata=foobar"},
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithEncodedInstallerData("foobar")
.Build())
.WithUsageStatsEnable(true)
.WithClientId("hello")
.Build());
}
TEST(TagParserTest, TagAmpersandOnly) {
VerifyTagParseSuccess("&", std::nullopt, TagArgsBuilder().Build());
}
TEST(TagParserTest, TagBeginsInAmpersand) {
VerifyTagParseSuccess(
"&appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithUsageStatsEnable(true)
.Build());
}
TEST(TagParserTest, TagEndsInAmpersand) {
VerifyTagParseSuccess(
"&appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1&",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithUsageStatsEnable(true)
.Build());
}
TEST(TagParserTest, WhitespaceOnly) {
for (const auto& whitespace : {"", " ", "\t", "\r", "\n", "\r\n"}) {
VerifyTagParseSuccess(whitespace, std::nullopt, TagArgsBuilder().Build());
}
}
//
// Test the parsing of the extra command and its arguments into a string.
//
TEST(TagParserTest, OneValidAttribute) {
VerifyTagParseSuccess(
"&appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithUsageStatsEnable(true)
.Build());
}
TEST(TagParserTest, TwoValidAttributes) {
VerifyTagParseSuccess(
"&appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1&client=hello",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithUsageStatsEnable(true)
.WithClientId("hello")
.Build());
}
TEST(TagParserTest, TagHasSwitchInTheMiddle) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1/other_value=9",
std::nullopt, ErrorCode::kTagIsInvalid);
}
TEST(TagParserTest, TagHasDoubleQuoteInTheMiddle) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1\"/other_value=9",
std::nullopt, ErrorCode::kTagIsInvalid);
}
TEST(TagParserTest, TagHasDoubleQuoteInTheMiddleAndNoForwardSlash) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1\"other_value=9",
std::nullopt, ErrorCode::kGlobal_UsageStatsValueIsInvalid);
}
TEST(TagParserTest, TagHasSpaceAndForwardSlashBeforeQuote) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1 /other_value=9",
std::nullopt, ErrorCode::kTagIsInvalid);
}
TEST(TagParserTest, TagHasForwardSlashBeforeQuote) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1/other_value=9",
std::nullopt, ErrorCode::kTagIsInvalid);
}
TEST(TagParserTest, AttributeSpecifiedTwice) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1\" \"client=10",
std::nullopt, ErrorCode::kGlobal_UsageStatsValueIsInvalid);
}
TEST(TagParserTest, WhiteSpaceBeforeArgs1) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
" usagestats=1",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617EE50-F91C-4DC1-B937-0969EEF59B0B").Build())
.WithUsageStatsEnable(true)
.Build());
}
TEST(TagParserTest, WhiteSpaceBeforeArgs2) {
VerifyTagParseSuccess(
"\tappguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617EE50-F91C-4DC1-B937-0969EEF59B0B").Build())
.WithUsageStatsEnable(true)
.Build());
}
TEST(TagParserTest, WhiteSpaceBeforeArgs3) {
VerifyTagParseSuccess(
"\rappguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617EE50-F91C-4DC1-B937-0969EEF59B0B").Build())
.WithUsageStatsEnable(true)
.Build());
}
TEST(TagParserTest, WhiteSpaceBeforeArgs4) {
VerifyTagParseSuccess(
"\nappguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B"
"&usagestats=1",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617EE50-F91C-4DC1-B937-0969EEF59B0B").Build())
.WithUsageStatsEnable(true)
.Build());
}
TEST(TagParserTest, WhiteSpaceBeforeArgs5) {
VerifyTagParseSuccess("\r\nusagestats=1", std::nullopt,
TagArgsBuilder().WithUsageStatsEnable(true).Build());
}
TEST(TagParserTest, ForwardSlash1) {
VerifyTagParseFail("/", std::nullopt, ErrorCode::kTagIsInvalid);
}
TEST(TagParserTest, ForwardSlash2) {
VerifyTagParseFail("/ appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B",
std::nullopt, ErrorCode::kTagIsInvalid);
}
TEST(TagParserTest, BackwardSlash1) {
VerifyTagParseFail("\\", std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, BackwardSlash2) {
VerifyTagParseFail("\\appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, BackwardSlash3) {
VerifyTagParseFail("\\ appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, AppArgsMustHaveValue) {
for (const auto& tag :
{"appguid", "appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&ap",
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&experiments",
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&appname",
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&needsadmin",
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&installdataindex",
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&untrusteddata"}) {
VerifyTagParseFail(tag, std::nullopt, ErrorCode::kAttributeMustHaveValue);
}
}
//
// Test specific extra commands.
//
TEST(TagParserTest, UsageStatsOutsideExtraCommand) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"/usagestats",
std::nullopt, ErrorCode::kTagIsInvalid);
}
TEST(TagParserTest, UsageStatsOn) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=1",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithUsageStatsEnable(true)
.Build());
}
TEST(TagParserTest, UsageStatsOff) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=0",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithUsageStatsEnable(false)
.Build());
}
TEST(TagParserTest, UsageStatsNone) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=2",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.Build());
}
TEST(TagParserTest, UsageStatsInvalidPositiveValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=3",
std::nullopt, ErrorCode::kGlobal_UsageStatsValueIsInvalid);
}
TEST(TagParserTest, UsageStatsInvalidNegativeValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=-1",
std::nullopt, ErrorCode::kGlobal_UsageStatsValueIsInvalid);
}
TEST(TagParserTest, UsageStatsValueIsString) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"usagestats=true",
std::nullopt, ErrorCode::kGlobal_UsageStatsValueIsInvalid);
}
TEST(TagParserTest, BundleNameValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"bundlename=Google%20Bundle",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithBundleName("Google Bundle")
.Build());
}
TEST(TagParserTest, BundleNameSpaceForValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"bundlename= ",
std::nullopt, ErrorCode::kAttributeMustHaveValue);
}
TEST(TagParserTest, BundleNameEncodedSpaceForValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"bundlename=%20",
std::nullopt, ErrorCode::kGlobal_BundleNameCannotBeWhitespace);
}
TEST(TagParserTest, BundleNameNotPresentButAppNameIs) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"appname=Google%20Chrome",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithAppName("Google Chrome")
.Build())
.WithBundleName("Google Chrome")
.Build());
}
TEST(TagParserTest, BundleNameNorAppNamePresent) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&", std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.Build());
}
TEST(TagParserTest, BundleNameNotPresentAndNoApp) {
VerifyTagParseSuccess(
"browser=0", std::nullopt,
TagArgsBuilder().WithBrowserType(TagArgs::BrowserType::kUnknown).Build());
}
TEST(TagParserTest, InstallationIdValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"iid=98CEC468-9429-4984-AEDE-4F53C6A14869",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithInstallationId("98CEC468-9429-4984-AEDE-4F53C6A14869")
.Build());
}
TEST(TagParserTest, InstallationIdContainsNonASCII) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"iid=रहा",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithInstallationId("रहा")
.Build());
}
TEST(TagParserTest, BrandCodeValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"brand=GOOG",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithBrandCode("GOOG")
.Build());
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"brand=GOOGLE",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithBrandCode("GOOGLE")
.Build());
}
TEST(TagParserTest, ClientIdValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"client=some_partner",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithClientId("some_partner")
.Build());
}
TEST(TagParserTest, UpdaterExperimentIdValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"omahaexperiments=experiment%3DgroupA%7Cexpir",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithExperimentLabels("experiment=groupA|expir")
.Build());
}
TEST(TagParserTest, UpdaterExperimentIdSpaceForValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"omahaexperiments= ",
std::nullopt, ErrorCode::kAttributeMustHaveValue);
}
TEST(TagParserTest, UpdaterExperimentIdEncodedSpaceForValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"omahaexperiments=%20",
std::nullopt, ErrorCode::kGlobal_ExperimentLabelsCannotBeWhitespace);
}
TEST(TagParserTest, AppExperimentIdValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"experiments=experiment%3DgroupA%7Cexpir",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithExperimentLabels("experiment=groupA|expir")
.Build())
.Build());
}
TEST(TagParserTest, AppExperimentIdSpaceForValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"experiments= ",
std::nullopt, ErrorCode::kAttributeMustHaveValue);
}
TEST(TagParserTest, AppExperimentIdEncodedSpaceForValue) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"experiments=%20",
std::nullopt, ErrorCode::kApp_ExperimentLabelsCannotBeWhitespace);
}
TEST(TagParserTest, ReferralIdValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"referral=ABCD123",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithReferralId("ABCD123")
.Build());
}
TEST(TagParserTest, ApValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"ap=developer",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithAp("developer")
.Build())
.Build());
}
TEST(TagParserTest, AppInstallerDataArgsValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&",
{"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"installerdata=%E0%A4foobar"},
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithEncodedInstallerData("%E0%A4foobar")
.Build())
.Build());
}
TEST(TagParserTest, AppInstallerDataArgsInvalidAppId) {
VerifyTagParseFail("appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&",
{"appguid=E135384F-85A2-4328-B07D-2CF70313D505&"
"installerdata=%E0%A4foobar"},
ErrorCode::kAppInstallerData_AppIdNotFound);
}
TEST(TagParserTest, AppInstallerDataArgsInvalidAttribute) {
VerifyTagParseFail("appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&",
{"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"needsadmin=true&"},
ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, InstallerDataNotAllowedInTag) {
VerifyTagParseFail(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"appname=TestApp2&"
"needsadmin=true&"
"installerdata=Hello%20World",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, InstallDataIndexValid) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"installdataindex=foobar",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithInstallDataIndex("foobar")
.Build())
.Build());
}
TEST(TagParserTest, BrowserTypeValid) {
std::tuple<std::string_view, TagArgs::BrowserType>
pairs[base::to_underlying(TagArgs::BrowserType::kMax)] = {
{"0", TagArgs::BrowserType::kUnknown},
{"1", TagArgs::BrowserType::kDefault},
{"2", TagArgs::BrowserType::kInternetExplorer},
{"3", TagArgs::BrowserType::kFirefox},
{"4", TagArgs::BrowserType::kChrome},
};
TEST(TagParserTest, BrowserTypeInvalid) {
EXPECT_EQ(5, int(TagArgs::BrowserType::kMax))
<< "Browser type may have been added. Update the BrowserTypeValid test "
"and change browser values in tag strings below.";
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"browser=5",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithBrowserType(TagArgs::BrowserType::kUnknown)
.Build());
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"browser=9",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithBrowserType(TagArgs::BrowserType::kUnknown)
.Build());
}
TEST(TagParserTest, ValidLang) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"lang=en",
std::nullopt,
TagArgsBuilder()
.WithApp(
AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b").Build())
.WithLanguage("en")
.Build());
}
TEST(TagParserTest, AppNameSpecifiedTwice) {
VerifyTagParseSuccess(
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"appname=TestApp&"
"appname=TestApp2&",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617EE50-F91C-4DC1-B937-0969EEF59B0B")
.WithAppName("TestApp2")
.Build())
.WithBundleName("TestApp2")
.Build());
}
TEST(TagParserTest, CaseInsensitiveAttributeNames) {
VerifyTagParseSuccess(
"APPguID=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"APPNAME=TestApp&",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("8617EE50-F91C-4DC1-B937-0969EEF59B0B")
.WithAppName("TestApp")
.Build())
.WithBundleName("TestApp")
.Build());
}
TEST(TagParserTest, BracesEncoding) {
VerifyTagParseSuccess(
"appguid=%7B8617EE50-F91C-4DC1-B937-0969EEF59B0B%7D&"
"appname=TestApp&",
std::nullopt,
TagArgsBuilder()
.WithApp(AppArgsBuilder("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}")
.WithAppName("TestApp")
.Build())
.WithBundleName("TestApp")
.Build());
}
//
// Test multiple applications in the extra arguments
//
TEST(TagParserTestMultipleEntries, TestNotStartingWithAppId) {
VerifyTagParseFail(
"appname=TestApp&"
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"appname=TestApp&"
"appname=false&"
"iid=98CEC468-9429-4984-AEDE-4F53C6A14869&"
"ap=test_ap&"
"usagestats=1&"
"browser=2&",
std::nullopt, ErrorCode::kApp_AppIdNotSpecified);
}
// This also tests that the last occurrence of a global extra arg is the one
// that is saved.
TEST(TagParserTestMultipleEntries, ThreeApplications) {
VerifyTagParseSuccess(
"etoken=5d086552-4514-4dfb-8a3e-337024ec35ac&"
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"appname=TestApp&"
"needsadmin=false&"
"iid=98CEC468-9429-4984-AEDE-4F53C6A14869&"
"ap=test_ap&"
"usagestats=1&"
"browser=2&"
"brand=GOOG&"
"client=_some_client&"
"experiments=_experiment_a&"
"untrusteddata=ABCDEFG&"
"referral=A123456789&"
"appguid=5E46DE36-737D-4271-91C1-C062F9FE21D9&"
"appname=TestApp2&"
"needsadmin=true&"
"experiments=_experiment_b&"
"untrusteddata=1234567&"
"iid=98CEC468-9429-4984-AEDE-4F53C6A14869&"
"ap=test_ap2&"
"usagestats=0&"
"browser=3&"
"brand=g00g&"
"client=_different_client&"
"appguid=5F46DE36-737D-4271-91C1-C062F9FE21D9&"
"appname=TestApp3&"
"needsadmin=prefers&",
{"appguid=5F46DE36-737D-4271-91C1-C062F9FE21D9&"
"installerdata=installerdata_app3&"
"appguid=8617EE50-F91C-4DC1-B937-0969EEF59B0B&"
"installerdata=installerdata_app1"},
TagArgsBuilder()
.WithEnrollmentToken("5d086552-4514-4dfb-8a3e-337024ec35ac")
.WithBundleName("TestApp")
.WithInstallationId("98CEC468-9429-4984-AEDE-4F53C6A14869")
.WithBrandCode("g00g")
.WithClientId("_different_client")
.WithReferralId("A123456789")
.WithBrowserType(TagArgs::BrowserType::kFirefox)
.WithUsageStatsEnable(false)
.WithApp(AppArgsBuilder("8617ee50-f91c-4dc1-b937-0969eef59b0b")
.WithAppName("TestApp")
.WithNeedsAdmin(NeedsAdmin::kNo)
.WithAp("test_ap")
.WithEncodedInstallerData("installerdata_app1")
.WithExperimentLabels("_experiment_a")
.WithUntrustedData("A=3&Message=Hello,%20World!")
.Build())
.WithApp(AppArgsBuilder("5e46de36-737d-4271-91c1-c062f9fe21d9")
.WithAppName("TestApp2")
.WithNeedsAdmin(NeedsAdmin::kYes)
.WithAp("test_ap2")
.WithExperimentLabels("_experiment_b")
.WithUntrustedData("X=5")
.Build())
.WithApp(AppArgsBuilder("5f46de36-737d-4271-91c1-c062f9fe21d9")
.WithAppName("TestApp3")
.WithEncodedInstallerData("installerdata_app3")
.WithNeedsAdmin(NeedsAdmin::kPrefers)
.Build())
.Build());
}
TEST(TagParserTest, RuntimeModeBeforeApp) {
VerifyTagParseFail(
"runtime=true&appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname1=Hello",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, RuntimeModeAfterApp) {
VerifyTagParseFail(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&appname1=Hello&runtime="
"true",
std::nullopt, ErrorCode::kUnrecognizedName);
}
TEST(TagParserTest, RuntimeModeIncorrectValue) {
VerifyTagParseFail("runtime=foo", std::nullopt,
ErrorCode::kGlobal_RuntimeModeValueIsInvalid);
}
TEST(TagParserTest, RuntimeModeIncorrectNeedsAdminValue) {
VerifyTagParseFail("runtime=true&needsadmin=foo", std::nullopt,
ErrorCode::kRuntimeMode_NeedsAdminValueIsInvalid);
}
TEST(TagParserTest, RuntimeModeValid) {
VerifyTagParseSuccess("runtime=true", std::nullopt,
TagArgsBuilder()
.WithRuntimeMode(RuntimeModeArgsBuilder().Build())
.Build());
}
TEST(TagParserTest, RuntimeModeValidSystem) {
VerifyTagParseSuccess(
"runtime=true&needsadmin=true", std::nullopt,
TagArgsBuilder()
.WithRuntimeMode(
RuntimeModeArgsBuilder().WithNeedsAdmin(NeedsAdmin::kYes).Build())
.Build());
}
TEST(TagParserTest, RuntimeModeValidUser) {
VerifyTagParseSuccess(
"runtime=true&needsadmin=false", std::nullopt,
TagArgsBuilder()
.WithRuntimeMode(
RuntimeModeArgsBuilder().WithNeedsAdmin(NeedsAdmin::kNo).Build())
.Build());
}
TEST(TagParserTest, EnrollmentTokenBeforeApp) {
VerifyTagParseSuccess(
"etoken=5d086552-4514-4dfb-8a3e-337024ec35ac&"
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname=Hello",
std::nullopt,
TagArgsBuilder()
.WithEnrollmentToken("5d086552-4514-4dfb-8a3e-337024ec35ac")
.WithBundleName("Hello")
.WithApp(AppArgsBuilder("D0324988-DA8A-49e5-BCE5-925FCD04EAB7")
.WithAppName("Hello")
.Build())
.Build());
}
TEST(TagParserTest, EnrollmentTokenAfterApp) {
VerifyTagParseSuccess(
"appguid=D0324988-DA8A-49e5-BCE5-925FCD04EAB7&"
"appname=Hello&"
"etoken=5d086552-4514-4dfb-8a3e-337024ec35ac",
std::nullopt,
TagArgsBuilder()
.WithEnrollmentToken("5d086552-4514-4dfb-8a3e-337024ec35ac")
.WithBundleName("Hello")
.WithApp(AppArgsBuilder("D0324988-DA8A-49e5-BCE5-925FCD04EAB7")
.WithAppName("Hello")
.Build())
.Build());
}
TEST(TagParserTest, EnrollmentTokenInvalidValue) {
VerifyTagParseFail("etoken=5d086552-4514-____-8a3e-337024ec35ac",
std::nullopt,
ErrorCode::kGlobal_EnrollmentTokenValueIsInvalid);
}
TEST(TagParserTest, EnrollmentTokenValid) {
VerifyTagParseSuccess(
"etoken=5d086552-4514-4dfb-8a3e-337024ec35ac", std::nullopt,
TagArgsBuilder()
.WithEnrollmentToken("5d086552-4514-4dfb-8a3e-337024ec35ac")
.Build());
}
TEST(TagExtractorTest, AdvanceIt) {
const std::vector<uint8_t> empty_binary;
ASSERT_TRUE(tagging::internal::AdvanceIt(empty_binary.begin(), 0,
empty_binary.end()) ==
empty_binary.end());
TEST(TagExtractorTest, CheckRange) {
const std::vector<uint8_t> empty_binary;
ASSERT_FALSE(
tagging::internal::CheckRange(empty_binary.end(), 1, empty_binary.end()));
std::vector<uint8_t>::const_iterator it = [Link]();
ASSERT_FALSE(tagging::internal::CheckRange(it, 0, [Link]()));
ASSERT_TRUE(tagging::internal::CheckRange(it, 1, [Link]()));
ASSERT_TRUE(tagging::internal::CheckRange(it, 5, [Link]()));
ASSERT_FALSE(tagging::internal::CheckRange(it, 6, [Link]()));
it = [Link]() + 2;
ASSERT_TRUE(tagging::internal::CheckRange(it, 3, [Link]()));
ASSERT_FALSE(tagging::internal::CheckRange(it, 4, [Link]()));
it = [Link]() + 5;
ASSERT_FALSE(tagging::internal::CheckRange(it, 0, [Link]()));
ASSERT_FALSE(tagging::internal::CheckRange(it, 1, [Link]()));
}
TEST(ExeTagTest, FileNotFound) {
ASSERT_TRUE(
tagging::BinaryReadTagString(test::GetTestFilePath("[Link]"))
.empty());
}
TEST(ExeTagTest, UntaggedExe) {
ASSERT_TRUE(tagging::BinaryReadTagString(test::GetTestFilePath("[Link]"))
.empty());
}
TEST(ExeTagTest, TaggedExeEncodeUtf8) {
ASSERT_EQ(tagging::BinaryReadTagString(
test::GetTestFilePath("tagged_encode_utf8.exe")),
"TestTag123");
}
struct ExeTagTestExeWriteTagTestCase {
const std::string exe_file_name;
const std::string tag_string;
const bool expected_success;
};
class ExeTagTestExeWriteTagTest
: public ::testing::TestWithParam<ExeTagTestExeWriteTagTestCase> {};
INSTANTIATE_TEST_SUITE_P(
ExeTagTestExeWriteTagTestCases,
ExeTagTestExeWriteTagTest,
::testing::ValuesIn(std::vector<ExeTagTestExeWriteTagTestCase>{
// single tag parameter.
{"[Link]", "brand=QAQA", true},
// already tagged.
{"tagged_encode_utf8.exe", "brand=QAQA", true},
TEST_P(ExeTagTestExeWriteTagTest, TestCases) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath out_file;
ASSERT_TRUE(CreateTemporaryFileInDir(temp_dir.GetPath(), &out_file));
ASSERT_EQ(tagging::BinaryWriteTag(
test::GetTestFilePath(GetParam().exe_file_name.c_str()),
GetParam().tag_string, 8206, out_file),
GetParam().expected_success)
<< GetParam().exe_file_name << ": " << GetParam().tag_string;
if (GetParam().expected_success) {
EXPECT_EQ(tagging::BinaryReadTagString(out_file), GetParam().tag_string);
}
}
struct MsiTagTestMsiReadTagTestCase {
const std::string msi_file_name;
const std::optional<tagging::TagArgs> expected_tag_args;
};
class MsiTagTestMsiReadTagTest
: public ::testing::TestWithParam<MsiTagTestMsiReadTagTestCase> {};
INSTANTIATE_TEST_SUITE_P(
MsiTagTestMsiReadTagTestCases,
MsiTagTestMsiReadTagTest,
::testing::ValuesIn(std::vector<MsiTagTestMsiReadTagTestCase>{
// tag:BRAND=QAQA.
{"[Link]",
[] {
tagging::TagArgs tag_args;
tag_args.brand_code = "QAQA";
return tag_args;
}()},
// tag:BRAND=QAQA&.
{"[Link]",
[] {
tagging::TagArgs tag_args;
tag_args.brand_code = "QAQA";
return tag_args;
}()},
// tag:
// appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&
// iid={2D8C18E9-8D3A-4EFC-6D61-AE23E3530EA2}&
// lang=en&browser=4&usagestats=0&appname=Google%20Chrome&
// needsadmin=prefers&brand=CHMB&
// installdataindex=defaultbrowser.
{"[Link]",
[] {
tagging::TagArgs tag_args;
tag_args.bundle_name = "Google Chrome";
tag_args.installation_id = "{2D8C18E9-8D3A-4EFC-6D61-AE23E3530EA2}";
tag_args.brand_code = "CHMB";
tag_args.language = "en";
tag_args.browser_type = tagging::TagArgs::BrowserType::kChrome;
tag_args.usage_stats_enable = false;
tagging::AppArgs app_args("{8A69D345-D564-463C-AFF1-A69D9E530F96}");
app_args.app_name = "Google Chrome";
app_args.install_data_index = "defaultbrowser";
app_args.needs_admin = tagging::NeedsAdmin::kPrefers;
tag_args.apps = {app_args};
return tag_args;
}()},
tagging::AppArgs app_args("{8237E44A-0054-442C-B6B6-EA0509993955}");
app_args.app_name = "Google Chrome Beta";
app_args.needs_admin = tagging::NeedsAdmin::kYes;
tag_args.apps = {app_args};
return tag_args;
}()},
// tag: =value&BRAND=QAQA.
{"[Link]", {}},
// tag: BRAND=.
{"[Link]", {}},
// tag:(empty string).
{"[Link]", {}},
// untagged.
{"[Link]", {}},
}));
TEST_P(MsiTagTestMsiReadTagTest, TestCases) {
const auto tag_args = tagging::BinaryReadTag(
test::GetTestFilePath("tagged_msi").AppendUTF8(GetParam().msi_file_name));
EXPECT_EQ(tag_args.has_value(), GetParam().expected_tag_args.has_value());
if (GetParam().expected_tag_args) {
test::ExpectTagArgsEqual(*tag_args, *GetParam().expected_tag_args);
}
}
struct MsiTagTestMsiWriteTagTestCase {
const std::string msi_file_name;
const std::string tag_string;
const bool expected_success;
};
class MsiTagTestMsiWriteTagTest
: public ::testing::TestWithParam<MsiTagTestMsiWriteTagTestCase> {};
INSTANTIATE_TEST_SUITE_P(
MsiTagTestMsiWriteTagTestCases,
MsiTagTestMsiWriteTagTest,
::testing::ValuesIn(std::vector<MsiTagTestMsiWriteTagTestCase>{
// single tag parameter.
{"[Link]", "brand=QAQA", true},
// already tagged.
{"[Link]", "brand=QAQA", true},
TEST_P(MsiTagTestMsiWriteTagTest, TestCases) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath out_file;
ASSERT_TRUE(CreateTemporaryFileInDir(temp_dir.GetPath(), &out_file));
const base::FilePath in_out_file = out_file.AddExtensionUTF8(".msi");
const base::FilePath msi_file_path =
test::GetTestFilePath("tagged_msi").AppendUTF8(GetParam().msi_file_name);
ASSERT_TRUE(base::CopyFile(msi_file_path, in_out_file));
} // namespace updater
#include "chrome/updater/update_service_impl_impl.h"
#include <algorithm>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/barrier_callback.h"
#include "base/barrier_closure.h"
#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/containers/queue.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/enterprise_companion/global_constants.h"
#include "chrome/updater/app/app_utils.h"
#include "chrome/updater/auto_run_on_os_upgrade_task.h"
#include "chrome/updater/branded_constants.h"
#include "chrome/updater/change_owners_task.h"
#include "chrome/updater/check_for_updates_task.h"
#include "chrome/updater/cleanup_task.h"
#include "chrome/updater/configurator.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/handle_inconsistent_apps_task.h"
#include "chrome/updater/installer.h"
#include "chrome/updater/persisted_data.h"
#include "chrome/updater/policy/service.h"
#include "chrome/updater/prefs.h"
#include "chrome/updater/registration_data.h"
#include "chrome/updater/remove_uninstalled_apps_task.h"
#include "chrome/updater/update_block_check.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/update_usage_stats_task.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util/util.h"
#include "components/policy/core/common/policy_types.h"
#include "components/prefs/pref_service.h"
#include "components/update_client/crx_update_item.h"
#include "components/update_client/protocol_definition.h"
#include "components/update_client/update_client.h"
#include "components/update_client/update_client_errors.h"
#if BUILDFLAG(IS_MAC)
#include <sys/mount.h>
#endif // BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_WIN)
#include <winhttp.h>
#include "base/win/registry.h"
#include "chrome/updater/util/win_util.h"
#include "chrome/updater/win/ui/l10n_util.h"
#include "chrome/updater/win/ui/resources/[Link]"
#include "chrome/updater/win/ui/resources/updater_installer_strings.h"
#include "chrome/updater/win/win_constants.h"
#endif // BUILDFLAG(IS_WIN)
namespace updater {
namespace internal {
UpdateService::Result ToResult(update_client::Error error) {
switch (error) {
case update_client::Error::NONE:
return UpdateService::Result::kSuccess;
case update_client::Error::UPDATE_IN_PROGRESS:
return UpdateService::Result::kUpdateInProgress;
case update_client::Error::UPDATE_CANCELED:
return UpdateService::Result::kUpdateCanceled;
case update_client::Error::RETRY_LATER:
return UpdateService::Result::kRetryLater;
case update_client::Error::SERVICE_ERROR:
return UpdateService::Result::kServiceFailed;
case update_client::Error::UPDATE_CHECK_ERROR:
return UpdateService::Result::kUpdateCheckFailed;
case update_client::Error::CRX_NOT_FOUND:
return UpdateService::Result::kAppNotFound;
case update_client::Error::INVALID_ARGUMENT:
case update_client::Error::BAD_CRX_DATA_CALLBACK:
return UpdateService::Result::kInvalidArgument;
case update_client::Error::MAX_VALUE:
NOTREACHED();
}
}
void GetComponents(
scoped_refptr<PolicyService> policy_service,
crx_file::VerifierFormat verifier_format,
scoped_refptr<PersistedData> persisted_data,
const base::flat_map<std::string, std::string>& app_client_install_data,
const base::flat_map<std::string, std::string>& app_install_data_index,
const std::string& install_source,
UpdateService::Priority priority,
bool update_blocked,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
const std::vector<std::string>& ids,
base::OnceCallback<
void(const std::vector<std::optional<update_client::CrxComponent>>&)>
callback) {
VLOG(1) << __func__
<< ". Same version update: " << policy_same_version_update;
const bool is_foreground = priority == UpdateService::Priority::kForeground;
auto barrier_callback =
base::BarrierCallback<std::optional<update_client::CrxComponent>>(
[Link](),
base::BindOnce(
[](const std::vector<std::string>& ids,
const std::vector<std::optional<update_client::CrxComponent>>&
unordered) {
// Re-order the vector to match the order of `ids`.
std::vector<std::optional<update_client::CrxComponent>> ordered;
for (const auto& id : ids) {
auto it = std::ranges::find_if(
unordered,
[&id](std::optional<update_client::CrxComponent> v) {
return v && v->app_id == id;
});
ordered.push_back(it != [Link]() ? *it : std::nullopt);
}
return ordered;
},
ids)
.Then(std::move(callback)));
for (const auto& id : ids) {
base::MakeRefCounted<Installer>(
id,
[&app_client_install_data, &id] {
auto it = app_client_install_data.find(id);
return it != app_client_install_data.end() ? it->second : "";
}(),
[&app_install_data_index, &id] {
auto it = app_install_data_index.find(id);
return it != app_install_data_index.end() ? it->second : "";
}(),
install_source,
policy_service->GetTargetChannel(id).policy_or(std::string()),
policy_service->GetTargetVersionPrefix(id).policy_or(std::string()),
policy_service->IsRollbackToTargetVersionAllowed(id).policy_or(false),
[&policy_service, &id, &is_foreground, update_blocked] {
if (update_blocked) {
return true;
}
PolicyStatus<int> app_updates =
policy_service->GetPolicyForAppUpdates(id);
return app_updates &&
(app_updates.policy() == kPolicyDisabled ||
(!is_foreground &&
app_updates.policy() == kPolicyManualUpdatesOnly) ||
(is_foreground &&
app_updates.policy() == kPolicyAutomaticUpdatesOnly));
}(),
policy_same_version_update, persisted_data, verifier_format)
->MakeCrxComponent(
base::BindOnce([](update_client::CrxComponent component) {
return component;
}).Then(barrier_callback));
}
}
#if BUILDFLAG(IS_WIN)
namespace {
std::wstring GetTextForUpdateClientInstallError(int error_code,
const std::wstring& language) {
#define INSTALL_SWITCH_ENTRY(error_code) \
case static_cast<int>(error_code): \
return GetLocalizedStringF(IDS_GENERIC_INSTALL_ERROR_BASE, L#error_code, \
language)
switch (error_code) {
INSTALL_SWITCH_ENTRY(update_client::InstallError::NONE);
INSTALL_SWITCH_ENTRY(update_client::InstallError::FINGERPRINT_WRITE_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::BAD_MANIFEST);
INSTALL_SWITCH_ENTRY(update_client::InstallError::GENERIC_ERROR);
INSTALL_SWITCH_ENTRY(update_client::InstallError::MOVE_FILES_ERROR);
INSTALL_SWITCH_ENTRY(update_client::InstallError::SET_PERMISSIONS_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::INVALID_VERSION);
INSTALL_SWITCH_ENTRY(update_client::InstallError::VERSION_NOT_UPGRADED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::NO_DIR_COMPONENT_USER);
INSTALL_SWITCH_ENTRY(update_client::InstallError::CLEAN_INSTALL_DIR_FAILED);
INSTALL_SWITCH_ENTRY(
update_client::InstallError::INSTALL_VERIFICATION_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::MISSING_INSTALL_PARAMS);
INSTALL_SWITCH_ENTRY(update_client::InstallError::LAUNCH_PROCESS_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::CUSTOM_ERROR_BASE);
default:
return GetLocalizedStringF(IDS_GENERIC_INSTALL_ERROR_BASE,
GetTextForSystemError(error_code), language);
}
#undef INSTALL_SWITCH_ENTRY
}
switch (error) {
DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::NO_URL);
DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::NO_HASH);
DOWNLOAD_SWITCH_ENTRY(
update_client::CrxDownloaderError::BITS_TOO_MANY_JOBS);
DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::GENERIC_ERROR);
case static_cast<int>(update_client::CrxDownloaderError::BAD_HASH):
return GetLocalizedString(IDS_DOWNLOAD_HASH_MISMATCH_BASE);
default:
return GetLocalizedStringF(IDS_GENERIC_DOWNLOAD_ERROR_BASE,
GetTextForSystemError(error), language);
}
#undef DOWNLOAD_SWITCH_ENTRY
}
switch (error) {
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kInvalidParams);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kInvalidFile);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kUnzipPathError);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kUnzipFailed);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kBadManifest);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kBadExtension);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kIoError);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kDeltaVerificationFailure);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaBadCommands);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaUnsupportedCommand);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaOperationFailure);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kDeltaPatchProcessFailure);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kDeltaMissingExistingFile);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kPuffinMissingPreviousCrx);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kCrxCacheNotProvided);
UNPACK_CACHING_SWITCH_ENTRY(
update_client::UnpackerError::kFailedToAddToCache);
UNPACK_CACHING_SWITCH_ENTRY(
update_client::UnpackerError::kFailedToCreateCacheDir);
default:
return GetLocalizedStringF(IDS_GENERIC_UNPACK_ERROR_BASE,
GetTextForSystemError(error), language);
}
#undef UNPACK_SWITCH_ENTRY
#undef UNPACK_CACHING_SWITCH_ENTRY
}
switch (error) {
SERVICE_SWITCH_ENTRY(update_client::ServiceError::SERVICE_WAIT_FAILED);
SERVICE_SWITCH_ENTRY(update_client::ServiceError::UPDATE_DISABLED);
SERVICE_SWITCH_ENTRY(update_client::ServiceError::CHECK_FOR_UPDATE_ONLY);
case static_cast<int>(update_client::ServiceError::CANCELLED):
return GetLocalizedString(IDS_SERVICE_ERROR_CANCELLED_BASE, language);
default:
return GetLocalizedStringF(IDS_GENERIC_SERVICE_ERROR_BASE,
GetTextForSystemError(error), language);
}
#undef SERVICE_SWITCH_ENTRY
}
std::wstring GetTextForUpdateCheckError(int error,
const std::wstring& language) {
#define UPDATE_CHECK_SWITCH_ENTRY(error_code) \
case static_cast<int>(error_code): \
return GetLocalizedStringF(IDS_GENERIC_UPDATE_CHECK_ERROR_BASE, \
L#error_code, language)
switch (error) {
UPDATE_CHECK_SWITCH_ENTRY(
update_client::ProtocolError::RESPONSE_NOT_TRUSTED);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::MISSING_URLS);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::PARSE_FAILED);
UPDATE_CHECK_SWITCH_ENTRY(
update_client::ProtocolError::UPDATE_RESPONSE_NOT_FOUND);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::URL_FETCHER_FAILED);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::INVALID_APPID);
case static_cast<int>(update_client::ProtocolError::UNKNOWN_APPLICATION):
return GetLocalizedString(IDS_UNKNOWN_APPLICATION_BASE, language);
case static_cast<int>(update_client::ProtocolError::RESTRICTED_APPLICATION):
return GetLocalizedString(IDS_RESTRICTED_RESPONSE_FROM_SERVER_BASE,
language);
case static_cast<int>(update_client::ProtocolError::OS_NOT_SUPPORTED):
return GetLocalizedString(IDS_OS_NOT_SUPPORTED_BASE, language);
case static_cast<int>(update_client::ProtocolError::HW_NOT_SUPPORTED):
return GetLocalizedString(IDS_HW_NOT_SUPPORTED_BASE, language);
case static_cast<int>(update_client::ProtocolError::NO_HASH):
return GetLocalizedString(IDS_NO_HASH_BASE, language);
case static_cast<int>(update_client::ProtocolError::UNSUPPORTED_PROTOCOL):
return GetLocalizedString(IDS_UNSUPPORTED_PROTOCOL_BASE, language);
case static_cast<int>(update_client::ProtocolError::INTERNAL):
return GetLocalizedString(IDS_INTERNAL_BASE, language);
case HRESULT_FROM_WIN32(ERROR_WINHTTP_NAME_NOT_RESOLVED):
return GetLocalizedStringF(IDS_NO_NETWORK_PRESENT_ERROR_BASE,
GetExecutableRelativePath().value(), language);
default:
return GetLocalizedStringF(
IDS_GENERIC_UPDATE_CHECK_ERROR_BASE,
error >= 400 && error < 600
? base::UTF8ToWide(base::StringPrintf("HTTP %d", error))
: GetTextForSystemError(error),
language);
}
#undef UPDATE_CHECK_SWITCH_ENTRY
}
switch (error_code) {
POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY);
POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY);
POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL);
case GOOPDATEINSTALL_E_FILENAME_INVALID:
return GetLocalizedString(IDS_INVALID_INSTALLER_FILENAME_BASE, language);
case GOOPDATEINSTALL_E_INSTALLER_FAILED_START:
return GetLocalizedString(IDS_INSTALLER_FAILED_TO_START_BASE, language);
case GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT:
return GetLocalizedString(IDS_INSTALLER_TIMED_OUT_BASE, language);
case GOOPDATEINSTALL_E_INSTALL_ALREADY_RUNNING:
return GetLocalizedStringF(
IDS_GENERIC_INSTALLER_ERROR_BASE,
GetTextForSystemError(ERROR_INSTALL_ALREADY_RUNNING), language);
case ERROR_SUCCESS_REBOOT_INITIATED:
case ERROR_SUCCESS_REBOOT_REQUIRED:
case ERROR_SUCCESS_RESTART_REQUIRED:
return GetLocalizedStringF(IDS_INSTALL_REBOOT_BASE,
GetTextForSystemError(error_code), language);
default:
return GetLocalizedStringF(IDS_GENERIC_INSTALLER_ERROR_BASE,
GetTextForSystemError(error_code), language);
}
#undef POLICY_ERROR_SWITCH_ENTRY
}
} // namespace
} // namespace internal
namespace {
update_client::Callback MakeUpdateClientCallback(
base::OnceCallback<void(UpdateService::Result)> callback) {
return base::BindOnce(
[](base::OnceCallback<void(UpdateService::Result)> callback,
update_client::Error error) {
std::move(callback).Run(internal::ToResult(error));
},
std::move(callback));
}
UpdateService::UpdateState::State ToUpdateState(
update_client::ComponentState component_state) {
switch (component_state) {
case update_client::ComponentState::kNew:
return UpdateService::UpdateState::State::kNotStarted;
case update_client::ComponentState::kChecking:
return UpdateService::UpdateState::State::kCheckingForUpdates;
case update_client::ComponentState::kDownloading:
case update_client::ComponentState::kDownloadingDiff:
return UpdateService::UpdateState::State::kDownloading;
case update_client::ComponentState::kCanUpdate:
return UpdateService::UpdateState::State::kUpdateAvailable;
case update_client::ComponentState::kUpdating:
case update_client::ComponentState::kUpdatingDiff:
return UpdateService::UpdateState::State::kInstalling;
case update_client::ComponentState::kUpdated:
return UpdateService::UpdateState::State::kUpdated;
case update_client::ComponentState::kUpToDate:
return UpdateService::UpdateState::State::kNoUpdate;
case update_client::ComponentState::kUpdateError:
return UpdateService::UpdateState::State::kUpdateError;
case update_client::ComponentState::kRun:
case update_client::ComponentState::kLastStatus:
NOTREACHED();
}
}
UpdateService::ErrorCategory ToErrorCategory(
update_client::ErrorCategory error_category) {
switch (error_category) {
case update_client::ErrorCategory::kNone:
return UpdateService::ErrorCategory::kNone;
case update_client::ErrorCategory::kDownload:
return UpdateService::ErrorCategory::kDownload;
case update_client::ErrorCategory::kUnpack:
return UpdateService::ErrorCategory::kUnpack;
case update_client::ErrorCategory::kInstall:
return UpdateService::ErrorCategory::kInstall;
case update_client::ErrorCategory::kService:
return UpdateService::ErrorCategory::kService;
case update_client::ErrorCategory::kUpdateCheck:
return UpdateService::ErrorCategory::kUpdateCheck;
case update_client::ErrorCategory::kInstaller:
return UpdateService::ErrorCategory::kInstaller;
}
}
update_client::UpdateClient::CrxStateChangeCallback
MakeUpdateClientCrxStateChangeCallback(
scoped_refptr<update_client::Configurator> config,
scoped_refptr<PersistedData> persisted_data,
const bool new_install,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)> callback) {
return base::BindRepeating(
[](scoped_refptr<update_client::Configurator> config,
scoped_refptr<PersistedData> persisted_data, const bool new_install,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
callback,
const update_client::CrxUpdateItem& crx_update_item) {
UpdateService::UpdateState update_state;
update_state.app_id = crx_update_item.id;
update_state.state = ToUpdateState(crx_update_item.state);
update_state.next_version = crx_update_item.next_version;
update_state.downloaded_bytes = crx_update_item.downloaded_bytes;
update_state.total_bytes = crx_update_item.total_bytes;
update_state.install_progress = crx_update_item.install_progress;
update_state.error_category =
ToErrorCategory(crx_update_item.error_category);
update_state.error_code = crx_update_item.error_code;
update_state.extra_code1 = crx_update_item.extra_code1;
if (crx_update_item.installer_result) {
update_state.installer_cmd_line =
crx_update_item.installer_result->installer_cmd_line;
update_state.installer_text =
crx_update_item.installer_result->installer_text;
#if BUILDFLAG(IS_WIN)
if (update_state.installer_text.empty())
update_state.installer_text = internal::GetInstallerText(
UpdateService::ErrorCategory::kInstaller,
update_state.error_code, update_state.extra_code1, language);
#endif // BUILDFLAG(IS_WIN)
}
if (update_state.state == UpdateService::UpdateState::State::kUpdated ||
update_state.state ==
UpdateService::UpdateState::State::kUpdateError ||
update_state.state ==
UpdateService::UpdateState::State::kNoUpdate) {
#if BUILDFLAG(IS_WIN)
if (update_state.installer_text.empty())
update_state.installer_text = internal::GetInstallerText(
update_state.error_category, update_state.error_code,
update_state.extra_code1, language);
#endif // BUILDFLAG(IS_WIN)
CHECK(!update_state.app_id.empty());
CHECK_NE(update_state.state,
UpdateService::UpdateState::State::kUnknown);
[Link](update_state);
},
config, persisted_data, new_install, language, callback);
}
void FetchPoliciesDone(
base::OnceCallback<void(base::OnceCallback<void(UpdateService::Result)>)>
fetch_policies_done,
base::OnceCallback<void(UpdateService::Result)> callback,
int result) {
if (result != kErrorOk) {
LOG(ERROR) << "FetchPolicies failed: " << result;
// Ignore policy fetch failures and fall through.
}
std::move(fetch_policies_done).Run(std::move(callback));
}
} // namespace
UpdateServiceImplImpl::UpdateServiceImplImpl(scoped_refptr<Configurator> config)
: config_(config),
main_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
update_client_(update_client::UpdateClientFactory(config)) {}
void UpdateServiceImplImpl::GetVersion(
base::OnceCallback<void(const base::Version&)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), base::Version(kUpdaterVersion)));
}
void UpdateServiceImplImpl::MaybeInstallEnterpriseCompanionAppOTA(
base::OnceClosure callback,
bool is_cloud_managed) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!is_cloud_managed) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, std::move(callback));
return;
}
void UpdateServiceImplImpl::FetchPolicies(
policy::PolicyFetchReason reason,
base::OnceCallback<void(int)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (GetUpdaterScope() == UpdaterScope::kUser) {
VLOG(2) << "Policy fetch skipped for user updater.";
std::move(callback).Run(0);
} else {
if (config_->GetPolicyService()->IsCecaExperimentEnabled() &&
!config_->GetUpdaterPersistedData()
->GetProductVersion(enterprise_companion::kCompanionAppId)
.IsValid()) {
config_->GetPolicyService()->IsCloudManaged(base::BindOnce(
&UpdateServiceImplImpl::MaybeInstallEnterpriseCompanionAppOTA,
base::WrapRefCounted(this),
base::BindOnce(&PolicyService::FetchPolicies,
config_->GetPolicyService(), reason,
std::move(callback))));
} else {
config_->GetPolicyService()->FetchPolicies(reason, std::move(callback));
}
}
}
void UpdateServiceImplImpl::RegisterApp(
const RegistrationRequest& request,
base::OnceCallback<void(int)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (IsPathOnReadOnlyMount(request.existence_checker_path)) {
VLOG(1) << "Existence check path " << request.existence_checker_path
<< " is on read-only file system. Registration of "
<< request.app_id << " is skipped.";
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), kRegistrationError));
return;
}
if (!IsUpdaterOrCompanionApp(request.app_id)) {
config_->GetUpdaterPersistedData()->SetHadApps();
}
bool send_event = !config_->GetUpdaterPersistedData()
->GetProductVersion(request.app_id)
.IsValid() &&
[Link]() &&
[Link] > base::Version("0") &&
!config_->GetUpdaterPersistedData()->GetEulaRequired();
config_->GetUpdaterPersistedData()->RegisterApp(request);
if (send_event) {
update_client::CrxComponent install_data;
install_data.ap = [Link];
install_data.app_id = request.app_id;
install_data.brand = request.brand_code;
install_data.lang = [Link];
install_data.requires_network_encryption = false;
install_data.version = [Link];
update_client_->SendPing(
install_data,
{.event_type = update_client::protocol_request::kEventInstall,
.result = update_client::protocol_request::kEventResultSuccess},
base::BindOnce([](update_client::Error error) {
// Ignore event ping errors; registration has been successful.
}).Then(base::BindOnce(std::move(callback), kRegistrationSuccess)));
return;
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), kRegistrationSuccess));
}
void UpdateServiceImplImpl::GetAppStates(
base::OnceCallback<void(const std::vector<AppState>&)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(&UpdateServiceImplImpl::GetAppStatesImpl, this,
std::move(callback)));
}
void UpdateServiceImplImpl::GetAppStatesImpl(
base::OnceCallback<void(const std::vector<AppState>&)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
scoped_refptr<PersistedData> persisted_data =
config_->GetUpdaterPersistedData();
std::vector<std::string> app_ids = persisted_data->GetAppIds();
std::vector<AppState> apps;
for (const std::string& app_id : app_ids) {
AppState app_state;
app_state.app_id = app_id;
app_state.version = persisted_data->GetProductVersion(app_id);
app_state.version_path = persisted_data->GetProductVersionPath(app_id);
app_state.version_key = persisted_data->GetProductVersionKey(app_id);
app_state.ap = persisted_data->GetAP(app_id);
app_state.ap_path = persisted_data->GetAPPath(app_id);
app_state.ap_key = persisted_data->GetAPKey(app_id);
app_state.brand_code = persisted_data->GetBrandCode(app_id);
app_state.brand_path = persisted_data->GetBrandPath(app_id);
app_state.ecp = persisted_data->GetExistenceCheckerPath(app_id);
app_state.cohort = persisted_data->GetCohort(app_id);
apps.push_back(app_state);
}
main_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(apps)));
}
config_->GetUpdaterPersistedData()->SetLastStarted(
base::Time::NowFromSystemTime());
VLOG(1) << "last_started updated.";
new_tasks.push_back(base::BindOnce(
[](scoped_refptr<UpdateServiceImplImpl> update_service_impl,
base::OnceClosure callback) {
update_service_impl->FetchPolicies(
policy::PolicyFetchReason::kScheduled,
base::BindOnce(
[](base::OnceClosure callback, int /* ignore_result */) {
std::move(callback).Run();
},
std::move(callback)));
},
base::WrapRefCounted(this)));
new_tasks.push_back(
base::BindOnce(&CheckForUpdatesTask::Run,
base::MakeRefCounted<CheckForUpdatesTask>(
config_, GetUpdaterScope(),
/*task_name=*/"UpdateAll",
base::BindOnce(&UpdateServiceImplImpl::UpdateAll, this,
base::DoNothing()))));
new_tasks.push_back(base::BindOnce(
[](scoped_refptr<UpdateServiceImplImpl> self,
base::OnceClosure callback) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(
&UpdateServiceImplImpl::ForceInstall, self, base::DoNothing(),
base::BindOnce(
[](base::OnceClosure closure,
UpdateService::Result result) {
VLOG(0) << "ForceInstall task complete: " << result;
std::move(closure).Run();
},
std::move(callback))));
},
base::WrapRefCounted(this)));
new_tasks.push_back(base::BindOnce(
&AutoRunOnOsUpgradeTask::Run,
base::MakeRefCounted<AutoRunOnOsUpgradeTask>(
GetUpdaterScope(), config_->GetUpdaterPersistedData())));
new_tasks.push_back(base::BindOnce(
&CleanupTask::Run, base::MakeRefCounted<CleanupTask>(GetUpdaterScope())));
if (tasks_.size() == new_tasks.size()) {
TaskStart();
}
}
void UpdateServiceImplImpl::TaskStart() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!tasks_.empty()) {
main_task_runner_->PostDelayedTask(FROM_HERE, std::move(tasks_.front()),
config_->InitialDelay());
}
}
void UpdateServiceImplImpl::TaskDone() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tasks_.pop();
TaskStart();
}
void UpdateServiceImplImpl::ForceInstall(
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PolicyStatus<std::vector<std::string>> force_install_apps_status =
config_->GetPolicyService()->GetForceInstallApps();
if (!force_install_apps_status) {
base::BindPostTask(main_task_runner_, std::move(callback))
.Run(UpdateService::Result::kSuccess);
return;
}
std::vector<std::string> force_install_apps =
force_install_apps_status.policy();
CHECK(!force_install_apps.empty());
std::vector<std::string> installed_app_ids =
config_->GetUpdaterPersistedData()->GetAppIds();
std::ranges::sort(force_install_apps);
std::ranges::sort(installed_app_ids);
std::vector<std::string> app_ids_to_install;
std::ranges::set_difference(force_install_apps, installed_app_ids,
std::back_inserter(app_ids_to_install));
if (app_ids_to_install.empty()) {
base::BindPostTask(main_task_runner_, std::move(callback))
.Run(UpdateService::Result::kSuccess);
return;
}
void UpdateServiceImplImpl::CheckForUpdate(
const std::string& app_id,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kUserRequest,
base::BindOnce(
&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::CheckForUpdateImpl, this,
app_id, priority, policy_same_version_update,
language, state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::CheckForUpdateImpl(
const std::string& app_id,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!config_->GetUpdaterPersistedData()
->GetProductVersion(app_id)
.IsValid()) {
VLOG(1) << __func__ << ": App not registered: " << app_id;
std::move(callback).Run(Result::kInvalidArgument);
return;
}
void UpdateServiceImplImpl::Update(
const std::string& app_id,
const std::string& install_data_index,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kScheduled,
base::BindOnce(&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::UpdateImpl,
this, app_id, install_data_index,
priority, policy_same_version_update,
language, state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::UpdateImpl(
const std::string& app_id,
const std::string& install_data_index,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!config_->GetUpdaterPersistedData()
->GetProductVersion(app_id)
.IsValid()) {
std::move(callback).Run(Result::kInvalidArgument);
return;
}
void UpdateServiceImplImpl::UpdateAll(
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(base::Contains(
app_ids, base::ToLowerASCII(kUpdaterAppId),
static_cast<std::string (*)(std::string_view)>(&base::ToLowerASCII)));
void UpdateServiceImplImpl::Install(
const RegistrationRequest& registration,
const std::string& client_install_data,
const std::string& install_data_index,
Priority priority,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kUserRequest,
base::BindOnce(&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::InstallImpl,
this, registration, client_install_data,
install_data_index, priority, language,
state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::InstallImpl(
const RegistrationRequest& registration,
const std::string& client_install_data,
const std::string& install_data_index,
Priority priority,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
void UpdateServiceImplImpl::RunInstaller(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id << ": " << installer_path << ": "
<< install_args << ": " << install_data << ": " << install_settings;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kUserRequest,
base::BindOnce(
&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::RunInstallerImpl, this,
app_id, installer_path, install_args, install_data,
install_settings, language, state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::RunInstallerImpl(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id << ": " << installer_path << ": "
<< install_args << ": " << install_data << ": " << install_settings;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const base::Version pv =
config_->GetUpdaterPersistedData()->GetProductVersion(app_id);
const bool new_install = ![Link]();
AppInfo app_info(
GetUpdaterScope(), app_id,
config_->GetUpdaterPersistedData()->GetAP(app_id),
![Link]() ? language
: config_->GetUpdaterPersistedData()->GetLang(app_id),
config_->GetUpdaterPersistedData()->GetBrandCode(app_id), pv,
config_->GetUpdaterPersistedData()->GetExistenceCheckerPath(app_id));
// Pre-register the app in case there is no registration for it. This app
// registration is removed later if `new_install` is `true and if the app
// install encounters an error.
RegistrationRequest request;
request.app_id = app_id;
[Link] = language;
config_->GetUpdaterPersistedData()->RegisterApp(request);
return {};
}());
return RunApplicationInstaller(
app_info, installer_path, install_args,
WriteInstallerDataToTempFile(temp_dir.GetPath(), install_data),
usage_stats_enabled, kWaitForAppInstaller,
base::BindRepeating(
[](base::RepeatingCallback<void(const UpdateState&)>
state_update,
const std::string& app_id, int progress) {
VLOG(4) << "Install progress: " << progress;
UpdateState state;
state.app_id = app_id;
[Link] = UpdateState::State::kInstalling;
state.install_progress = progress;
state_update.Run(state);
},
state_update, app_info.app_id));
},
app_info, installer_path, install_args, install_data, state_update,
IsUpdaterOrCompanionApp(app_info.app_id) &&
config_->GetUpdaterPersistedData()->GetUsageStatsEnabled()),
base::BindOnce(
[](scoped_refptr<Configurator> config,
scoped_refptr<PersistedData> persisted_data,
scoped_refptr<update_client::UpdateClient> update_client,
base::Version installer_version,
base::RepeatingCallback<void(const UpdateState&)> state_update,
const std::string& app_id, const std::string& ap,
const std::string& brand, const std::string& language,
bool new_install, base::OnceCallback<void(Result)> callback,
const InstallerResult& result) {
// Final state update after installation completes.
UpdateState state;
state.app_id = app_id;
[Link] =
[Link] == update_client::ErrorCategory::kNone
? UpdateState::State::kUpdated
: UpdateState::State::kUpdateError;
state.error_category = ToErrorCategory([Link]);
state.error_code = [Link];
state.extra_code1 = [Link];
state.installer_text = result.installer_text;
#if BUILDFLAG(IS_WIN)
if (state.installer_text.empty())
state.installer_text = internal::GetInstallerText(
state.error_category, state.error_code, state.extra_code1,
language);
#endif // BUILDFLAG(IS_WIN)
state.installer_cmd_line = result.installer_cmd_line;
state_update.Run(state);
VLOG(1) << app_id
<< " installation completed: " << state.error_code;
if (!persisted_data->GetEulaRequired()) {
// Send an install ping. In some environments the ping cannot be
// sent, so do not wait for it to be sent before calling back the
// client.
update_client::CrxComponent install_data;
install_data.ap = ap;
install_data.app_id = app_id;
install_data.lang = language;
install_data.brand = brand;
install_data.requires_network_encryption = false;
install_data.install_source = kInstallSourceOffline;
install_data.version = installer_version;
update_client->SendPing(
install_data,
{.event_type = update_client::protocol_request::kEventInstall,
.result =
[Link] ==
update_client::ErrorCategory::kNone
? update_client::protocol_request::
kEventResultSuccess
: update_client::protocol_request::kEventResultError,
.error_category = [Link],
.error_code = [Link],
.extra_code1 = [Link]},
base::DoNothing());
}
std::move(callback).Run([Link] ==
update_client::ErrorCategory::kNone
? Result::kSuccess
: Result::kInstallFailed);
},
config_, config_->GetUpdaterPersistedData(), update_client_,
installer_version, state_update, app_info.app_id, app_info.ap,
app_info.brand, language, new_install, std::move(callback)));
}
policy = kPolicyEnabled;
if (is_install) {
PolicyStatus<int> app_install_policy_status =
config_->GetPolicyService()->GetPolicyForAppInstalls(app_id);
if (app_install_policy_status) {
policy = app_install_policy_status.policy();
}
return app_install_policy_status &&
(policy == kPolicyDisabled || (config_->IsPerUserInstall() &&
policy == kPolicyEnabledMachineOnly));
} else {
PolicyStatus<int> app_update_policy_status =
config_->GetPolicyService()->GetPolicyForAppUpdates(app_id);
if (app_update_policy_status) {
policy = app_update_policy_status.policy();
}
return app_update_policy_status &&
(policy == kPolicyDisabled ||
((policy == kPolicyManualUpdatesOnly) &&
(priority != Priority::kForeground)) ||
((policy == kPolicyAutomaticUpdatesOnly) &&
(priority == Priority::kForeground)));
}
}
void UpdateServiceImplImpl::HandleUpdateDisabledByPolicy(
const std::string& app_id,
int policy,
bool is_install,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UpdateState update_state;
update_state.app_id = app_id;
update_state.state = UpdateService::UpdateState::State::kUpdateError;
update_state.error_category = UpdateService::ErrorCategory::kInstaller;
update_state.error_code =
is_install ? GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY
: policy != kPolicyAutomaticUpdatesOnly
? GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY
: GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL;
update_state.extra_code1 = 0;
#if BUILDFLAG(IS_WIN)
update_state.installer_text = internal::GetInstallerText(
update_state.error_category, update_state.error_code,
update_state.extra_code1, language);
#endif // BUILDFLAG(IS_WIN)
base::BindPostTask(main_task_runner_, state_update).Run(update_state);
base::BindPostTask(main_task_runner_, std::move(callback))
.Run(UpdateService::Result::kUpdateCheckFailed);
}
void UpdateServiceImplImpl::OnShouldBlockCheckForUpdateForMeteredNetwork(
const std::string& app_id,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback,
bool update_blocked) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&update_client::UpdateClient::CheckForUpdate, update_client_, app_id,
base::BindOnce(&internal::GetComponents, config_->GetPolicyService(),
config_->GetCrxVerifierFormat(),
config_->GetUpdaterPersistedData(), kEmptyFlatMap,
kEmptyFlatMap,
priority == UpdateService::Priority::kForeground
? kInstallSourceOnDemand
: "",
priority, update_blocked, policy_same_version_update),
MakeUpdateClientCrxStateChangeCallback(
config_, config_->GetUpdaterPersistedData(),
/*new_install=*/false, language, state_update),
priority == Priority::kForeground,
MakeUpdateClientCallback(std::move(callback))));
}
void UpdateServiceImplImpl::OnShouldBlockUpdateForMeteredNetwork(
const std::vector<std::string>& app_ids,
const base::flat_map<std::string, std::string>& app_client_install_data,
const base::flat_map<std::string, std::string>& app_install_data_index,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback,
bool update_blocked) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&update_client::UpdateClient::Update, update_client_, app_ids,
base::BindOnce(&internal::GetComponents, config_->GetPolicyService(),
config_->GetCrxVerifierFormat(),
config_->GetUpdaterPersistedData(),
app_client_install_data, app_install_data_index,
priority == UpdateService::Priority::kForeground
? kInstallSourceOnDemand
: "",
priority, update_blocked, policy_same_version_update),
MakeUpdateClientCrxStateChangeCallback(
config_, config_->GetUpdaterPersistedData(),
/*new_install=*/false, language, state_update),
priority == Priority::kForeground,
MakeUpdateClientCallback(std::move(callback))));
}
void UpdateServiceImplImpl::OnShouldBlockForceInstallForMeteredNetwork(
const std::vector<std::string>& app_ids,
const base::flat_map<std::string, std::string>& app_client_install_data,
const base::flat_map<std::string, std::string>& app_install_data_index,
PolicySameVersionUpdate policy_same_version_update,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback,
bool update_blocked) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// The result from Install is only used for logging. Thus, arbitrarily pick
// the first non-success result to propagate.
auto barrier_callback = base::BarrierCallback<Result>(
app_ids.size(),
base::BindOnce([](const std::vector<Result>& results) {
auto error_it = std::ranges::find_if(
results, [](Result result) { return result != Result::kSuccess; });
return error_it == std::end(results) ? Result::kSuccess : *error_it;
}).Then(std::move(callback)));
UpdateServiceImplImpl::~UpdateServiceImplImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
config_->GetPrefService()->SchedulePendingLossyWrites();
}
} // namespace updater
#include "chrome/updater/update_service_impl_impl.h"
#include <algorithm>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/barrier_callback.h"
#include "base/barrier_closure.h"
#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/containers/queue.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/enterprise_companion/global_constants.h"
#include "chrome/updater/app/app_utils.h"
#include "chrome/updater/auto_run_on_os_upgrade_task.h"
#include "chrome/updater/branded_constants.h"
#include "chrome/updater/change_owners_task.h"
#include "chrome/updater/check_for_updates_task.h"
#include "chrome/updater/cleanup_task.h"
#include "chrome/updater/configurator.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/handle_inconsistent_apps_task.h"
#include "chrome/updater/installer.h"
#include "chrome/updater/persisted_data.h"
#include "chrome/updater/policy/service.h"
#include "chrome/updater/prefs.h"
#include "chrome/updater/registration_data.h"
#include "chrome/updater/remove_uninstalled_apps_task.h"
#include "chrome/updater/update_block_check.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/update_usage_stats_task.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util/util.h"
#include "components/policy/core/common/policy_types.h"
#include "components/prefs/pref_service.h"
#include "components/update_client/crx_update_item.h"
#include "components/update_client/protocol_definition.h"
#include "components/update_client/update_client.h"
#include "components/update_client/update_client_errors.h"
#if BUILDFLAG(IS_MAC)
#include <sys/mount.h>
#endif // BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_WIN)
#include <winhttp.h>
#include "base/win/registry.h"
#include "chrome/updater/util/win_util.h"
#include "chrome/updater/win/ui/l10n_util.h"
#include "chrome/updater/win/ui/resources/[Link]"
#include "chrome/updater/win/ui/resources/updater_installer_strings.h"
#include "chrome/updater/win/win_constants.h"
#endif // BUILDFLAG(IS_WIN)
namespace updater {
namespace internal {
UpdateService::Result ToResult(update_client::Error error) {
switch (error) {
case update_client::Error::NONE:
return UpdateService::Result::kSuccess;
case update_client::Error::UPDATE_IN_PROGRESS:
return UpdateService::Result::kUpdateInProgress;
case update_client::Error::UPDATE_CANCELED:
return UpdateService::Result::kUpdateCanceled;
case update_client::Error::RETRY_LATER:
return UpdateService::Result::kRetryLater;
case update_client::Error::SERVICE_ERROR:
return UpdateService::Result::kServiceFailed;
case update_client::Error::UPDATE_CHECK_ERROR:
return UpdateService::Result::kUpdateCheckFailed;
case update_client::Error::CRX_NOT_FOUND:
return UpdateService::Result::kAppNotFound;
case update_client::Error::INVALID_ARGUMENT:
case update_client::Error::BAD_CRX_DATA_CALLBACK:
return UpdateService::Result::kInvalidArgument;
case update_client::Error::MAX_VALUE:
NOTREACHED();
}
}
void GetComponents(
scoped_refptr<PolicyService> policy_service,
crx_file::VerifierFormat verifier_format,
scoped_refptr<PersistedData> persisted_data,
const base::flat_map<std::string, std::string>& app_client_install_data,
const base::flat_map<std::string, std::string>& app_install_data_index,
const std::string& install_source,
UpdateService::Priority priority,
bool update_blocked,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
const std::vector<std::string>& ids,
base::OnceCallback<
void(const std::vector<std::optional<update_client::CrxComponent>>&)>
callback) {
VLOG(1) << __func__
<< ". Same version update: " << policy_same_version_update;
const bool is_foreground = priority == UpdateService::Priority::kForeground;
auto barrier_callback =
base::BarrierCallback<std::optional<update_client::CrxComponent>>(
[Link](),
base::BindOnce(
[](const std::vector<std::string>& ids,
const std::vector<std::optional<update_client::CrxComponent>>&
unordered) {
// Re-order the vector to match the order of `ids`.
std::vector<std::optional<update_client::CrxComponent>> ordered;
for (const auto& id : ids) {
auto it = std::ranges::find_if(
unordered,
[&id](std::optional<update_client::CrxComponent> v) {
return v && v->app_id == id;
});
ordered.push_back(it != [Link]() ? *it : std::nullopt);
}
return ordered;
},
ids)
.Then(std::move(callback)));
for (const auto& id : ids) {
base::MakeRefCounted<Installer>(
id,
[&app_client_install_data, &id] {
auto it = app_client_install_data.find(id);
return it != app_client_install_data.end() ? it->second : "";
}(),
[&app_install_data_index, &id] {
auto it = app_install_data_index.find(id);
return it != app_install_data_index.end() ? it->second : "";
}(),
install_source,
policy_service->GetTargetChannel(id).policy_or(std::string()),
policy_service->GetTargetVersionPrefix(id).policy_or(std::string()),
policy_service->IsRollbackToTargetVersionAllowed(id).policy_or(false),
[&policy_service, &id, &is_foreground, update_blocked] {
if (update_blocked) {
return true;
}
PolicyStatus<int> app_updates =
policy_service->GetPolicyForAppUpdates(id);
return app_updates &&
(app_updates.policy() == kPolicyDisabled ||
(!is_foreground &&
app_updates.policy() == kPolicyManualUpdatesOnly) ||
(is_foreground &&
app_updates.policy() == kPolicyAutomaticUpdatesOnly));
}(),
policy_same_version_update, persisted_data, verifier_format)
->MakeCrxComponent(
base::BindOnce([](update_client::CrxComponent component) {
return component;
}).Then(barrier_callback));
}
}
#if BUILDFLAG(IS_WIN)
namespace {
switch (error_code) {
INSTALL_SWITCH_ENTRY(update_client::InstallError::NONE);
INSTALL_SWITCH_ENTRY(update_client::InstallError::FINGERPRINT_WRITE_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::BAD_MANIFEST);
INSTALL_SWITCH_ENTRY(update_client::InstallError::GENERIC_ERROR);
INSTALL_SWITCH_ENTRY(update_client::InstallError::MOVE_FILES_ERROR);
INSTALL_SWITCH_ENTRY(update_client::InstallError::SET_PERMISSIONS_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::INVALID_VERSION);
INSTALL_SWITCH_ENTRY(update_client::InstallError::VERSION_NOT_UPGRADED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::NO_DIR_COMPONENT_USER);
INSTALL_SWITCH_ENTRY(update_client::InstallError::CLEAN_INSTALL_DIR_FAILED);
INSTALL_SWITCH_ENTRY(
update_client::InstallError::INSTALL_VERIFICATION_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::MISSING_INSTALL_PARAMS);
INSTALL_SWITCH_ENTRY(update_client::InstallError::LAUNCH_PROCESS_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::CUSTOM_ERROR_BASE);
default:
return GetLocalizedStringF(IDS_GENERIC_INSTALL_ERROR_BASE,
GetTextForSystemError(error_code), language);
}
#undef INSTALL_SWITCH_ENTRY
}
switch (error) {
DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::NO_URL);
DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::NO_HASH);
DOWNLOAD_SWITCH_ENTRY(
update_client::CrxDownloaderError::BITS_TOO_MANY_JOBS);
DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::GENERIC_ERROR);
case static_cast<int>(update_client::CrxDownloaderError::BAD_HASH):
return GetLocalizedString(IDS_DOWNLOAD_HASH_MISMATCH_BASE);
default:
return GetLocalizedStringF(IDS_GENERIC_DOWNLOAD_ERROR_BASE,
GetTextForSystemError(error), language);
}
#undef DOWNLOAD_SWITCH_ENTRY
}
switch (error) {
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kInvalidParams);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kInvalidFile);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kUnzipPathError);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kUnzipFailed);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kBadManifest);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kBadExtension);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kIoError);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kDeltaVerificationFailure);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaBadCommands);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaUnsupportedCommand);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaOperationFailure);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kDeltaPatchProcessFailure);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kDeltaMissingExistingFile);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kPuffinMissingPreviousCrx);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kCrxCacheNotProvided);
UNPACK_CACHING_SWITCH_ENTRY(
update_client::UnpackerError::kFailedToAddToCache);
UNPACK_CACHING_SWITCH_ENTRY(
update_client::UnpackerError::kFailedToCreateCacheDir);
default:
return GetLocalizedStringF(IDS_GENERIC_UNPACK_ERROR_BASE,
GetTextForSystemError(error), language);
}
#undef UNPACK_SWITCH_ENTRY
#undef UNPACK_CACHING_SWITCH_ENTRY
}
switch (error) {
SERVICE_SWITCH_ENTRY(update_client::ServiceError::SERVICE_WAIT_FAILED);
SERVICE_SWITCH_ENTRY(update_client::ServiceError::UPDATE_DISABLED);
SERVICE_SWITCH_ENTRY(update_client::ServiceError::CHECK_FOR_UPDATE_ONLY);
case static_cast<int>(update_client::ServiceError::CANCELLED):
return GetLocalizedString(IDS_SERVICE_ERROR_CANCELLED_BASE, language);
default:
return GetLocalizedStringF(IDS_GENERIC_SERVICE_ERROR_BASE,
GetTextForSystemError(error), language);
}
#undef SERVICE_SWITCH_ENTRY
}
switch (error) {
UPDATE_CHECK_SWITCH_ENTRY(
update_client::ProtocolError::RESPONSE_NOT_TRUSTED);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::MISSING_URLS);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::PARSE_FAILED);
UPDATE_CHECK_SWITCH_ENTRY(
update_client::ProtocolError::UPDATE_RESPONSE_NOT_FOUND);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::URL_FETCHER_FAILED);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::INVALID_APPID);
case static_cast<int>(update_client::ProtocolError::UNKNOWN_APPLICATION):
return GetLocalizedString(IDS_UNKNOWN_APPLICATION_BASE, language);
case static_cast<int>(update_client::ProtocolError::RESTRICTED_APPLICATION):
return GetLocalizedString(IDS_RESTRICTED_RESPONSE_FROM_SERVER_BASE,
language);
case static_cast<int>(update_client::ProtocolError::OS_NOT_SUPPORTED):
return GetLocalizedString(IDS_OS_NOT_SUPPORTED_BASE, language);
case static_cast<int>(update_client::ProtocolError::HW_NOT_SUPPORTED):
return GetLocalizedString(IDS_HW_NOT_SUPPORTED_BASE, language);
case static_cast<int>(update_client::ProtocolError::NO_HASH):
return GetLocalizedString(IDS_NO_HASH_BASE, language);
case static_cast<int>(update_client::ProtocolError::UNSUPPORTED_PROTOCOL):
return GetLocalizedString(IDS_UNSUPPORTED_PROTOCOL_BASE, language);
case static_cast<int>(update_client::ProtocolError::INTERNAL):
return GetLocalizedString(IDS_INTERNAL_BASE, language);
case HRESULT_FROM_WIN32(ERROR_WINHTTP_NAME_NOT_RESOLVED):
return GetLocalizedStringF(IDS_NO_NETWORK_PRESENT_ERROR_BASE,
GetExecutableRelativePath().value(), language);
default:
return GetLocalizedStringF(
IDS_GENERIC_UPDATE_CHECK_ERROR_BASE,
error >= 400 && error < 600
? base::UTF8ToWide(base::StringPrintf("HTTP %d", error))
: GetTextForSystemError(error),
language);
}
#undef UPDATE_CHECK_SWITCH_ENTRY
}
switch (error_code) {
POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY);
POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY);
POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL);
case GOOPDATEINSTALL_E_FILENAME_INVALID:
return GetLocalizedString(IDS_INVALID_INSTALLER_FILENAME_BASE, language);
case GOOPDATEINSTALL_E_INSTALLER_FAILED_START:
return GetLocalizedString(IDS_INSTALLER_FAILED_TO_START_BASE, language);
case GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT:
return GetLocalizedString(IDS_INSTALLER_TIMED_OUT_BASE, language);
case GOOPDATEINSTALL_E_INSTALL_ALREADY_RUNNING:
return GetLocalizedStringF(
IDS_GENERIC_INSTALLER_ERROR_BASE,
GetTextForSystemError(ERROR_INSTALL_ALREADY_RUNNING), language);
case ERROR_SUCCESS_REBOOT_INITIATED:
case ERROR_SUCCESS_REBOOT_REQUIRED:
case ERROR_SUCCESS_RESTART_REQUIRED:
return GetLocalizedStringF(IDS_INSTALL_REBOOT_BASE,
GetTextForSystemError(error_code), language);
default:
return GetLocalizedStringF(IDS_GENERIC_INSTALLER_ERROR_BASE,
GetTextForSystemError(error_code), language);
}
#undef POLICY_ERROR_SWITCH_ENTRY
}
} // namespace
} // namespace internal
namespace {
update_client::Callback MakeUpdateClientCallback(
base::OnceCallback<void(UpdateService::Result)> callback) {
return base::BindOnce(
[](base::OnceCallback<void(UpdateService::Result)> callback,
update_client::Error error) {
std::move(callback).Run(internal::ToResult(error));
},
std::move(callback));
}
UpdateService::UpdateState::State ToUpdateState(
update_client::ComponentState component_state) {
switch (component_state) {
case update_client::ComponentState::kNew:
return UpdateService::UpdateState::State::kNotStarted;
case update_client::ComponentState::kChecking:
return UpdateService::UpdateState::State::kCheckingForUpdates;
case update_client::ComponentState::kDownloading:
case update_client::ComponentState::kDownloadingDiff:
return UpdateService::UpdateState::State::kDownloading;
case update_client::ComponentState::kCanUpdate:
return UpdateService::UpdateState::State::kUpdateAvailable;
case update_client::ComponentState::kUpdating:
case update_client::ComponentState::kUpdatingDiff:
return UpdateService::UpdateState::State::kInstalling;
case update_client::ComponentState::kUpdated:
return UpdateService::UpdateState::State::kUpdated;
case update_client::ComponentState::kUpToDate:
return UpdateService::UpdateState::State::kNoUpdate;
case update_client::ComponentState::kUpdateError:
return UpdateService::UpdateState::State::kUpdateError;
case update_client::ComponentState::kRun:
case update_client::ComponentState::kLastStatus:
NOTREACHED();
}
}
UpdateService::ErrorCategory ToErrorCategory(
update_client::ErrorCategory error_category) {
switch (error_category) {
case update_client::ErrorCategory::kNone:
return UpdateService::ErrorCategory::kNone;
case update_client::ErrorCategory::kDownload:
return UpdateService::ErrorCategory::kDownload;
case update_client::ErrorCategory::kUnpack:
return UpdateService::ErrorCategory::kUnpack;
case update_client::ErrorCategory::kInstall:
return UpdateService::ErrorCategory::kInstall;
case update_client::ErrorCategory::kService:
return UpdateService::ErrorCategory::kService;
case update_client::ErrorCategory::kUpdateCheck:
return UpdateService::ErrorCategory::kUpdateCheck;
case update_client::ErrorCategory::kInstaller:
return UpdateService::ErrorCategory::kInstaller;
}
}
update_client::UpdateClient::CrxStateChangeCallback
MakeUpdateClientCrxStateChangeCallback(
scoped_refptr<update_client::Configurator> config,
scoped_refptr<PersistedData> persisted_data,
const bool new_install,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)> callback) {
return base::BindRepeating(
[](scoped_refptr<update_client::Configurator> config,
scoped_refptr<PersistedData> persisted_data, const bool new_install,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
callback,
const update_client::CrxUpdateItem& crx_update_item) {
UpdateService::UpdateState update_state;
update_state.app_id = crx_update_item.id;
update_state.state = ToUpdateState(crx_update_item.state);
update_state.next_version = crx_update_item.next_version;
update_state.downloaded_bytes = crx_update_item.downloaded_bytes;
update_state.total_bytes = crx_update_item.total_bytes;
update_state.install_progress = crx_update_item.install_progress;
update_state.error_category =
ToErrorCategory(crx_update_item.error_category);
update_state.error_code = crx_update_item.error_code;
update_state.extra_code1 = crx_update_item.extra_code1;
if (crx_update_item.installer_result) {
update_state.installer_cmd_line =
crx_update_item.installer_result->installer_cmd_line;
update_state.installer_text =
crx_update_item.installer_result->installer_text;
#if BUILDFLAG(IS_WIN)
if (update_state.installer_text.empty())
update_state.installer_text = internal::GetInstallerText(
UpdateService::ErrorCategory::kInstaller,
update_state.error_code, update_state.extra_code1, language);
#endif // BUILDFLAG(IS_WIN)
}
if (update_state.state == UpdateService::UpdateState::State::kUpdated ||
update_state.state ==
UpdateService::UpdateState::State::kUpdateError ||
update_state.state ==
UpdateService::UpdateState::State::kNoUpdate) {
#if BUILDFLAG(IS_WIN)
if (update_state.installer_text.empty())
update_state.installer_text = internal::GetInstallerText(
update_state.error_category, update_state.error_code,
update_state.extra_code1, language);
#endif // BUILDFLAG(IS_WIN)
CHECK(!update_state.app_id.empty());
CHECK_NE(update_state.state,
UpdateService::UpdateState::State::kUnknown);
[Link](update_state);
},
config, persisted_data, new_install, language, callback);
}
void FetchPoliciesDone(
base::OnceCallback<void(base::OnceCallback<void(UpdateService::Result)>)>
fetch_policies_done,
base::OnceCallback<void(UpdateService::Result)> callback,
int result) {
if (result != kErrorOk) {
LOG(ERROR) << "FetchPolicies failed: " << result;
// Ignore policy fetch failures and fall through.
}
std::move(fetch_policies_done).Run(std::move(callback));
}
} // namespace
UpdateServiceImplImpl::UpdateServiceImplImpl(scoped_refptr<Configurator> config)
: config_(config),
main_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
update_client_(update_client::UpdateClientFactory(config)) {}
void UpdateServiceImplImpl::GetVersion(
base::OnceCallback<void(const base::Version&)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), base::Version(kUpdaterVersion)));
}
void UpdateServiceImplImpl::MaybeInstallEnterpriseCompanionAppOTA(
base::OnceClosure callback,
bool is_cloud_managed) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!is_cloud_managed) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, std::move(callback));
return;
}
void UpdateServiceImplImpl::FetchPolicies(
policy::PolicyFetchReason reason,
base::OnceCallback<void(int)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (GetUpdaterScope() == UpdaterScope::kUser) {
VLOG(2) << "Policy fetch skipped for user updater.";
std::move(callback).Run(0);
} else {
if (config_->GetPolicyService()->IsCecaExperimentEnabled() &&
!config_->GetUpdaterPersistedData()
->GetProductVersion(enterprise_companion::kCompanionAppId)
.IsValid()) {
config_->GetPolicyService()->IsCloudManaged(base::BindOnce(
&UpdateServiceImplImpl::MaybeInstallEnterpriseCompanionAppOTA,
base::WrapRefCounted(this),
base::BindOnce(&PolicyService::FetchPolicies,
config_->GetPolicyService(), reason,
std::move(callback))));
} else {
config_->GetPolicyService()->FetchPolicies(reason, std::move(callback));
}
}
}
void UpdateServiceImplImpl::RegisterApp(
const RegistrationRequest& request,
base::OnceCallback<void(int)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (IsPathOnReadOnlyMount(request.existence_checker_path)) {
VLOG(1) << "Existence check path " << request.existence_checker_path
<< " is on read-only file system. Registration of "
<< request.app_id << " is skipped.";
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), kRegistrationError));
return;
}
if (!IsUpdaterOrCompanionApp(request.app_id)) {
config_->GetUpdaterPersistedData()->SetHadApps();
}
bool send_event = !config_->GetUpdaterPersistedData()
->GetProductVersion(request.app_id)
.IsValid() &&
[Link]() &&
[Link] > base::Version("0") &&
!config_->GetUpdaterPersistedData()->GetEulaRequired();
config_->GetUpdaterPersistedData()->RegisterApp(request);
if (send_event) {
update_client::CrxComponent install_data;
install_data.ap = [Link];
install_data.app_id = request.app_id;
install_data.brand = request.brand_code;
install_data.lang = [Link];
install_data.requires_network_encryption = false;
install_data.version = [Link];
update_client_->SendPing(
install_data,
{.event_type = update_client::protocol_request::kEventInstall,
.result = update_client::protocol_request::kEventResultSuccess},
base::BindOnce([](update_client::Error error) {
// Ignore event ping errors; registration has been successful.
}).Then(base::BindOnce(std::move(callback), kRegistrationSuccess)));
return;
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), kRegistrationSuccess));
}
void UpdateServiceImplImpl::GetAppStates(
base::OnceCallback<void(const std::vector<AppState>&)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(&UpdateServiceImplImpl::GetAppStatesImpl, this,
std::move(callback)));
}
void UpdateServiceImplImpl::GetAppStatesImpl(
base::OnceCallback<void(const std::vector<AppState>&)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
scoped_refptr<PersistedData> persisted_data =
config_->GetUpdaterPersistedData();
std::vector<std::string> app_ids = persisted_data->GetAppIds();
std::vector<AppState> apps;
for (const std::string& app_id : app_ids) {
AppState app_state;
app_state.app_id = app_id;
app_state.version = persisted_data->GetProductVersion(app_id);
app_state.version_path = persisted_data->GetProductVersionPath(app_id);
app_state.version_key = persisted_data->GetProductVersionKey(app_id);
app_state.ap = persisted_data->GetAP(app_id);
app_state.ap_path = persisted_data->GetAPPath(app_id);
app_state.ap_key = persisted_data->GetAPKey(app_id);
app_state.brand_code = persisted_data->GetBrandCode(app_id);
app_state.brand_path = persisted_data->GetBrandPath(app_id);
app_state.ecp = persisted_data->GetExistenceCheckerPath(app_id);
app_state.cohort = persisted_data->GetCohort(app_id);
apps.push_back(app_state);
}
main_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(apps)));
}
config_->GetUpdaterPersistedData()->SetLastStarted(
base::Time::NowFromSystemTime());
VLOG(1) << "last_started updated.";
new_tasks.push_back(base::BindOnce(
[](scoped_refptr<UpdateServiceImplImpl> update_service_impl,
base::OnceClosure callback) {
update_service_impl->FetchPolicies(
policy::PolicyFetchReason::kScheduled,
base::BindOnce(
[](base::OnceClosure callback, int /* ignore_result */) {
std::move(callback).Run();
},
std::move(callback)));
},
base::WrapRefCounted(this)));
new_tasks.push_back(
base::BindOnce(&CheckForUpdatesTask::Run,
base::MakeRefCounted<CheckForUpdatesTask>(
config_, GetUpdaterScope(),
/*task_name=*/"UpdateAll",
base::BindOnce(&UpdateServiceImplImpl::UpdateAll, this,
base::DoNothing()))));
new_tasks.push_back(base::BindOnce(
[](scoped_refptr<UpdateServiceImplImpl> self,
base::OnceClosure callback) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(
&UpdateServiceImplImpl::ForceInstall, self, base::DoNothing(),
base::BindOnce(
[](base::OnceClosure closure,
UpdateService::Result result) {
VLOG(0) << "ForceInstall task complete: " << result;
std::move(closure).Run();
},
std::move(callback))));
},
base::WrapRefCounted(this)));
new_tasks.push_back(base::BindOnce(
&AutoRunOnOsUpgradeTask::Run,
base::MakeRefCounted<AutoRunOnOsUpgradeTask>(
GetUpdaterScope(), config_->GetUpdaterPersistedData())));
new_tasks.push_back(base::BindOnce(
&CleanupTask::Run, base::MakeRefCounted<CleanupTask>(GetUpdaterScope())));
const auto barrier_closure =
base::BarrierClosure(new_tasks.size(), std::move(callback));
for (auto& task : new_tasks) {
tasks_.push(base::BindOnce(std::move(task),
barrier_closure.Then(base::BindRepeating(
&UpdateServiceImplImpl::TaskDone, this))));
}
if (tasks_.size() == new_tasks.size()) {
TaskStart();
}
}
void UpdateServiceImplImpl::TaskStart() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!tasks_.empty()) {
main_task_runner_->PostDelayedTask(FROM_HERE, std::move(tasks_.front()),
config_->InitialDelay());
}
}
void UpdateServiceImplImpl::TaskDone() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tasks_.pop();
TaskStart();
}
void UpdateServiceImplImpl::ForceInstall(
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PolicyStatus<std::vector<std::string>> force_install_apps_status =
config_->GetPolicyService()->GetForceInstallApps();
if (!force_install_apps_status) {
base::BindPostTask(main_task_runner_, std::move(callback))
.Run(UpdateService::Result::kSuccess);
return;
}
std::vector<std::string> force_install_apps =
force_install_apps_status.policy();
CHECK(!force_install_apps.empty());
std::vector<std::string> installed_app_ids =
config_->GetUpdaterPersistedData()->GetAppIds();
std::ranges::sort(force_install_apps);
std::ranges::sort(installed_app_ids);
std::vector<std::string> app_ids_to_install;
std::ranges::set_difference(force_install_apps, installed_app_ids,
std::back_inserter(app_ids_to_install));
if (app_ids_to_install.empty()) {
base::BindPostTask(main_task_runner_, std::move(callback))
.Run(UpdateService::Result::kSuccess);
return;
}
ShouldBlockUpdateForMeteredNetwork(
Priority::kBackground,
base::BindOnce(
&UpdateServiceImplImpl::OnShouldBlockForceInstallForMeteredNetwork,
this, app_ids_to_install, kEmptyFlatMap, kEmptyFlatMap,
UpdateService::PolicySameVersionUpdate::kNotAllowed, state_update,
std::move(callback)));
}
void UpdateServiceImplImpl::CheckForUpdate(
const std::string& app_id,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kUserRequest,
base::BindOnce(
&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::CheckForUpdateImpl, this,
app_id, priority, policy_same_version_update,
language, state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::CheckForUpdateImpl(
const std::string& app_id,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!config_->GetUpdaterPersistedData()
->GetProductVersion(app_id)
.IsValid()) {
VLOG(1) << __func__ << ": App not registered: " << app_id;
std::move(callback).Run(Result::kInvalidArgument);
return;
}
void UpdateServiceImplImpl::Update(
const std::string& app_id,
const std::string& install_data_index,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kScheduled,
base::BindOnce(&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::UpdateImpl,
this, app_id, install_data_index,
priority, policy_same_version_update,
language, state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::UpdateImpl(
const std::string& app_id,
const std::string& install_data_index,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!config_->GetUpdaterPersistedData()
->GetProductVersion(app_id)
.IsValid()) {
std::move(callback).Run(Result::kInvalidArgument);
return;
}
void UpdateServiceImplImpl::UpdateAll(
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(base::Contains(
app_ids, base::ToLowerASCII(kUpdaterAppId),
static_cast<std::string (*)(std::string_view)>(&base::ToLowerASCII)));
void UpdateServiceImplImpl::Install(
const RegistrationRequest& registration,
const std::string& client_install_data,
const std::string& install_data_index,
Priority priority,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kUserRequest,
base::BindOnce(&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::InstallImpl,
this, registration, client_install_data,
install_data_index, priority, language,
state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::InstallImpl(
const RegistrationRequest& registration,
const std::string& client_install_data,
const std::string& install_data_index,
Priority priority,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
void UpdateServiceImplImpl::RunInstaller(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id << ": " << installer_path << ": "
<< install_args << ": " << install_data << ": " << install_settings;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kUserRequest,
base::BindOnce(
&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::RunInstallerImpl, this,
app_id, installer_path, install_args, install_data,
install_settings, language, state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::RunInstallerImpl(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id << ": " << installer_path << ": "
<< install_args << ": " << install_data << ": " << install_settings;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!IsUpdaterOrCompanionApp(app_id)) {
config_->GetUpdaterPersistedData()->SetHadApps();
}
const base::Version pv =
config_->GetUpdaterPersistedData()->GetProductVersion(app_id);
const bool new_install = ![Link]();
AppInfo app_info(
GetUpdaterScope(), app_id,
config_->GetUpdaterPersistedData()->GetAP(app_id),
![Link]() ? language
: config_->GetUpdaterPersistedData()->GetLang(app_id),
config_->GetUpdaterPersistedData()->GetBrandCode(app_id), pv,
config_->GetUpdaterPersistedData()->GetExistenceCheckerPath(app_id));
// Pre-register the app in case there is no registration for it. This app
// registration is removed later if `new_install` is `true and if the app
// install encounters an error.
RegistrationRequest request;
request.app_id = app_id;
[Link] = language;
config_->GetUpdaterPersistedData()->RegisterApp(request);
return {};
}());
return RunApplicationInstaller(
app_info, installer_path, install_args,
WriteInstallerDataToTempFile(temp_dir.GetPath(), install_data),
usage_stats_enabled, kWaitForAppInstaller,
base::BindRepeating(
[](base::RepeatingCallback<void(const UpdateState&)>
state_update,
const std::string& app_id, int progress) {
VLOG(4) << "Install progress: " << progress;
UpdateState state;
state.app_id = app_id;
[Link] = UpdateState::State::kInstalling;
state.install_progress = progress;
state_update.Run(state);
},
state_update, app_info.app_id));
},
app_info, installer_path, install_args, install_data, state_update,
IsUpdaterOrCompanionApp(app_info.app_id) &&
config_->GetUpdaterPersistedData()->GetUsageStatsEnabled()),
base::BindOnce(
[](scoped_refptr<Configurator> config,
scoped_refptr<PersistedData> persisted_data,
scoped_refptr<update_client::UpdateClient> update_client,
base::Version installer_version,
base::RepeatingCallback<void(const UpdateState&)> state_update,
const std::string& app_id, const std::string& ap,
const std::string& brand, const std::string& language,
bool new_install, base::OnceCallback<void(Result)> callback,
const InstallerResult& result) {
// Final state update after installation completes.
UpdateState state;
state.app_id = app_id;
[Link] =
[Link] == update_client::ErrorCategory::kNone
? UpdateState::State::kUpdated
: UpdateState::State::kUpdateError;
state.error_category = ToErrorCategory([Link]);
state.error_code = [Link];
state.extra_code1 = [Link];
state.installer_text = result.installer_text;
#if BUILDFLAG(IS_WIN)
if (state.installer_text.empty())
state.installer_text = internal::GetInstallerText(
state.error_category, state.error_code, state.extra_code1,
language);
#endif // BUILDFLAG(IS_WIN)
state.installer_cmd_line = result.installer_cmd_line;
state_update.Run(state);
VLOG(1) << app_id
<< " installation completed: " << state.error_code;
if (!persisted_data->GetEulaRequired()) {
// Send an install ping. In some environments the ping cannot be
// sent, so do not wait for it to be sent before calling back the
// client.
update_client::CrxComponent install_data;
install_data.ap = ap;
install_data.app_id = app_id;
install_data.lang = language;
install_data.brand = brand;
install_data.requires_network_encryption = false;
install_data.install_source = kInstallSourceOffline;
install_data.version = installer_version;
update_client->SendPing(
install_data,
{.event_type = update_client::protocol_request::kEventInstall,
.result =
[Link] ==
update_client::ErrorCategory::kNone
? update_client::protocol_request::
kEventResultSuccess
: update_client::protocol_request::kEventResultError,
.error_category = [Link],
.error_code = [Link],
.extra_code1 = [Link]},
base::DoNothing());
}
std::move(callback).Run([Link] ==
update_client::ErrorCategory::kNone
? Result::kSuccess
: Result::kInstallFailed);
},
config_, config_->GetUpdaterPersistedData(), update_client_,
installer_version, state_update, app_info.app_id, app_info.ap,
app_info.brand, language, new_install, std::move(callback)));
}
policy = kPolicyEnabled;
if (is_install) {
PolicyStatus<int> app_install_policy_status =
config_->GetPolicyService()->GetPolicyForAppInstalls(app_id);
if (app_install_policy_status) {
policy = app_install_policy_status.policy();
}
return app_install_policy_status &&
(policy == kPolicyDisabled || (config_->IsPerUserInstall() &&
policy == kPolicyEnabledMachineOnly));
} else {
PolicyStatus<int> app_update_policy_status =
config_->GetPolicyService()->GetPolicyForAppUpdates(app_id);
if (app_update_policy_status) {
policy = app_update_policy_status.policy();
}
return app_update_policy_status &&
(policy == kPolicyDisabled ||
((policy == kPolicyManualUpdatesOnly) &&
(priority != Priority::kForeground)) ||
((policy == kPolicyAutomaticUpdatesOnly) &&
(priority == Priority::kForeground)));
}
}
void UpdateServiceImplImpl::HandleUpdateDisabledByPolicy(
const std::string& app_id,
int policy,
bool is_install,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UpdateState update_state;
update_state.app_id = app_id;
update_state.state = UpdateService::UpdateState::State::kUpdateError;
update_state.error_category = UpdateService::ErrorCategory::kInstaller;
update_state.error_code =
is_install ? GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY
: policy != kPolicyAutomaticUpdatesOnly
? GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY
: GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL;
update_state.extra_code1 = 0;
#if BUILDFLAG(IS_WIN)
update_state.installer_text = internal::GetInstallerText(
update_state.error_category, update_state.error_code,
update_state.extra_code1, language);
#endif // BUILDFLAG(IS_WIN)
base::BindPostTask(main_task_runner_, state_update).Run(update_state);
base::BindPostTask(main_task_runner_, std::move(callback))
.Run(UpdateService::Result::kUpdateCheckFailed);
}
void UpdateServiceImplImpl::OnShouldBlockCheckForUpdateForMeteredNetwork(
const std::string& app_id,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback,
bool update_blocked) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&update_client::UpdateClient::CheckForUpdate, update_client_, app_id,
base::BindOnce(&internal::GetComponents, config_->GetPolicyService(),
config_->GetCrxVerifierFormat(),
config_->GetUpdaterPersistedData(), kEmptyFlatMap,
kEmptyFlatMap,
priority == UpdateService::Priority::kForeground
? kInstallSourceOnDemand
: "",
priority, update_blocked, policy_same_version_update),
MakeUpdateClientCrxStateChangeCallback(
config_, config_->GetUpdaterPersistedData(),
/*new_install=*/false, language, state_update),
priority == Priority::kForeground,
MakeUpdateClientCallback(std::move(callback))));
}
void UpdateServiceImplImpl::OnShouldBlockUpdateForMeteredNetwork(
const std::vector<std::string>& app_ids,
const base::flat_map<std::string, std::string>& app_client_install_data,
const base::flat_map<std::string, std::string>& app_install_data_index,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback,
bool update_blocked) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&update_client::UpdateClient::Update, update_client_, app_ids,
base::BindOnce(&internal::GetComponents, config_->GetPolicyService(),
config_->GetCrxVerifierFormat(),
config_->GetUpdaterPersistedData(),
app_client_install_data, app_install_data_index,
priority == UpdateService::Priority::kForeground
? kInstallSourceOnDemand
: "",
priority, update_blocked, policy_same_version_update),
MakeUpdateClientCrxStateChangeCallback(
config_, config_->GetUpdaterPersistedData(),
/*new_install=*/false, language, state_update),
priority == Priority::kForeground,
MakeUpdateClientCallback(std::move(callback))));
}
void UpdateServiceImplImpl::OnShouldBlockForceInstallForMeteredNetwork(
const std::vector<std::string>& app_ids,
const base::flat_map<std::string, std::string>& app_client_install_data,
const base::flat_map<std::string, std::string>& app_install_data_index,
PolicySameVersionUpdate policy_same_version_update,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback,
bool update_blocked) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// The result from Install is only used for logging. Thus, arbitrarily pick
// the first non-success result to propagate.
auto barrier_callback = base::BarrierCallback<Result>(
app_ids.size(),
base::BindOnce([](const std::vector<Result>& results) {
auto error_it = std::ranges::find_if(
results, [](Result result) { return result != Result::kSuccess; });
return error_it == std::end(results) ? Result::kSuccess : *error_it;
}).Then(std::move(callback)));
UpdateServiceImplImpl::~UpdateServiceImplImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
config_->GetPrefService()->SchedulePendingLossyWrites();
}
} // namespace updater
#include "chrome/updater/update_service_impl_impl.h"
#include <algorithm>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/barrier_callback.h"
#include "base/barrier_closure.h"
#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/containers/queue.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/enterprise_companion/global_constants.h"
#include "chrome/updater/app/app_utils.h"
#include "chrome/updater/auto_run_on_os_upgrade_task.h"
#include "chrome/updater/branded_constants.h"
#include "chrome/updater/change_owners_task.h"
#include "chrome/updater/check_for_updates_task.h"
#include "chrome/updater/cleanup_task.h"
#include "chrome/updater/configurator.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/handle_inconsistent_apps_task.h"
#include "chrome/updater/installer.h"
#include "chrome/updater/persisted_data.h"
#include "chrome/updater/policy/service.h"
#include "chrome/updater/prefs.h"
#include "chrome/updater/registration_data.h"
#include "chrome/updater/remove_uninstalled_apps_task.h"
#include "chrome/updater/update_block_check.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/update_usage_stats_task.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util/util.h"
#include "components/policy/core/common/policy_types.h"
#include "components/prefs/pref_service.h"
#include "components/update_client/crx_update_item.h"
#include "components/update_client/protocol_definition.h"
#include "components/update_client/update_client.h"
#include "components/update_client/update_client_errors.h"
#if BUILDFLAG(IS_MAC)
#include <sys/mount.h>
#endif // BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_WIN)
#include <winhttp.h>
#include "base/win/registry.h"
#include "chrome/updater/util/win_util.h"
#include "chrome/updater/win/ui/l10n_util.h"
#include "chrome/updater/win/ui/resources/[Link]"
#include "chrome/updater/win/ui/resources/updater_installer_strings.h"
#include "chrome/updater/win/win_constants.h"
#endif // BUILDFLAG(IS_WIN)
namespace updater {
namespace internal {
UpdateService::Result ToResult(update_client::Error error) {
switch (error) {
case update_client::Error::NONE:
return UpdateService::Result::kSuccess;
case update_client::Error::UPDATE_IN_PROGRESS:
return UpdateService::Result::kUpdateInProgress;
case update_client::Error::UPDATE_CANCELED:
return UpdateService::Result::kUpdateCanceled;
case update_client::Error::RETRY_LATER:
return UpdateService::Result::kRetryLater;
case update_client::Error::SERVICE_ERROR:
return UpdateService::Result::kServiceFailed;
case update_client::Error::UPDATE_CHECK_ERROR:
return UpdateService::Result::kUpdateCheckFailed;
case update_client::Error::CRX_NOT_FOUND:
return UpdateService::Result::kAppNotFound;
case update_client::Error::INVALID_ARGUMENT:
case update_client::Error::BAD_CRX_DATA_CALLBACK:
return UpdateService::Result::kInvalidArgument;
case update_client::Error::MAX_VALUE:
NOTREACHED();
}
}
void GetComponents(
scoped_refptr<PolicyService> policy_service,
crx_file::VerifierFormat verifier_format,
scoped_refptr<PersistedData> persisted_data,
const base::flat_map<std::string, std::string>& app_client_install_data,
const base::flat_map<std::string, std::string>& app_install_data_index,
const std::string& install_source,
UpdateService::Priority priority,
bool update_blocked,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
const std::vector<std::string>& ids,
base::OnceCallback<
void(const std::vector<std::optional<update_client::CrxComponent>>&)>
callback) {
VLOG(1) << __func__
<< ". Same version update: " << policy_same_version_update;
const bool is_foreground = priority == UpdateService::Priority::kForeground;
auto barrier_callback =
base::BarrierCallback<std::optional<update_client::CrxComponent>>(
[Link](),
base::BindOnce(
[](const std::vector<std::string>& ids,
const std::vector<std::optional<update_client::CrxComponent>>&
unordered) {
// Re-order the vector to match the order of `ids`.
std::vector<std::optional<update_client::CrxComponent>> ordered;
for (const auto& id : ids) {
auto it = std::ranges::find_if(
unordered,
[&id](std::optional<update_client::CrxComponent> v) {
return v && v->app_id == id;
});
ordered.push_back(it != [Link]() ? *it : std::nullopt);
}
return ordered;
},
ids)
.Then(std::move(callback)));
for (const auto& id : ids) {
base::MakeRefCounted<Installer>(
id,
[&app_client_install_data, &id] {
auto it = app_client_install_data.find(id);
return it != app_client_install_data.end() ? it->second : "";
}(),
[&app_install_data_index, &id] {
auto it = app_install_data_index.find(id);
return it != app_install_data_index.end() ? it->second : "";
}(),
install_source,
policy_service->GetTargetChannel(id).policy_or(std::string()),
policy_service->GetTargetVersionPrefix(id).policy_or(std::string()),
policy_service->IsRollbackToTargetVersionAllowed(id).policy_or(false),
[&policy_service, &id, &is_foreground, update_blocked] {
if (update_blocked) {
return true;
}
PolicyStatus<int> app_updates =
policy_service->GetPolicyForAppUpdates(id);
return app_updates &&
(app_updates.policy() == kPolicyDisabled ||
(!is_foreground &&
app_updates.policy() == kPolicyManualUpdatesOnly) ||
(is_foreground &&
app_updates.policy() == kPolicyAutomaticUpdatesOnly));
}(),
policy_same_version_update, persisted_data, verifier_format)
->MakeCrxComponent(
base::BindOnce([](update_client::CrxComponent component) {
return component;
}).Then(barrier_callback));
}
}
#if BUILDFLAG(IS_WIN)
namespace {
switch (error_code) {
INSTALL_SWITCH_ENTRY(update_client::InstallError::NONE);
INSTALL_SWITCH_ENTRY(update_client::InstallError::FINGERPRINT_WRITE_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::BAD_MANIFEST);
INSTALL_SWITCH_ENTRY(update_client::InstallError::GENERIC_ERROR);
INSTALL_SWITCH_ENTRY(update_client::InstallError::MOVE_FILES_ERROR);
INSTALL_SWITCH_ENTRY(update_client::InstallError::SET_PERMISSIONS_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::INVALID_VERSION);
INSTALL_SWITCH_ENTRY(update_client::InstallError::VERSION_NOT_UPGRADED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::NO_DIR_COMPONENT_USER);
INSTALL_SWITCH_ENTRY(update_client::InstallError::CLEAN_INSTALL_DIR_FAILED);
INSTALL_SWITCH_ENTRY(
update_client::InstallError::INSTALL_VERIFICATION_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::MISSING_INSTALL_PARAMS);
INSTALL_SWITCH_ENTRY(update_client::InstallError::LAUNCH_PROCESS_FAILED);
INSTALL_SWITCH_ENTRY(update_client::InstallError::CUSTOM_ERROR_BASE);
default:
return GetLocalizedStringF(IDS_GENERIC_INSTALL_ERROR_BASE,
GetTextForSystemError(error_code), language);
}
#undef INSTALL_SWITCH_ENTRY
}
switch (error) {
DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::NO_URL);
DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::NO_HASH);
DOWNLOAD_SWITCH_ENTRY(
update_client::CrxDownloaderError::BITS_TOO_MANY_JOBS);
DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::GENERIC_ERROR);
case static_cast<int>(update_client::CrxDownloaderError::BAD_HASH):
return GetLocalizedString(IDS_DOWNLOAD_HASH_MISMATCH_BASE);
default:
return GetLocalizedStringF(IDS_GENERIC_DOWNLOAD_ERROR_BASE,
GetTextForSystemError(error), language);
}
#undef DOWNLOAD_SWITCH_ENTRY
}
switch (error) {
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kInvalidParams);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kInvalidFile);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kUnzipPathError);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kUnzipFailed);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kBadManifest);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kBadExtension);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kIoError);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kDeltaVerificationFailure);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaBadCommands);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaUnsupportedCommand);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaOperationFailure);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kDeltaPatchProcessFailure);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kDeltaMissingExistingFile);
UNPACK_SWITCH_ENTRY(
update_client::UnpackerError::kPuffinMissingPreviousCrx);
UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kCrxCacheNotProvided);
UNPACK_CACHING_SWITCH_ENTRY(
update_client::UnpackerError::kFailedToAddToCache);
UNPACK_CACHING_SWITCH_ENTRY(
update_client::UnpackerError::kFailedToCreateCacheDir);
default:
return GetLocalizedStringF(IDS_GENERIC_UNPACK_ERROR_BASE,
GetTextForSystemError(error), language);
}
#undef UNPACK_SWITCH_ENTRY
#undef UNPACK_CACHING_SWITCH_ENTRY
}
switch (error) {
SERVICE_SWITCH_ENTRY(update_client::ServiceError::SERVICE_WAIT_FAILED);
SERVICE_SWITCH_ENTRY(update_client::ServiceError::UPDATE_DISABLED);
SERVICE_SWITCH_ENTRY(update_client::ServiceError::CHECK_FOR_UPDATE_ONLY);
case static_cast<int>(update_client::ServiceError::CANCELLED):
return GetLocalizedString(IDS_SERVICE_ERROR_CANCELLED_BASE, language);
default:
return GetLocalizedStringF(IDS_GENERIC_SERVICE_ERROR_BASE,
GetTextForSystemError(error), language);
}
#undef SERVICE_SWITCH_ENTRY
}
switch (error) {
UPDATE_CHECK_SWITCH_ENTRY(
update_client::ProtocolError::RESPONSE_NOT_TRUSTED);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::MISSING_URLS);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::PARSE_FAILED);
UPDATE_CHECK_SWITCH_ENTRY(
update_client::ProtocolError::UPDATE_RESPONSE_NOT_FOUND);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::URL_FETCHER_FAILED);
UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::INVALID_APPID);
case static_cast<int>(update_client::ProtocolError::UNKNOWN_APPLICATION):
return GetLocalizedString(IDS_UNKNOWN_APPLICATION_BASE, language);
case static_cast<int>(update_client::ProtocolError::RESTRICTED_APPLICATION):
return GetLocalizedString(IDS_RESTRICTED_RESPONSE_FROM_SERVER_BASE,
language);
case static_cast<int>(update_client::ProtocolError::OS_NOT_SUPPORTED):
return GetLocalizedString(IDS_OS_NOT_SUPPORTED_BASE, language);
case static_cast<int>(update_client::ProtocolError::HW_NOT_SUPPORTED):
return GetLocalizedString(IDS_HW_NOT_SUPPORTED_BASE, language);
case static_cast<int>(update_client::ProtocolError::NO_HASH):
return GetLocalizedString(IDS_NO_HASH_BASE, language);
case static_cast<int>(update_client::ProtocolError::UNSUPPORTED_PROTOCOL):
return GetLocalizedString(IDS_UNSUPPORTED_PROTOCOL_BASE, language);
case static_cast<int>(update_client::ProtocolError::INTERNAL):
return GetLocalizedString(IDS_INTERNAL_BASE, language);
case HRESULT_FROM_WIN32(ERROR_WINHTTP_NAME_NOT_RESOLVED):
return GetLocalizedStringF(IDS_NO_NETWORK_PRESENT_ERROR_BASE,
GetExecutableRelativePath().value(), language);
default:
return GetLocalizedStringF(
IDS_GENERIC_UPDATE_CHECK_ERROR_BASE,
error >= 400 && error < 600
? base::UTF8ToWide(base::StringPrintf("HTTP %d", error))
: GetTextForSystemError(error),
language);
}
#undef UPDATE_CHECK_SWITCH_ENTRY
}
switch (error_code) {
POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY);
POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY);
POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL);
case GOOPDATEINSTALL_E_FILENAME_INVALID:
return GetLocalizedString(IDS_INVALID_INSTALLER_FILENAME_BASE, language);
case GOOPDATEINSTALL_E_INSTALLER_FAILED_START:
return GetLocalizedString(IDS_INSTALLER_FAILED_TO_START_BASE, language);
case GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT:
return GetLocalizedString(IDS_INSTALLER_TIMED_OUT_BASE, language);
case GOOPDATEINSTALL_E_INSTALL_ALREADY_RUNNING:
return GetLocalizedStringF(
IDS_GENERIC_INSTALLER_ERROR_BASE,
GetTextForSystemError(ERROR_INSTALL_ALREADY_RUNNING), language);
case ERROR_SUCCESS_REBOOT_INITIATED:
case ERROR_SUCCESS_REBOOT_REQUIRED:
case ERROR_SUCCESS_RESTART_REQUIRED:
return GetLocalizedStringF(IDS_INSTALL_REBOOT_BASE,
GetTextForSystemError(error_code), language);
default:
return GetLocalizedStringF(IDS_GENERIC_INSTALLER_ERROR_BASE,
GetTextForSystemError(error_code), language);
}
#undef POLICY_ERROR_SWITCH_ENTRY
}
} // namespace
} // namespace internal
namespace {
update_client::Callback MakeUpdateClientCallback(
base::OnceCallback<void(UpdateService::Result)> callback) {
return base::BindOnce(
[](base::OnceCallback<void(UpdateService::Result)> callback,
update_client::Error error) {
std::move(callback).Run(internal::ToResult(error));
},
std::move(callback));
}
UpdateService::UpdateState::State ToUpdateState(
update_client::ComponentState component_state) {
switch (component_state) {
case update_client::ComponentState::kNew:
return UpdateService::UpdateState::State::kNotStarted;
case update_client::ComponentState::kChecking:
return UpdateService::UpdateState::State::kCheckingForUpdates;
case update_client::ComponentState::kDownloading:
case update_client::ComponentState::kDownloadingDiff:
return UpdateService::UpdateState::State::kDownloading;
case update_client::ComponentState::kCanUpdate:
return UpdateService::UpdateState::State::kUpdateAvailable;
case update_client::ComponentState::kUpdating:
case update_client::ComponentState::kUpdatingDiff:
return UpdateService::UpdateState::State::kInstalling;
case update_client::ComponentState::kUpdated:
return UpdateService::UpdateState::State::kUpdated;
case update_client::ComponentState::kUpToDate:
return UpdateService::UpdateState::State::kNoUpdate;
case update_client::ComponentState::kUpdateError:
return UpdateService::UpdateState::State::kUpdateError;
case update_client::ComponentState::kRun:
case update_client::ComponentState::kLastStatus:
NOTREACHED();
}
}
UpdateService::ErrorCategory ToErrorCategory(
update_client::ErrorCategory error_category) {
switch (error_category) {
case update_client::ErrorCategory::kNone:
return UpdateService::ErrorCategory::kNone;
case update_client::ErrorCategory::kDownload:
return UpdateService::ErrorCategory::kDownload;
case update_client::ErrorCategory::kUnpack:
return UpdateService::ErrorCategory::kUnpack;
case update_client::ErrorCategory::kInstall:
return UpdateService::ErrorCategory::kInstall;
case update_client::ErrorCategory::kService:
return UpdateService::ErrorCategory::kService;
case update_client::ErrorCategory::kUpdateCheck:
return UpdateService::ErrorCategory::kUpdateCheck;
case update_client::ErrorCategory::kInstaller:
return UpdateService::ErrorCategory::kInstaller;
}
}
update_client::UpdateClient::CrxStateChangeCallback
MakeUpdateClientCrxStateChangeCallback(
scoped_refptr<update_client::Configurator> config,
scoped_refptr<PersistedData> persisted_data,
const bool new_install,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)> callback) {
return base::BindRepeating(
[](scoped_refptr<update_client::Configurator> config,
scoped_refptr<PersistedData> persisted_data, const bool new_install,
const std::string& language,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
callback,
const update_client::CrxUpdateItem& crx_update_item) {
UpdateService::UpdateState update_state;
update_state.app_id = crx_update_item.id;
update_state.state = ToUpdateState(crx_update_item.state);
update_state.next_version = crx_update_item.next_version;
update_state.downloaded_bytes = crx_update_item.downloaded_bytes;
update_state.total_bytes = crx_update_item.total_bytes;
update_state.install_progress = crx_update_item.install_progress;
update_state.error_category =
ToErrorCategory(crx_update_item.error_category);
update_state.error_code = crx_update_item.error_code;
update_state.extra_code1 = crx_update_item.extra_code1;
if (crx_update_item.installer_result) {
update_state.installer_cmd_line =
crx_update_item.installer_result->installer_cmd_line;
update_state.installer_text =
crx_update_item.installer_result->installer_text;
#if BUILDFLAG(IS_WIN)
if (update_state.installer_text.empty())
update_state.installer_text = internal::GetInstallerText(
UpdateService::ErrorCategory::kInstaller,
update_state.error_code, update_state.extra_code1, language);
#endif // BUILDFLAG(IS_WIN)
}
if (update_state.state == UpdateService::UpdateState::State::kUpdated ||
update_state.state ==
UpdateService::UpdateState::State::kUpdateError ||
update_state.state ==
UpdateService::UpdateState::State::kNoUpdate) {
#if BUILDFLAG(IS_WIN)
if (update_state.installer_text.empty())
update_state.installer_text = internal::GetInstallerText(
update_state.error_category, update_state.error_code,
update_state.extra_code1, language);
#endif // BUILDFLAG(IS_WIN)
CHECK(!update_state.app_id.empty());
CHECK_NE(update_state.state,
UpdateService::UpdateState::State::kUnknown);
[Link](update_state);
},
config, persisted_data, new_install, language, callback);
}
void FetchPoliciesDone(
base::OnceCallback<void(base::OnceCallback<void(UpdateService::Result)>)>
fetch_policies_done,
base::OnceCallback<void(UpdateService::Result)> callback,
int result) {
if (result != kErrorOk) {
LOG(ERROR) << "FetchPolicies failed: " << result;
// Ignore policy fetch failures and fall through.
}
std::move(fetch_policies_done).Run(std::move(callback));
}
} // namespace
UpdateServiceImplImpl::UpdateServiceImplImpl(scoped_refptr<Configurator> config)
: config_(config),
main_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
update_client_(update_client::UpdateClientFactory(config)) {}
void UpdateServiceImplImpl::GetVersion(
base::OnceCallback<void(const base::Version&)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), base::Version(kUpdaterVersion)));
}
void UpdateServiceImplImpl::MaybeInstallEnterpriseCompanionAppOTA(
base::OnceClosure callback,
bool is_cloud_managed) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!is_cloud_managed) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, std::move(callback));
return;
}
void UpdateServiceImplImpl::FetchPolicies(
policy::PolicyFetchReason reason,
base::OnceCallback<void(int)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (GetUpdaterScope() == UpdaterScope::kUser) {
VLOG(2) << "Policy fetch skipped for user updater.";
std::move(callback).Run(0);
} else {
if (config_->GetPolicyService()->IsCecaExperimentEnabled() &&
!config_->GetUpdaterPersistedData()
->GetProductVersion(enterprise_companion::kCompanionAppId)
.IsValid()) {
config_->GetPolicyService()->IsCloudManaged(base::BindOnce(
&UpdateServiceImplImpl::MaybeInstallEnterpriseCompanionAppOTA,
base::WrapRefCounted(this),
base::BindOnce(&PolicyService::FetchPolicies,
config_->GetPolicyService(), reason,
std::move(callback))));
} else {
config_->GetPolicyService()->FetchPolicies(reason, std::move(callback));
}
}
}
void UpdateServiceImplImpl::RegisterApp(
const RegistrationRequest& request,
base::OnceCallback<void(int)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (IsPathOnReadOnlyMount(request.existence_checker_path)) {
VLOG(1) << "Existence check path " << request.existence_checker_path
<< " is on read-only file system. Registration of "
<< request.app_id << " is skipped.";
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), kRegistrationError));
return;
}
if (!IsUpdaterOrCompanionApp(request.app_id)) {
config_->GetUpdaterPersistedData()->SetHadApps();
}
bool send_event = !config_->GetUpdaterPersistedData()
->GetProductVersion(request.app_id)
.IsValid() &&
[Link]() &&
[Link] > base::Version("0") &&
!config_->GetUpdaterPersistedData()->GetEulaRequired();
config_->GetUpdaterPersistedData()->RegisterApp(request);
if (send_event) {
update_client::CrxComponent install_data;
install_data.ap = [Link];
install_data.app_id = request.app_id;
install_data.brand = request.brand_code;
install_data.lang = [Link];
install_data.requires_network_encryption = false;
install_data.version = [Link];
update_client_->SendPing(
install_data,
{.event_type = update_client::protocol_request::kEventInstall,
.result = update_client::protocol_request::kEventResultSuccess},
base::BindOnce([](update_client::Error error) {
// Ignore event ping errors; registration has been successful.
}).Then(base::BindOnce(std::move(callback), kRegistrationSuccess)));
return;
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), kRegistrationSuccess));
}
void UpdateServiceImplImpl::GetAppStates(
base::OnceCallback<void(const std::vector<AppState>&)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(&UpdateServiceImplImpl::GetAppStatesImpl, this,
std::move(callback)));
}
void UpdateServiceImplImpl::GetAppStatesImpl(
base::OnceCallback<void(const std::vector<AppState>&)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
scoped_refptr<PersistedData> persisted_data =
config_->GetUpdaterPersistedData();
std::vector<std::string> app_ids = persisted_data->GetAppIds();
std::vector<AppState> apps;
for (const std::string& app_id : app_ids) {
AppState app_state;
app_state.app_id = app_id;
app_state.version = persisted_data->GetProductVersion(app_id);
app_state.version_path = persisted_data->GetProductVersionPath(app_id);
app_state.version_key = persisted_data->GetProductVersionKey(app_id);
app_state.ap = persisted_data->GetAP(app_id);
app_state.ap_path = persisted_data->GetAPPath(app_id);
app_state.ap_key = persisted_data->GetAPKey(app_id);
app_state.brand_code = persisted_data->GetBrandCode(app_id);
app_state.brand_path = persisted_data->GetBrandPath(app_id);
app_state.ecp = persisted_data->GetExistenceCheckerPath(app_id);
app_state.cohort = persisted_data->GetCohort(app_id);
apps.push_back(app_state);
}
main_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(apps)));
}
config_->GetUpdaterPersistedData()->SetLastStarted(
base::Time::NowFromSystemTime());
VLOG(1) << "last_started updated.";
std::vector<base::OnceCallback<void(base::OnceClosure)>> new_tasks;
new_tasks.push_back(
base::BindOnce(&HandleInconsistentAppsTask::Run,
base::MakeRefCounted<HandleInconsistentAppsTask>(
config_, GetUpdaterScope())));
new_tasks.push_back(
base::BindOnce(&RemoveUninstalledAppsTask::Run,
base::MakeRefCounted<RemoveUninstalledAppsTask>(
config_, GetUpdaterScope())));
new_tasks.push_back(base::BindOnce(
&UpdateUsageStatsTask::Run,
base::MakeRefCounted<UpdateUsageStatsTask>(
GetUpdaterScope(), config_->GetUpdaterPersistedData())));
new_tasks.push_back(MakeChangeOwnersTask(config_->GetUpdaterPersistedData(),
GetUpdaterScope()));
new_tasks.push_back(base::BindOnce(
[](scoped_refptr<UpdateServiceImplImpl> update_service_impl,
base::OnceClosure callback) {
update_service_impl->FetchPolicies(
policy::PolicyFetchReason::kScheduled,
base::BindOnce(
[](base::OnceClosure callback, int /* ignore_result */) {
std::move(callback).Run();
},
std::move(callback)));
},
base::WrapRefCounted(this)));
new_tasks.push_back(
base::BindOnce(&CheckForUpdatesTask::Run,
base::MakeRefCounted<CheckForUpdatesTask>(
config_, GetUpdaterScope(),
/*task_name=*/"UpdateAll",
base::BindOnce(&UpdateServiceImplImpl::UpdateAll, this,
base::DoNothing()))));
new_tasks.push_back(base::BindOnce(
[](scoped_refptr<UpdateServiceImplImpl> self,
base::OnceClosure callback) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(
&UpdateServiceImplImpl::ForceInstall, self, base::DoNothing(),
base::BindOnce(
[](base::OnceClosure closure,
UpdateService::Result result) {
VLOG(0) << "ForceInstall task complete: " << result;
std::move(closure).Run();
},
std::move(callback))));
},
base::WrapRefCounted(this)));
new_tasks.push_back(base::BindOnce(
&AutoRunOnOsUpgradeTask::Run,
base::MakeRefCounted<AutoRunOnOsUpgradeTask>(
GetUpdaterScope(), config_->GetUpdaterPersistedData())));
new_tasks.push_back(base::BindOnce(
&CleanupTask::Run, base::MakeRefCounted<CleanupTask>(GetUpdaterScope())));
const auto barrier_closure =
base::BarrierClosure(new_tasks.size(), std::move(callback));
for (auto& task : new_tasks) {
tasks_.push(base::BindOnce(std::move(task),
barrier_closure.Then(base::BindRepeating(
&UpdateServiceImplImpl::TaskDone, this))));
}
if (tasks_.size() == new_tasks.size()) {
TaskStart();
}
}
void UpdateServiceImplImpl::TaskStart() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!tasks_.empty()) {
main_task_runner_->PostDelayedTask(FROM_HERE, std::move(tasks_.front()),
config_->InitialDelay());
}
}
void UpdateServiceImplImpl::TaskDone() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tasks_.pop();
TaskStart();
}
void UpdateServiceImplImpl::ForceInstall(
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PolicyStatus<std::vector<std::string>> force_install_apps_status =
config_->GetPolicyService()->GetForceInstallApps();
if (!force_install_apps_status) {
base::BindPostTask(main_task_runner_, std::move(callback))
.Run(UpdateService::Result::kSuccess);
return;
}
std::vector<std::string> force_install_apps =
force_install_apps_status.policy();
CHECK(!force_install_apps.empty());
std::vector<std::string> installed_app_ids =
config_->GetUpdaterPersistedData()->GetAppIds();
std::ranges::sort(force_install_apps);
std::ranges::sort(installed_app_ids);
std::vector<std::string> app_ids_to_install;
std::ranges::set_difference(force_install_apps, installed_app_ids,
std::back_inserter(app_ids_to_install));
if (app_ids_to_install.empty()) {
base::BindPostTask(main_task_runner_, std::move(callback))
.Run(UpdateService::Result::kSuccess);
return;
}
VLOG(1) << __func__ << ": app_ids_to_install: "
<< base::JoinString(app_ids_to_install, " ");
ShouldBlockUpdateForMeteredNetwork(
Priority::kBackground,
base::BindOnce(
&UpdateServiceImplImpl::OnShouldBlockForceInstallForMeteredNetwork,
this, app_ids_to_install, kEmptyFlatMap, kEmptyFlatMap,
UpdateService::PolicySameVersionUpdate::kNotAllowed, state_update,
std::move(callback)));
}
void UpdateServiceImplImpl::CheckForUpdate(
const std::string& app_id,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kUserRequest,
base::BindOnce(
&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::CheckForUpdateImpl, this,
app_id, priority, policy_same_version_update,
language, state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::CheckForUpdateImpl(
const std::string& app_id,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!config_->GetUpdaterPersistedData()
->GetProductVersion(app_id)
.IsValid()) {
VLOG(1) << __func__ << ": App not registered: " << app_id;
std::move(callback).Run(Result::kInvalidArgument);
return;
}
void UpdateServiceImplImpl::Update(
const std::string& app_id,
const std::string& install_data_index,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kScheduled,
base::BindOnce(&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::UpdateImpl,
this, app_id, install_data_index,
priority, policy_same_version_update,
language, state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::UpdateImpl(
const std::string& app_id,
const std::string& install_data_index,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!config_->GetUpdaterPersistedData()
->GetProductVersion(app_id)
.IsValid()) {
std::move(callback).Run(Result::kInvalidArgument);
return;
}
void UpdateServiceImplImpl::UpdateAll(
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(base::Contains(
app_ids, base::ToLowerASCII(kUpdaterAppId),
static_cast<std::string (*)(std::string_view)>(&base::ToLowerASCII)));
void UpdateServiceImplImpl::Install(
const RegistrationRequest& registration,
const std::string& client_install_data,
const std::string& install_data_index,
Priority priority,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kUserRequest,
base::BindOnce(&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::InstallImpl,
this, registration, client_install_data,
install_data_index, priority, language,
state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::InstallImpl(
const RegistrationRequest& registration,
const std::string& client_install_data,
const std::string& install_data_index,
Priority priority,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
void UpdateServiceImplImpl::RunInstaller(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id << ": " << installer_path << ": "
<< install_args << ": " << install_data << ": " << install_settings;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::MakeRefCounted<HandleInconsistentAppsTask>(config_, GetUpdaterScope())
->Run(base::BindOnce(
&UpdateServiceImplImpl::FetchPolicies, this,
policy::PolicyFetchReason::kUserRequest,
base::BindOnce(
&FetchPoliciesDone,
base::BindOnce(&UpdateServiceImplImpl::RunInstallerImpl, this,
app_id, installer_path, install_args, install_data,
install_settings, language, state_update),
std::move(callback))));
}
void UpdateServiceImplImpl::RunInstallerImpl(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
VLOG(1) << __func__ << ": " << app_id << ": " << installer_path << ": "
<< install_args << ": " << install_data << ": " << install_settings;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!IsUpdaterOrCompanionApp(app_id)) {
config_->GetUpdaterPersistedData()->SetHadApps();
}
const base::Version pv =
config_->GetUpdaterPersistedData()->GetProductVersion(app_id);
const bool new_install = ![Link]();
AppInfo app_info(
GetUpdaterScope(), app_id,
config_->GetUpdaterPersistedData()->GetAP(app_id),
![Link]() ? language
: config_->GetUpdaterPersistedData()->GetLang(app_id),
config_->GetUpdaterPersistedData()->GetBrandCode(app_id), pv,
config_->GetUpdaterPersistedData()->GetExistenceCheckerPath(app_id));
// Pre-register the app in case there is no registration for it. This app
// registration is removed later if `new_install` is `true and if the app
// install encounters an error.
RegistrationRequest request;
request.app_id = app_id;
[Link] = language;
config_->GetUpdaterPersistedData()->RegisterApp(request);
return {};
}());
return RunApplicationInstaller(
app_info, installer_path, install_args,
WriteInstallerDataToTempFile(temp_dir.GetPath(), install_data),
usage_stats_enabled, kWaitForAppInstaller,
base::BindRepeating(
[](base::RepeatingCallback<void(const UpdateState&)>
state_update,
const std::string& app_id, int progress) {
VLOG(4) << "Install progress: " << progress;
UpdateState state;
state.app_id = app_id;
[Link] = UpdateState::State::kInstalling;
state.install_progress = progress;
state_update.Run(state);
},
state_update, app_info.app_id));
},
app_info, installer_path, install_args, install_data, state_update,
IsUpdaterOrCompanionApp(app_info.app_id) &&
config_->GetUpdaterPersistedData()->GetUsageStatsEnabled()),
base::BindOnce(
[](scoped_refptr<Configurator> config,
scoped_refptr<PersistedData> persisted_data,
scoped_refptr<update_client::UpdateClient> update_client,
base::Version installer_version,
base::RepeatingCallback<void(const UpdateState&)> state_update,
const std::string& app_id, const std::string& ap,
const std::string& brand, const std::string& language,
bool new_install, base::OnceCallback<void(Result)> callback,
const InstallerResult& result) {
// Final state update after installation completes.
UpdateState state;
state.app_id = app_id;
[Link] =
[Link] == update_client::ErrorCategory::kNone
? UpdateState::State::kUpdated
: UpdateState::State::kUpdateError;
state.error_category = ToErrorCategory([Link]);
state.error_code = [Link];
state.extra_code1 = [Link];
state.installer_text = result.installer_text;
#if BUILDFLAG(IS_WIN)
if (state.installer_text.empty())
state.installer_text = internal::GetInstallerText(
state.error_category, state.error_code, state.extra_code1,
language);
#endif // BUILDFLAG(IS_WIN)
state.installer_cmd_line = result.installer_cmd_line;
state_update.Run(state);
VLOG(1) << app_id
<< " installation completed: " << state.error_code;
if (!persisted_data->GetEulaRequired()) {
// Send an install ping. In some environments the ping cannot be
// sent, so do not wait for it to be sent before calling back the
// client.
update_client::CrxComponent install_data;
install_data.ap = ap;
install_data.app_id = app_id;
install_data.lang = language;
install_data.brand = brand;
install_data.requires_network_encryption = false;
install_data.install_source = kInstallSourceOffline;
install_data.version = installer_version;
update_client->SendPing(
install_data,
{.event_type = update_client::protocol_request::kEventInstall,
.result =
[Link] ==
update_client::ErrorCategory::kNone
? update_client::protocol_request::
kEventResultSuccess
: update_client::protocol_request::kEventResultError,
.error_category = [Link],
.error_code = [Link],
.extra_code1 = [Link]},
base::DoNothing());
}
std::move(callback).Run([Link] ==
update_client::ErrorCategory::kNone
? Result::kSuccess
: Result::kInstallFailed);
},
config_, config_->GetUpdaterPersistedData(), update_client_,
installer_version, state_update, app_info.app_id, app_info.ap,
app_info.brand, language, new_install, std::move(callback)));
}
policy = kPolicyEnabled;
if (is_install) {
PolicyStatus<int> app_install_policy_status =
config_->GetPolicyService()->GetPolicyForAppInstalls(app_id);
if (app_install_policy_status) {
policy = app_install_policy_status.policy();
}
return app_install_policy_status &&
(policy == kPolicyDisabled || (config_->IsPerUserInstall() &&
policy == kPolicyEnabledMachineOnly));
} else {
PolicyStatus<int> app_update_policy_status =
config_->GetPolicyService()->GetPolicyForAppUpdates(app_id);
if (app_update_policy_status) {
policy = app_update_policy_status.policy();
}
return app_update_policy_status &&
(policy == kPolicyDisabled ||
((policy == kPolicyManualUpdatesOnly) &&
(priority != Priority::kForeground)) ||
((policy == kPolicyAutomaticUpdatesOnly) &&
(priority == Priority::kForeground)));
}
}
void UpdateServiceImplImpl::HandleUpdateDisabledByPolicy(
const std::string& app_id,
int policy,
bool is_install,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UpdateState update_state;
update_state.app_id = app_id;
update_state.state = UpdateService::UpdateState::State::kUpdateError;
update_state.error_category = UpdateService::ErrorCategory::kInstaller;
update_state.error_code =
is_install ? GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY
: policy != kPolicyAutomaticUpdatesOnly
? GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY
: GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL;
update_state.extra_code1 = 0;
#if BUILDFLAG(IS_WIN)
update_state.installer_text = internal::GetInstallerText(
update_state.error_category, update_state.error_code,
update_state.extra_code1, language);
#endif // BUILDFLAG(IS_WIN)
base::BindPostTask(main_task_runner_, state_update).Run(update_state);
base::BindPostTask(main_task_runner_, std::move(callback))
.Run(UpdateService::Result::kUpdateCheckFailed);
}
void UpdateServiceImplImpl::OnShouldBlockCheckForUpdateForMeteredNetwork(
const std::string& app_id,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback,
bool update_blocked) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&update_client::UpdateClient::CheckForUpdate, update_client_, app_id,
base::BindOnce(&internal::GetComponents, config_->GetPolicyService(),
config_->GetCrxVerifierFormat(),
config_->GetUpdaterPersistedData(), kEmptyFlatMap,
kEmptyFlatMap,
priority == UpdateService::Priority::kForeground
? kInstallSourceOnDemand
: "",
priority, update_blocked, policy_same_version_update),
MakeUpdateClientCrxStateChangeCallback(
config_, config_->GetUpdaterPersistedData(),
/*new_install=*/false, language, state_update),
priority == Priority::kForeground,
MakeUpdateClientCallback(std::move(callback))));
}
void UpdateServiceImplImpl::OnShouldBlockUpdateForMeteredNetwork(
const std::vector<std::string>& app_ids,
const base::flat_map<std::string, std::string>& app_client_install_data,
const base::flat_map<std::string, std::string>& app_install_data_index,
Priority priority,
PolicySameVersionUpdate policy_same_version_update,
const std::string& language,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback,
bool update_blocked) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&update_client::UpdateClient::Update, update_client_, app_ids,
base::BindOnce(&internal::GetComponents, config_->GetPolicyService(),
config_->GetCrxVerifierFormat(),
config_->GetUpdaterPersistedData(),
app_client_install_data, app_install_data_index,
priority == UpdateService::Priority::kForeground
? kInstallSourceOnDemand
: "",
priority, update_blocked, policy_same_version_update),
MakeUpdateClientCrxStateChangeCallback(
config_, config_->GetUpdaterPersistedData(),
/*new_install=*/false, language, state_update),
priority == Priority::kForeground,
MakeUpdateClientCallback(std::move(callback))));
}
void UpdateServiceImplImpl::OnShouldBlockForceInstallForMeteredNetwork(
const std::vector<std::string>& app_ids,
const base::flat_map<std::string, std::string>& app_client_install_data,
const base::flat_map<std::string, std::string>& app_install_data_index,
PolicySameVersionUpdate policy_same_version_update,
base::RepeatingCallback<void(const UpdateState&)> state_update,
base::OnceCallback<void(Result)> callback,
bool update_blocked) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// The result from Install is only used for logging. Thus, arbitrarily pick
// the first non-success result to propagate.
auto barrier_callback = base::BarrierCallback<Result>(
app_ids.size(),
base::BindOnce([](const std::vector<Result>& results) {
auto error_it = std::ranges::find_if(
results, [](Result result) { return result != Result::kSuccess; });
return error_it == std::end(results) ? Result::kSuccess : *error_it;
}).Then(std::move(callback)));
UpdateServiceImplImpl::~UpdateServiceImplImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
config_->GetPrefService()->SchedulePendingLossyWrites();
}
} // namespace updater
mport("//build/config/chrome_build.gni")
import("//build/config/chromeos/[Link]")
import("//build/config/chromeos/ui_mode.gni")
import("//build/config/compiler/[Link]")
import("//build/config/compiler/pgo/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/sanitizers/[Link]")
import("//build/config/[Link]")
import("//build/config/win/console_app.gni")
import("//build/config/win/[Link]")
import("//build/private_code_test/private_code_test.gni")
import("//build/toolchain/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/chrome_paks.gni")
import("//chrome/common/[Link]")
import("//chrome/process_version_rc_template.gni")
import("//components/nacl/[Link]")
import("//components/optimization_guide/[Link]")
import("//extensions/buildflags/[Link]")
import("//media/media_options.gni")
import("//ppapi/buildflags/[Link]")
import("//third_party/angle/gni/[Link]")
import("//third_party/blink/public/public_features.gni")
import("//third_party/widevine/cdm/[Link]")
import("//tools/resources/generate_resource_allowlist.gni")
import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
import("//ui/gl/[Link]")
import("//v8/gni/[Link]")
if (is_android) {
import("//build/config/android/[Link]")
} else if (is_linux || is_chromeos) {
import("//build/linux/extract_symbols.gni")
import("//build/linux/strip_binary.gni")
} else if (is_mac) {
import("//build/apple/compile_entitlements.gni")
import("//build/apple/compile_plist.gni")
import("//build/apple/tweak_info_plist.gni")
import("//build/compiled_action.gni")
import("//build/config/apple/[Link]")
import("//build/config/mac/mac_sdk.gni")
import("//build/config/mac/[Link]")
import("//build/util/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/updater/[Link]")
import("//chrome/[Link]")
import("//content/public/app/mac_helpers.gni")
import("//media/cdm/library_cdm/cdm_paths.gni")
import("//services/on_device_model/on_device_model.gni")
import("//third_party/icu/[Link]")
}
if (_cros_generate_embed_section_target) {
import("//build/chromeos/embed_sections.gni")
}
declare_args() {
# On macOS, `is_chrome_branded` builds that have been signed locally will not
# launch because certain entitlements are tied to the official Google code
# signing identity. If `include_branded_entitlements` is set to false, these
# entitlements will be skipped.
include_branded_entitlements = true
}
if (is_win) {
action("reorder_imports") {
script = "//build/win/[Link]"
# initialexe/ is used so that the we can reorder imports and write back to
# the final destination at $root_out_dir/.
inputs = [
"$root_out_dir/initialexe/[Link]",
"$root_out_dir/initialexe/[Link]",
]
outputs = [
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
]
args = [
"-i",
rebase_path("$root_out_dir/initialexe", root_build_dir),
"-o",
rebase_path("$root_out_dir", root_build_dir),
"-a",
current_cpu,
]
deps = [ ":chrome_initial" ]
}
}
if (is_android) {
deps += [ "//chrome/android:chrome_public_apk" ]
} else {
deps += [ ":chrome" ]
}
if (is_win) {
deps += [ ":chrome_dll" ]
}
# This should not pull in installer strings. This is will bloat the binary
# for no reason and is easy to mess up. See the comment at the top of
# //chrome/installer/util/[Link].
assert_no_deps = [ "//chrome/installer/util:strings" ]
}
if (is_win) {
_chrome_output_name = "initialexe/chrome"
} else {
_chrome_output_name = "chrome"
}
executable("chrome_initial") {
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
output_name = _chrome_output_name
if (is_chromeos) {
data_deps += [
"//components/variations/cros_evaluate_seed:evaluate_seed",
"//sandbox/linux:chrome_sandbox",
]
if (build_mojo_proxy) {
data_deps += [ "//mojo/proxy:mojo_proxy" ]
}
deps += [
"//components/exo/wayland:test_controller_stub",
"//components/exo/wayland:ui_controls_protocol_stub",
]
}
if (is_win) {
sources += [
"app/chrome_exe.rc",
"app/chrome_exe_main_win.cc",
"app/delay_load_failure_hook_win.cc",
"app/delay_load_failure_hook_win.h",
"app/main_dll_loader_win.cc",
"app/main_dll_loader_win.h",
"common/crash_keys.cc",
"common/crash_keys.h",
]
deps += [
":chrome_dll",
":chrome_exe_version",
":copy_first_run",
":packed_resources_integrity_header",
":visual_elements_resources",
"//base",
"//build:branding_buildflags",
"//chrome/app:chrome_exe_main_exports",
"//chrome/app:exit_code_watcher",
"//chrome/app/version_assembly:chrome_exe_manifest",
"//chrome/browser:active_use_util",
"//chrome/browser:chrome_process_finder",
"//chrome/browser/policy:path_parser",
"//chrome/chrome_elf",
"//chrome/common:constants",
"//chrome/common/win:delay_load_failure_support",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//chrome/installer/util:constants",
"//chrome/installer/util:did_run_support",
"//components/crash/core/app",
"//components/crash/core/app:run_as_crashpad_handler",
"//components/crash/core/common",
"//components/crash/win:chrome_wer",
"//components/webui/flags:switches",
"//content:sandbox_helper_win",
"//content/public/common:static_switches",
"//crypto",
"//gpu/command_buffer/service",
"//sandbox",
"//sandbox/policy",
"//sandbox/policy/mojom",
"//third_party/breakpad:breakpad_handler",
"//third_party/breakpad:breakpad_sender",
"//third_party/crashpad/crashpad/util",
"//ui/gl",
]
data_deps = [
"//chrome/app/version_assembly:version_assembly_manifest",
"//chrome/browser/web_applications/chrome_pwa_launcher",
"//chrome/chrome_proxy",
"//chrome/elevation_service",
"//chrome/notification_helper",
"//chrome/windows_services/elevated_tracing_service",
]
if (enable_platform_experience) {
data_deps +=
[ "//chrome/browser/platform_experience/win:os_update_handler" ]
}
defines += [ "CHROME_EXE_MAIN" ]
if (win_console_app) {
defines += [ "WIN_CONSOLE_APP" ]
} else {
# Set /SUBSYSTEM:WINDOWS for [Link] itself, unless a console build
# has been requested.
configs -= [ "//build/config/win:console" ]
configs += [ "//build/config/win:windowed" ]
}
configs += [
"//build/config/win:delayloads",
"//build/config/win:delayloads_not_for_child_dll",
]
if (current_cpu == "x86") {
# Set the initial stack size to 0.5MiB, instead of the 1.5MiB needed by
# Chrome's main thread. This saves significant memory on threads (like
# those in the Windows thread pool, and others) whose stack size we can
# only control through this setting. Because Chrome's main thread needs
# a minimum 1.5 MiB stack, the main thread (in 32-bit builds only) uses
# fibers to switch to a 1.5 MiB stack before running any other code.
ldflags = [ "/STACK:0x80000" ]
} else {
# Increase the initial stack size. The default is 1MB, this is 8MB.
ldflags = [ "/STACK:0x800000" ]
}
} else if (use_aura) {
# Non-Windows aura entrypoint.
sources += [ "app/chrome_exe_main_aura.cc" ]
}
if (is_linux || is_chromeos) {
sources += [
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
deps += [
# On Linux, link the dependencies (libraries) that make up actual
# Chromium functionality directly into the executable.
":dependencies",
"//chrome/common:version_header",
public_deps = [
":xdg_mime", # Needs to be public for installer to consume files.
"//chrome/common:buildflags",
]
data_deps += [ "//components/crash/core/app:chrome_crashpad_handler" ]
ldflags = []
# Chrome OS debug builds for arm need to pass --long-plt to the linker.
# See [Link]
if (is_chromeos && is_debug && target_cpu == "arm") {
ldflags += [ "-Wl,--long-plt" ]
}
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [
"//chrome/browser/ash/locale",
"//chrome/browser/ash/schedqos",
]
}
if (use_ozone) {
deps += [ "//ui/ozone" ]
if (is_linux) {
deps += [ "//ui/linux:display_server_utils" ]
}
}
}
data_deps += [
"//chrome/browser/resources/media/mei_preload:component",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component",
"//third_party/widevine/cdm",
]
if (is_linux) {
sources += [
"app/chrome_main_linux.cc",
"app/chrome_main_linux.h",
]
}
}
if (is_win) {
shared_library("chrome_dll") {
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
defines = []
sources = [
"//base/win/[Link]",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
output_name = "chrome"
deps = [
":chrome_dll_manifest",
":chrome_dll_version",
":dependencies",
"//chrome/app:chrome_dll_resources",
"//chrome/app:command_ids",
"//chrome/app/theme:chrome_unscaled_resources",
"//chrome/chrome_elf",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//crypto",
"//headless:headless_non_renderer",
"//headless:headless_shell_browser_lib",
"//net:net_resources",
"//ppapi/buildflags",
"//sandbox/win:sandbox",
"//third_party/cld_3/src/src:cld_3",
"//third_party/wtl",
"//ui/views",
]
configs += [ "//build/config/win:delayloads" ]
if (use_aura) {
deps += [ "//ui/compositor" ]
}
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
copy("copy_first_run") {
sources = [ "app/FirstRun" ]
outputs = [ "$root_out_dir/First Run" ]
}
} else if (is_mac) {
chrome_helper_name = chrome_product_full_name + " Helper"
chrome_framework_name = chrome_product_full_name + " Framework"
chrome_framework_version = chrome_version_full
group("chrome") {
deps = [ ":chrome_app" ]
data_deps = [ ":chrome_app" ]
if (verify_dynamic_libraries) {
deps += [ ":verify_libraries_chrome_app" ]
}
if (is_chrome_branded && is_official_build) {
deps += [
":chrome_dsym_archive",
":chrome_dump_syms",
]
}
}
tweak_info_plist("chrome_app_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--scm=1",
"--bundle_id=$chrome_mac_bundle_id",
]
if (enable_updater) {
args += [ "--privileged_helper_id=$privileged_helper_name" ]
if (is_chrome_branded) {
args += [ "--keystone=1" ]
if (current_cpu == "arm64") {
args += [ "--keystone-base-tag=arm64" ]
}
} else {
args += [ "--keystone=0" ]
}
} else {
args += [ "--keystone=0" ]
}
}
mac_app_bundle("chrome_app") {
output_name = chrome_product_full_name
info_plist_target = ":chrome_app_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_CREATOR=$chrome_mac_creator_code",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
":chrome_app_strings_bundle_data",
":chrome_resources",
":chrome_versioned_bundle_data",
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:buildflags",
"//chrome/common:version_header",
]
if (enable_updater) {
deps += [ ":chromium_updater_privileged_helper" ]
}
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags = [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link" ]
ldflags = [ "-Wl,-rpath,@executable_path/../Frameworks" ]
# The Framework is packaged inside the .app bundle. But when using the
# component build, all the dependent shared libraries of :chrome_dll are
# not packaged within the framework. This data_deps line makes all of
# those dependent libraries runtime dependencies of the .app bundle.
# This is a bit of a hack, since GN deliberately terminates its search
# for runtime_deps at create_bundle nodes ([Link]
data_deps = [ ":chrome_framework" ]
}
}
if (verify_dynamic_libraries) {
action("verify_libraries_chrome_app") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [ "${root_out_dir}/${chrome_product_full_name}.app/Contents/MacOS/$
{chrome_product_full_name}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
"--allow",
"/usr/lib/[Link]",
]
deps = [ ":chrome_app" ]
}
}
compiled_action("chrome_app_strings") {
tool = "//chrome/tools/build/mac:infoplist_strings_util"
inputs = []
outputs = []
foreach(locale, platform_pak_locales) {
inputs += [ "$root_gen_dir/chrome/branded_strings_${locale}.pak" ]
}
foreach(locale, locales_as_apple_outputs) {
outputs += [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
}
args =
[
"-b",
"branded_strings",
"-v",
chrome_version_full,
"-g",
rebase_path("$root_gen_dir/chrome", root_build_dir),
"-o",
rebase_path("$target_gen_dir/app_infoplist_strings", root_build_dir),
"-t",
"main",
] + platform_pak_locales
deps = [ "//chrome/app:branded_strings" ]
}
foreach(locale, locales_as_apple_outputs) {
bundle_data("chrome_app_strings_${locale}_bundle_data") {
sources = [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
outputs =
[ "{{bundle_resources_dir}}/$[Link]/{{source_file_part}}" ]
public_deps = [ ":chrome_app_strings" ]
}
}
group("chrome_app_strings_bundle_data") {
public_deps = []
foreach(locale, locales_as_apple_outputs) {
public_deps += [ ":chrome_app_strings_${locale}_bundle_data" ]
}
}
bundle_data("chrome_app_icon") {
sources = [ "app/theme/$branding_path_component/mac/[Link]" ]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
}
bundle_data("chrome_resources") {
sources = [
"$root_out_dir/$chrome_mac_bundle_id.manifest",
"app/theme/$branding_path_component/mac/[Link]",
"browser/ui/cocoa/applescript/[Link]",
]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":chrome_app_icon",
":chrome_app_strings",
"//components/policy:chrome_manifest_bundle",
]
}
bundle_data("chrome_versioned_bundle_data") {
sources = [ "$root_out_dir/$chrome_framework_name.framework" ]
outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
public_deps = [
# Before bundling the versioned app components, delete any existing
# versions.
":clean_up_old_versions",
if (enable_widevine_cdm_host_verification) {
# The :chrome_framework_widevine_signature target copies into the
# :chrome_framework bundle. But because the signing file depends on the
# framework itself, that would cause a cyclical dependency. Instead,
# this dependency directly copies the file into the framework's
# resources directory.
public_deps += [ ":chrome_framework_widevine_signature" ]
}
}
if (enable_updater) {
bundle_data("chromium_updater_privileged_helper") {
sources = [ "$root_out_dir/$privileged_helper_name" ]
outputs = [
"{{bundle_contents_dir}}/Library/LaunchServices/{{source_file_part}}",
]
public_deps = [ "//chrome/updater/mac:privileged_helper" ]
}
}
action("clean_up_old_versions") {
script = "//chrome/tools/build/mac/clean_up_old_versions.py"
_stamp_file = "$root_gen_dir/run_$target_name.stamp"
outputs = [ _stamp_file ]
_versions_dir =
"$root_out_dir/$chrome_product_full_name.app/Contents/Frameworks/$chrome_framework_
[Link]/Versions"
args = [
"--versions-dir",
rebase_path(_versions_dir, root_build_dir),
"--stamp",
rebase_path(_stamp_file, root_build_dir),
"--keep",
chrome_framework_version,
"--keep",
"Current",
]
}
tweak_info_plist("chrome_helper_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=0",
]
}
compile_entitlements("entitlements") {
entitlements_templates = [ "app/[Link]" ]
if (is_chrome_branded && include_branded_entitlements) {
# These entitlements are bound to the official Google Chrome signing
# certificate and will not necessarily work in any other build.
entitlements_templates += [ "app/[Link]" ]
}
output_name = "$target_gen_dir/[Link]"
substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_TEAM_ID=$chrome_mac_team_id",
]
visibility = [ "//chrome/installer/mac:copies" ]
}
template("chrome_helper_app") {
mac_app_bundle(target_name) {
assert(defined(invoker.helper_name_suffix))
assert(defined(invoker.helper_bundle_id_suffix))
if (defined(invoker.info_plist_target)) {
info_plist_target = invoker.info_plist_target
} else {
info_plist_target = ":chrome_helper_plist"
}
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_HELPER_SUFFIX=${invoker.helper_name_suffix}",
"CHROMIUM_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
defines = [ "HELPER_EXECUTABLE" ]
deps = [
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:version_header",
"//sandbox/mac:seatbelt",
]
if (defined([Link])) {
deps += [Link]
}
ldflags = []
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link_nested" ]
ldflags += [
# The helper is in [Link]/Contents/Frameworks/Chromium
[Link]/Versions/X/Helpers/Chromium [Link]/Contents/MacOS
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags += [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
}
}
# Create app for the alert helper manually here as we want to modify the plist
# to set the alert style and add the app icon to its resources.
tweak_info_plist("chrome_helper_app_alerts_plist") {
deps = [ ":chrome_helper_plist" ]
info_plists = get_target_outputs(":chrome_helper_plist") +
[ "app/[Link]" ]
}
chrome_helper_app("chrome_helper_app_${alert_helper_params[0]}") {
helper_name_suffix = alert_helper_params[2]
helper_bundle_id_suffix = alert_helper_params[1]
info_plist_target = ":chrome_helper_app_alerts_plist"
deps = [
":chrome_app_icon",
":chrome_helper_app_alerts_resources",
]
}
if (verify_dynamic_libraries) {
foreach(helper_params, chrome_mac_helpers) {
_helper_target = helper_params[0]
_helper_bundle_id = helper_params[1]
_helper_suffix = helper_params[2]
action("verify_libraries_chrome_helper_app_${_helper_target}") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [
"${root_out_dir}/${chrome_helper_name}${_helper_suffix}.app/Contents/MacOS/$
{chrome_helper_name}${_helper_suffix}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
# Do not --allow more libraries here without consulting with the
# security team (security-dev@[Link]).
"--allow",
"/usr/lib/[Link]",
"--allow",
"/usr/lib/[Link]",
]
deps = [ ":chrome_helper_app_${_helper_target}" ]
}
}
}
bundle_data("chrome_framework_helpers") {
sources = [
"$root_out_dir/app_mode_loader",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/web_app_shortcut_copier",
]
outputs = [ "{{bundle_contents_dir}}/Helpers/{{source_file_part}}" ]
public_deps = [
"//chrome/app_shim:app_mode_loader",
"//chrome/browser/web_applications/os_integration/mac:web_app_shortcut_copier",
"//components/crash/core/app:chrome_crashpad_handler",
]
foreach(helper_params, chrome_mac_helpers) {
sources +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.app" ]
public_deps += [ ":chrome_helper_app_${helper_params[0]}" ]
if (verify_dynamic_libraries) {
public_deps +=
[ ":verify_libraries_chrome_helper_app_${helper_params[0]}" ]
}
}
if (enable_updater) {
if (is_chrome_branded) {
sources += [ "//third_party/updater/chrome_mac_universal_prod/cipd/$
{updater_product_full_name}.app" ]
} else {
sources += [ "$root_out_dir/${updater_product_full_name}.app" ]
public_deps += [
"//chrome/updater/mac:browser_install_script",
"//chrome/updater/mac:updater_bundle",
"//chrome/updater/mac:updater_install_script",
]
}
}
}
bundle_data("chrome_framework_resources") {
sources = [
"//ui/gl/resources/angle-metal/gpu_shader_cache.bin",
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":packed_resources",
"//chrome/app_shim:app_mode_loader_plist_bundle_data",
"//chrome/browser/mac:install",
]
if (icu_use_data_file) {
sources += [ "$root_out_dir/[Link]" ]
public_deps += [ "//third_party/icu:icudata" ]
}
if (v8_use_external_startup_data) {
public_deps += [ "//v8" ]
if (use_v8_context_snapshot) {
sources += [ "$root_out_dir/$v8_context_snapshot_filename" ]
public_deps += [ "//tools/v8_context_snapshot" ]
}
if (!use_v8_context_snapshot || include_both_v8_snapshots) {
sources += [ "$root_out_dir/snapshot_blob.bin" ]
}
}
}
if (enable_nacl) {
bundle_data("chrome_framework_plugins") {
sources = []
outputs =
[ "{{bundle_contents_dir}}/Internet Plug-Ins/{{source_file_part}}" ]
public_deps = []
if (enable_nacl) {
if (current_cpu == "x86") {
sources += [ "$root_out_dir/nacl_irt_x86_32.nexe" ]
} else if (current_cpu == "x64") {
sources += [ "$root_out_dir/nacl_irt_x86_64.nexe" ]
}
public_deps += [ "//ppapi/native_client:irt" ]
}
}
} else {
group("chrome_framework_plugins") {
}
}
if (bundle_widevine_cdm) {
bundle_data("widevine_cdm_library_binaries") {
sources = [ "$root_out_dir/$widevine_cdm_path/[Link]" ]
if (enable_widevine_cdm_host_verification) {
sources +=
[ "$root_out_dir/$widevine_cdm_path/[Link]" ]
}
outputs = [
"{{bundle_contents_dir}}/Libraries/$widevine_cdm_path/{{source_file_part}}" ]
public_deps = [ "//third_party/widevine/cdm" ]
}
bundle_data("widevine_cdm_library_manifest_and_license_files") {
sources = [
"$root_out_dir/WidevineCdm/LICENSE",
"$root_out_dir/WidevineCdm/[Link]",
]
outputs = [
"{{bundle_contents_dir}}/Libraries/WidevineCdm/{{source_file_part}}",
]
public_deps = [ "//third_party/widevine/cdm" ]
}
}
group("widevine_cdm_library") {
if (bundle_widevine_cdm) {
deps = [
":widevine_cdm_library_binaries",
":widevine_cdm_library_manifest_and_license_files",
]
}
}
if (enable_widevine_cdm_host_verification) {
widevine_sign_file("sign_chrome_framework_for_widevine") {
file =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
flags = 1
signature_file = "$root_out_dir/$chrome_framework_name.sig"
deps = [ ":chrome_framework" ]
}
copy("chrome_framework_widevine_signature") {
deps = [ ":sign_chrome_framework_for_widevine" ]
sources = [ "$root_out_dir/$chrome_framework_name.sig" ]
outputs = [
"$root_out_dir/$chrome_framework_name.framework/Resources/{{source_file_part}}" ]
}
}
if (build_with_internal_optimization_guide) {
# Add the optimization guide .dylib in the MODULE_DIR of [Link]
bundle_data("optimization_guide_library") {
sources = [
"$root_out_dir/og_intermediates/liboptimization_guide_internal.dylib",
]
outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ]
public_deps = [
"//components/optimization_guide/core:optimization_guide_internal_library_copy" ]
}
} else {
group("optimization_guide_library") {
}
}
tweak_info_plist("chrome_framework_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=1",
"--branding",
chrome_product_short_name,
]
}
sources = [
"app/chrome_crash_reporter_client.cc",
"app/chrome_crash_reporter_client.h",
"app/chrome_crash_reporter_client_mac.mm",
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/chrome_main_mac.h",
"app/chrome_main_mac.mm",
"app/startup_timestamps.h",
]
deps = [
":dependencies",
"//build:chromeos_buildflags",
"//chrome/app:command_ids",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//headless:headless_shell_lib",
"//third_party/cld_3/src/src:cld_3",
]
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
if (is_component_build) {
frameworks = [ "[Link]" ]
}
ldflags = [ "-ObjC" ]
configs += [
":chrome_dll_symbol_order",
"//build/config/compiler:wexit_time_destructors",
]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
}
mac_framework_bundle("chrome_framework") {
output_name = chrome_framework_name
framework_version = chrome_framework_version
framework_contents = [
"Helpers",
"Libraries",
"Resources",
]
if (is_chrome_branded) {
framework_contents += [ "Default Apps" ]
}
if (enable_nacl) {
framework_contents += [ "Internet Plug-Ins" ]
}
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
info_plist_target = ":chrome_framework_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
]
public_deps = [ ":chrome_dll" ]
bundle_deps = [
":angle_binaries",
":chrome_framework_helpers",
":chrome_framework_plugins",
":chrome_framework_resources",
":optimization_guide_library",
":swiftshader_binaries",
":widevine_cdm_library",
"//chrome/browser/resources/media/mei_preload:component_bundle",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component_bundle",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component_bundle
",
]
if (is_chrome_branded) {
bundle_deps += [ ":preinstalled_apps" ]
}
configs += [ ":chrome_dll_symbol_order" ]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
ldflags = [
"-compatibility_version",
chrome_dylib_version,
"-current_version",
chrome_dylib_version,
]
if (!is_component_build) {
# Specify a sensible install_name for static builds. The library is
# dlopen()ed so this is not used to resolve the module.
ldflags += [
"-Wl,-install_name,@executable_path/../Frameworks/$chrome_framework_name.framework/
Versions/$chrome_framework_version/$chrome_framework_name" ]
} else {
# In the component build, both the :chrome_app and various
# :chrome_helper* targets directly link to the Framework target. Use
# @rpath-based loading so that the dylib ID does not have to be changed
# with install_name_tool.
ldflags += [
"-Wl,-install_name,@rpath/$chrome_framework_name.framework/$chrome_framework_name",
"-Wl,-rpath,@loader_path/../../../../../..",
"-Wl,-reexport_library,libchrome_dll.dylib",
]
data_deps = [ ":chrome_dll" ]
}
}
_framework_binary_path =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
assert(_framework_binary_path != "",
"Ignore configuration-dependent unused variable warning")
# This list must be updated with the two targets' deps list below, and
# the list of _dsyms in :chrome_dsym_archive.
_chrome_symbols_sources = [
"$root_out_dir/$chrome_product_full_name.app/Contents/MacOS/$chrome_product_full_na
me",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.dylib",
_framework_binary_path,
]
if (build_with_internal_optimization_guide) {
_chrome_symbols_sources +=
[ "$root_out_dir/liboptimization_guide_internal.dylib" ]
}
foreach(helper_params, chrome_mac_helpers) {
_chrome_symbols_sources += [ "$root_out_dir/${chrome_helper_name}$
{helper_params[2]}.app/Contents/MacOS/${chrome_helper_name}${helper_params[2]}" ]
}
action_foreach("chrome_dump_syms") {
script = "//build/redirect_stdout.py"
sources = _chrome_symbols_sources
outputs =
[ "$root_out_dir/{{source_file_part}}-$chrome_version_full.breakpad" ]
dump_syms =
"//third_party/breakpad:dump_syms($host_system_allocator_toolchain)"
args = rebase_path(outputs, root_build_dir) + [
rebase_path(get_label_info(dump_syms, "root_out_dir") + "/" +
get_label_info(dump_syms, "name"),
root_build_dir),
"-d",
"-m",
"-g",
rebase_path(
"$root_out_dir/{{source_file_part}}.dSYM/Contents/Resources/DWARF/
{{source_file_part}}",
root_build_dir),
"{{source}}",
]
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
dump_syms,
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
}
action("chrome_dsym_archive") {
script = "//chrome/tools/build/mac/archive_symbols.py"
# These are the dSYMs that will be archived. The sources list must be
# the target outputs that correspond to the dSYMs (since a dSYM is a
# directory it cannot be listed as a source file). The targets that
# generate both the dSYM and binary image are listed in deps.
_dsyms = [
"$root_out_dir/$chrome_framework_name.dSYM",
"$root_out_dir/$chrome_product_full_name.dSYM",
"$root_out_dir/chrome_crashpad_handler.dSYM",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.[Link]",
]
if (build_with_internal_optimization_guide) {
_dsyms += [ "$root_out_dir/liboptimization_guide_internal.[Link]" ]
}
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
_dsyms +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.dSYM" ]
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
sources = _chrome_symbols_sources
_output = "$root_out_dir/$chrome_product_full_name.[Link].bz2"
outputs = [ _output ]
group("dependencies") {
public_deps = [
"//build:branding_buildflags",
"//build:chromeos_buildflags",
"//chrome/browser",
"//chrome/browser:buildflags",
"//chrome/browser:shell_integration",
"//chrome/browser/policy:path_parser",
"//chrome/child",
"//chrome/common",
"//chrome/gpu",
"//chrome/renderer",
"//chrome/utility",
"//components/crash/core/app",
"//components/devtools/devtools_pipe",
"//components/memory_system",
"//components/startup_metric_utils",
"//components/sync",
"//components/upload_list:upload_list",
"//components/webui/about",
"//content/public/child",
"//pdf",
"//services/tracing/public/cpp",
"//third_party/blink/public:blink_devtools_frontend_resources",
"//third_party/blink/public:blink_devtools_inspector_resources",
"//v8:v8_headers",
]
if (enable_ppapi) {
public_deps += [ "//ppapi/host" ]
}
if (enable_printing) {
public_deps += [ "//printing" ]
}
if (enable_nacl) {
public_deps += [
"//components/nacl/browser",
"//components/nacl/renderer/plugin:nacl_trusted_plugin",
]
}
if (is_chromeos) {
public_deps += [
"//ash/constants",
"//chrome/browser/ash/boot_times_recorder",
"//chrome/browser/ash/dbus",
"//chrome/browser/ash/schedqos",
"//chromeos/ash/components/memory",
"//chromeos/dbus/constants",
]
}
}
if (is_win) {
process_version_rc_template("chrome_exe_version") {
sources = [ "app/chrome_exe.ver" ]
output = "$target_gen_dir/chrome_exe_version.rc"
}
process_version_rc_template("chrome_dll_version") {
sources = [ "app/chrome_dll.ver" ]
output = "$target_gen_dir/chrome_dll_version.rc"
}
# This manifest matches what GYP produced. It may not even be necessary.
windows_manifest("chrome_dll_manifest") {
sources = [
as_invoker_manifest,
common_controls_manifest,
]
}
process_version_rc_template("other_version") {
sources = [ "app/[Link]" ]
output = "$target_gen_dir/other_version.rc"
}
}
copy("visual_elements_resources") {
sources = [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"app/visual_elements_resources/[Link]",
]
if (is_chrome_branded) {
sources += [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
group("resources") {
public_deps = [
"//chrome/browser:resources",
"//chrome/common:resources",
"//chrome/renderer:resources",
]
}
group("extra_resources") {
# Deps should be same as those in chrome_extra_paks() within chrome_paks.gni.
public_deps = [
"//chrome/browser/resources:resources",
"//components/autofill/core/browser:autofill_address_rewriter_resources",
]
}
target(_preinstalled_apps_target_type, "preinstalled_apps") {
visibility = [ ":packed_resources" ]
if (is_mac) {
visibility += [
":chrome_framework",
":chrome_framework_shared_library",
]
}
sources = [ "browser/resources/default_apps/external_extensions.json" ]
if (!is_mac) {
outputs = [ "$root_out_dir/default_apps/{{source_file_part}}" ]
} else {
outputs = [ "{{bundle_contents_dir}}/Default Apps/{{source_file_part}}" ]
}
# Force anybody that depends on this to get the default apps as data files.
data = process_file_template(sources, outputs)
}
}
if (!is_android) {
chrome_paks("packed_resources") {
if (is_mac) {
output_dir = "$root_gen_dir/repack"
copy_data_to_bundle = true
} else {
output_dir = root_out_dir
mark_as_data = true
}
if (enable_resource_allowlist_generation) {
repack_allowlist = _chrome_resource_allowlist
deps = [ ":resource_allowlist" ]
}
if (is_chrome_branded && !is_mac) {
public_deps = [ ":preinstalled_apps" ]
}
repack("browser_tests_pak") {
testonly = true
sources = [ "$root_gen_dir/chrome/webui_test_resources.pak" ]
output = "$root_out_dir/browser_tests.pak"
deps = [ "//chrome/test/data/webui:resources" ]
}
group("strings") {
public_deps = [
"//chrome/app:branded_strings",
"//chrome/app:generated_resources",
"//chrome/app/resources:locale_settings",
]
}
if (is_android) {
java_cpp_enum("offline_pages_enum_javagen") {
sources = [ "browser/offline_pages/offline_page_utils.h" ]
}
java_cpp_enum("download_enum_javagen") {
sources = [
"browser/download/android/download_open_source.h",
"browser/download/download_dialog_types.h",
"browser/download/download_prompt_status.h",
]
}
source_set("chrome_android_core") {
sources = [
"app/android/chrome_jni_onload.cc",
"app/android/chrome_jni_onload.h",
"app/android/chrome_main_delegate_android.cc",
"app/android/chrome_main_delegate_android.h",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
libs = [
"android",
"jnigraphics",
]
public_deps = [
"//chrome/browser",
"//chrome/utility",
]
deps = [
":dependencies",
"//chrome/browser/flags:flags_android",
"//chrome/browser/ui",
"//chrome/child",
"//chrome/common",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/gpu",
"//chrome/renderer",
"//components/crash/android:crash_android",
"//components/minidump_uploader",
"//components/safe_browsing:buildflags",
"//components/safe_browsing/android:safe_browsing_api_handler",
"//components/safe_browsing/android:safe_browsing_mobile",
"//components/stylus_handwriting/android",
"//components/variations:variations_associated_data",
"//content/public/app",
]
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
}
if (is_linux || is_chromeos) {
if (!(is_debug && use_debug_fission)) {
group("linux_symbols") {
deps = [
":angle_egl_symbols",
":angle_gles_symbols",
":chrome_crashpad_symbols",
":chrome_symbols",
]
if (is_linux) {
deps += [ ":swiftshader_vk_symbols" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
deps += [ ":angle_libvulkan_symbols" ]
}
if (build_with_internal_optimization_guide) {
deps += [ ":optimization_guide_symbols" ]
}
}
extract_symbols("chrome_symbols") {
binary = "$root_out_dir/chrome"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ ":chrome" ]
}
extract_symbols("chrome_crashpad_symbols") {
binary = "$root_out_dir/chrome_crashpad_handler"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ "//components/crash/core/app:chrome_crashpad_handler" ]
}
extract_symbols("swiftshader_vk_symbols") {
binary = "$root_out_dir/libvk_swiftshader.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.$current_cpu"
}
deps = [ "//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan" ]
}
extract_symbols("angle_egl_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libegl.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libegl.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libEGL" ]
}
extract_symbols("angle_gles_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libgles.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libgles.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libGLESv2" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
extract_symbols("angle_libvulkan_symbols") {
binary = "$root_out_dir/[Link].1"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.$current_cpu"
}
deps = [ "//third_party/vulkan-loader/src:libvulkan" ]
}
}
if (build_with_internal_optimization_guide) {
extract_symbols("optimization_guide_symbols") {
binary = "$root_out_dir/liboptimization_guide_internal.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.ia32"
} else {
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.$current_cpu"
}
deps = [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
}
}
# Copies some scripts and resources that are used for desktop integration.
copy("xdg_mime") {
sources = [
"//chrome/tools/build/linux/chrome-wrapper",
"//third_party/xdg-utils/scripts/xdg-mime",
"//third_party/xdg-utils/scripts/xdg-settings",
]
if (is_linux) {
sources += [
"//chrome/app/theme/$branding_path_component/linux/product_logo_48.png",
]
} else {
sources +=
[ "//chrome/app/theme/$branding_path_component/product_logo_48.png" ]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
}
if (_cros_generate_embed_section_target) {
embed_sections("section_embedded_chrome_binary") {
binary_input = "$root_out_dir/chrome"
sections_embedded_binary_output = "$root_out_dir/chrome.sections_embedded"
deps = [ ":chrome" ]
}
}
mport("//build/config/chrome_build.gni")
import("//build/config/chromeos/[Link]")
import("//build/config/chromeos/ui_mode.gni")
import("//build/config/compiler/[Link]")
import("//build/config/compiler/pgo/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/sanitizers/[Link]")
import("//build/config/[Link]")
import("//build/config/win/console_app.gni")
import("//build/config/win/[Link]")
import("//build/private_code_test/private_code_test.gni")
import("//build/toolchain/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/chrome_paks.gni")
import("//chrome/common/[Link]")
import("//chrome/process_version_rc_template.gni")
import("//components/nacl/[Link]")
import("//components/optimization_guide/[Link]")
import("//extensions/buildflags/[Link]")
import("//media/media_options.gni")
import("//ppapi/buildflags/[Link]")
import("//third_party/angle/gni/[Link]")
import("//third_party/blink/public/public_features.gni")
import("//third_party/widevine/cdm/[Link]")
import("//tools/resources/generate_resource_allowlist.gni")
import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
import("//ui/gl/[Link]")
import("//v8/gni/[Link]")
if (is_android) {
import("//build/config/android/[Link]")
} else if (is_linux || is_chromeos) {
import("//build/linux/extract_symbols.gni")
import("//build/linux/strip_binary.gni")
} else if (is_mac) {
import("//build/apple/compile_entitlements.gni")
import("//build/apple/compile_plist.gni")
import("//build/apple/tweak_info_plist.gni")
import("//build/compiled_action.gni")
import("//build/config/apple/[Link]")
import("//build/config/mac/mac_sdk.gni")
import("//build/config/mac/[Link]")
import("//build/util/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/updater/[Link]")
import("//chrome/[Link]")
import("//content/public/app/mac_helpers.gni")
import("//media/cdm/library_cdm/cdm_paths.gni")
import("//services/on_device_model/on_device_model.gni")
import("//third_party/icu/[Link]")
}
if (_cros_generate_embed_section_target) {
import("//build/chromeos/embed_sections.gni")
}
declare_args() {
# On macOS, `is_chrome_branded` builds that have been signed locally will not
# launch because certain entitlements are tied to the official Google code
# signing identity. If `include_branded_entitlements` is set to false, these
# entitlements will be skipped.
include_branded_entitlements = true
}
if (is_win) {
action("reorder_imports") {
script = "//build/win/[Link]"
# initialexe/ is used so that the we can reorder imports and write back to
# the final destination at $root_out_dir/.
inputs = [
"$root_out_dir/initialexe/[Link]",
"$root_out_dir/initialexe/[Link]",
]
outputs = [
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
]
args = [
"-i",
rebase_path("$root_out_dir/initialexe", root_build_dir),
"-o",
rebase_path("$root_out_dir", root_build_dir),
"-a",
current_cpu,
]
deps = [ ":chrome_initial" ]
}
}
if (is_android) {
deps += [ "//chrome/android:chrome_public_apk" ]
} else {
deps += [ ":chrome" ]
}
if (is_win) {
deps += [ ":chrome_dll" ]
}
# This should not pull in installer strings. This is will bloat the binary
# for no reason and is easy to mess up. See the comment at the top of
# //chrome/installer/util/[Link].
assert_no_deps = [ "//chrome/installer/util:strings" ]
}
if (is_win) {
_chrome_output_name = "initialexe/chrome"
} else {
_chrome_output_name = "chrome"
}
executable("chrome_initial") {
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
output_name = _chrome_output_name
if (is_chromeos) {
data_deps += [
"//components/variations/cros_evaluate_seed:evaluate_seed",
"//sandbox/linux:chrome_sandbox",
]
if (build_mojo_proxy) {
data_deps += [ "//mojo/proxy:mojo_proxy" ]
}
deps += [
"//components/exo/wayland:test_controller_stub",
"//components/exo/wayland:ui_controls_protocol_stub",
]
}
if (is_win) {
sources += [
"app/chrome_exe.rc",
"app/chrome_exe_main_win.cc",
"app/delay_load_failure_hook_win.cc",
"app/delay_load_failure_hook_win.h",
"app/main_dll_loader_win.cc",
"app/main_dll_loader_win.h",
"common/crash_keys.cc",
"common/crash_keys.h",
]
deps += [
":chrome_dll",
":chrome_exe_version",
":copy_first_run",
":packed_resources_integrity_header",
":visual_elements_resources",
"//base",
"//build:branding_buildflags",
"//chrome/app:chrome_exe_main_exports",
"//chrome/app:exit_code_watcher",
"//chrome/app/version_assembly:chrome_exe_manifest",
"//chrome/browser:active_use_util",
"//chrome/browser:chrome_process_finder",
"//chrome/browser/policy:path_parser",
"//chrome/chrome_elf",
"//chrome/common:constants",
"//chrome/common/win:delay_load_failure_support",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//chrome/installer/util:constants",
"//chrome/installer/util:did_run_support",
"//components/crash/core/app",
"//components/crash/core/app:run_as_crashpad_handler",
"//components/crash/core/common",
"//components/crash/win:chrome_wer",
"//components/webui/flags:switches",
"//content:sandbox_helper_win",
"//content/public/common:static_switches",
"//crypto",
"//gpu/command_buffer/service",
"//sandbox",
"//sandbox/policy",
"//sandbox/policy/mojom",
"//third_party/breakpad:breakpad_handler",
"//third_party/breakpad:breakpad_sender",
"//third_party/crashpad/crashpad/util",
"//ui/gl",
]
data_deps = [
"//chrome/app/version_assembly:version_assembly_manifest",
"//chrome/browser/web_applications/chrome_pwa_launcher",
"//chrome/chrome_proxy",
"//chrome/elevation_service",
"//chrome/notification_helper",
"//chrome/windows_services/elevated_tracing_service",
]
if (enable_platform_experience) {
data_deps +=
[ "//chrome/browser/platform_experience/win:os_update_handler" ]
}
defines += [ "CHROME_EXE_MAIN" ]
if (win_console_app) {
defines += [ "WIN_CONSOLE_APP" ]
} else {
# Set /SUBSYSTEM:WINDOWS for [Link] itself, unless a console build
# has been requested.
configs -= [ "//build/config/win:console" ]
configs += [ "//build/config/win:windowed" ]
}
configs += [
"//build/config/win:delayloads",
"//build/config/win:delayloads_not_for_child_dll",
]
if (current_cpu == "x86") {
# Set the initial stack size to 0.5MiB, instead of the 1.5MiB needed by
# Chrome's main thread. This saves significant memory on threads (like
# those in the Windows thread pool, and others) whose stack size we can
# only control through this setting. Because Chrome's main thread needs
# a minimum 1.5 MiB stack, the main thread (in 32-bit builds only) uses
# fibers to switch to a 1.5 MiB stack before running any other code.
ldflags = [ "/STACK:0x80000" ]
} else {
# Increase the initial stack size. The default is 1MB, this is 8MB.
ldflags = [ "/STACK:0x800000" ]
}
} else if (use_aura) {
# Non-Windows aura entrypoint.
sources += [ "app/chrome_exe_main_aura.cc" ]
}
if (is_linux || is_chromeos) {
sources += [
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
deps += [
# On Linux, link the dependencies (libraries) that make up actual
# Chromium functionality directly into the executable.
":dependencies",
"//chrome/common:version_header",
public_deps = [
":xdg_mime", # Needs to be public for installer to consume files.
"//chrome/common:buildflags",
]
data_deps += [ "//components/crash/core/app:chrome_crashpad_handler" ]
ldflags = []
# Chrome OS debug builds for arm need to pass --long-plt to the linker.
# See [Link]
if (is_chromeos && is_debug && target_cpu == "arm") {
ldflags += [ "-Wl,--long-plt" ]
}
if (is_linux && !is_component_build && !using_sanitizer) {
version_script = "//build/linux/[Link]"
inputs = [ version_script ]
ldflags += [ "-Wl,--version-script=" +
rebase_path(version_script, root_build_dir) ]
}
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [
"//chrome/browser/ash/locale",
"//chrome/browser/ash/schedqos",
]
}
if (use_ozone) {
deps += [ "//ui/ozone" ]
if (is_linux) {
deps += [ "//ui/linux:display_server_utils" ]
}
}
}
data_deps += [
"//chrome/browser/resources/media/mei_preload:component",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component",
"//third_party/widevine/cdm",
]
if (is_linux) {
sources += [
"app/chrome_main_linux.cc",
"app/chrome_main_linux.h",
]
}
}
if (is_win) {
shared_library("chrome_dll") {
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
defines = []
sources = [
"//base/win/[Link]",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
output_name = "chrome"
deps = [
":chrome_dll_manifest",
":chrome_dll_version",
":dependencies",
"//chrome/app:chrome_dll_resources",
"//chrome/app:command_ids",
"//chrome/app/theme:chrome_unscaled_resources",
"//chrome/chrome_elf",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//crypto",
"//headless:headless_non_renderer",
"//headless:headless_shell_browser_lib",
"//net:net_resources",
"//ppapi/buildflags",
"//sandbox/win:sandbox",
"//third_party/cld_3/src/src:cld_3",
"//third_party/wtl",
"//ui/views",
]
configs += [ "//build/config/win:delayloads" ]
if (use_aura) {
deps += [ "//ui/compositor" ]
}
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
copy("copy_first_run") {
sources = [ "app/FirstRun" ]
outputs = [ "$root_out_dir/First Run" ]
}
} else if (is_mac) {
chrome_helper_name = chrome_product_full_name + " Helper"
chrome_framework_name = chrome_product_full_name + " Framework"
chrome_framework_version = chrome_version_full
group("chrome") {
deps = [ ":chrome_app" ]
data_deps = [ ":chrome_app" ]
if (verify_dynamic_libraries) {
deps += [ ":verify_libraries_chrome_app" ]
}
tweak_info_plist("chrome_app_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--scm=1",
"--bundle_id=$chrome_mac_bundle_id",
]
if (enable_updater) {
args += [ "--privileged_helper_id=$privileged_helper_name" ]
if (is_chrome_branded) {
args += [ "--keystone=1" ]
if (current_cpu == "arm64") {
args += [ "--keystone-base-tag=arm64" ]
}
} else {
args += [ "--keystone=0" ]
}
} else {
args += [ "--keystone=0" ]
}
}
mac_app_bundle("chrome_app") {
output_name = chrome_product_full_name
info_plist_target = ":chrome_app_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_CREATOR=$chrome_mac_creator_code",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
":chrome_app_strings_bundle_data",
":chrome_resources",
":chrome_versioned_bundle_data",
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:buildflags",
"//chrome/common:version_header",
]
if (enable_updater) {
deps += [ ":chromium_updater_privileged_helper" ]
}
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags = [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link" ]
ldflags = [ "-Wl,-rpath,@executable_path/../Frameworks" ]
# The Framework is packaged inside the .app bundle. But when using the
# component build, all the dependent shared libraries of :chrome_dll are
# not packaged within the framework. This data_deps line makes all of
# those dependent libraries runtime dependencies of the .app bundle.
# This is a bit of a hack, since GN deliberately terminates its search
# for runtime_deps at create_bundle nodes ([Link]
data_deps = [ ":chrome_framework" ]
}
}
if (verify_dynamic_libraries) {
action("verify_libraries_chrome_app") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [ "${root_out_dir}/${chrome_product_full_name}.app/Contents/MacOS/$
{chrome_product_full_name}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
"--allow",
"/usr/lib/[Link]",
]
deps = [ ":chrome_app" ]
}
}
compiled_action("chrome_app_strings") {
tool = "//chrome/tools/build/mac:infoplist_strings_util"
inputs = []
outputs = []
foreach(locale, platform_pak_locales) {
inputs += [ "$root_gen_dir/chrome/branded_strings_${locale}.pak" ]
}
foreach(locale, locales_as_apple_outputs) {
outputs += [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
}
args =
[
"-b",
"branded_strings",
"-v",
chrome_version_full,
"-g",
rebase_path("$root_gen_dir/chrome", root_build_dir),
"-o",
rebase_path("$target_gen_dir/app_infoplist_strings", root_build_dir),
"-t",
"main",
] + platform_pak_locales
deps = [ "//chrome/app:branded_strings" ]
}
foreach(locale, locales_as_apple_outputs) {
bundle_data("chrome_app_strings_${locale}_bundle_data") {
sources = [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
outputs =
[ "{{bundle_resources_dir}}/$[Link]/{{source_file_part}}" ]
public_deps = [ ":chrome_app_strings" ]
}
}
group("chrome_app_strings_bundle_data") {
public_deps = []
foreach(locale, locales_as_apple_outputs) {
public_deps += [ ":chrome_app_strings_${locale}_bundle_data" ]
}
}
bundle_data("chrome_app_icon") {
sources = [ "app/theme/$branding_path_component/mac/[Link]" ]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
}
bundle_data("chrome_resources") {
sources = [
"$root_out_dir/$chrome_mac_bundle_id.manifest",
"app/theme/$branding_path_component/mac/[Link]",
"browser/ui/cocoa/applescript/[Link]",
]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":chrome_app_icon",
":chrome_app_strings",
"//components/policy:chrome_manifest_bundle",
]
}
bundle_data("chrome_versioned_bundle_data") {
sources = [ "$root_out_dir/$chrome_framework_name.framework" ]
outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
public_deps = [
# Before bundling the versioned app components, delete any existing
# versions.
":clean_up_old_versions",
if (enable_widevine_cdm_host_verification) {
# The :chrome_framework_widevine_signature target copies into the
# :chrome_framework bundle. But because the signing file depends on the
# framework itself, that would cause a cyclical dependency. Instead,
# this dependency directly copies the file into the framework's
# resources directory.
public_deps += [ ":chrome_framework_widevine_signature" ]
}
}
if (enable_updater) {
bundle_data("chromium_updater_privileged_helper") {
sources = [ "$root_out_dir/$privileged_helper_name" ]
outputs = [
"{{bundle_contents_dir}}/Library/LaunchServices/{{source_file_part}}",
]
public_deps = [ "//chrome/updater/mac:privileged_helper" ]
}
}
action("clean_up_old_versions") {
script = "//chrome/tools/build/mac/clean_up_old_versions.py"
_stamp_file = "$root_gen_dir/run_$target_name.stamp"
outputs = [ _stamp_file ]
_versions_dir =
"$root_out_dir/$chrome_product_full_name.app/Contents/Frameworks/$chrome_framework_
[Link]/Versions"
args = [
"--versions-dir",
rebase_path(_versions_dir, root_build_dir),
"--stamp",
rebase_path(_stamp_file, root_build_dir),
"--keep",
chrome_framework_version,
"--keep",
"Current",
]
}
tweak_info_plist("chrome_helper_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=0",
]
}
compile_entitlements("entitlements") {
entitlements_templates = [ "app/[Link]" ]
if (is_chrome_branded && include_branded_entitlements) {
# These entitlements are bound to the official Google Chrome signing
# certificate and will not necessarily work in any other build.
entitlements_templates += [ "app/[Link]" ]
}
output_name = "$target_gen_dir/[Link]"
substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_TEAM_ID=$chrome_mac_team_id",
]
visibility = [ "//chrome/installer/mac:copies" ]
}
template("chrome_helper_app") {
mac_app_bundle(target_name) {
assert(defined(invoker.helper_name_suffix))
assert(defined(invoker.helper_bundle_id_suffix))
if (defined(invoker.info_plist_target)) {
info_plist_target = invoker.info_plist_target
} else {
info_plist_target = ":chrome_helper_plist"
}
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_HELPER_SUFFIX=${invoker.helper_name_suffix}",
"CHROMIUM_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
defines = [ "HELPER_EXECUTABLE" ]
deps = [
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:version_header",
"//sandbox/mac:seatbelt",
]
if (defined([Link])) {
deps += [Link]
}
ldflags = []
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link_nested" ]
ldflags += [
# The helper is in [Link]/Contents/Frameworks/Chromium
[Link]/Versions/X/Helpers/Chromium [Link]/Contents/MacOS
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags += [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
}
}
# Create app for the alert helper manually here as we want to modify the plist
# to set the alert style and add the app icon to its resources.
tweak_info_plist("chrome_helper_app_alerts_plist") {
deps = [ ":chrome_helper_plist" ]
info_plists = get_target_outputs(":chrome_helper_plist") +
[ "app/[Link]" ]
}
chrome_helper_app("chrome_helper_app_${alert_helper_params[0]}") {
helper_name_suffix = alert_helper_params[2]
helper_bundle_id_suffix = alert_helper_params[1]
info_plist_target = ":chrome_helper_app_alerts_plist"
deps = [
":chrome_app_icon",
":chrome_helper_app_alerts_resources",
]
}
if (verify_dynamic_libraries) {
foreach(helper_params, chrome_mac_helpers) {
_helper_target = helper_params[0]
_helper_bundle_id = helper_params[1]
_helper_suffix = helper_params[2]
action("verify_libraries_chrome_helper_app_${_helper_target}") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [
"${root_out_dir}/${chrome_helper_name}${_helper_suffix}.app/Contents/MacOS/$
{chrome_helper_name}${_helper_suffix}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
bundle_data("chrome_framework_helpers") {
sources = [
"$root_out_dir/app_mode_loader",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/web_app_shortcut_copier",
]
outputs = [ "{{bundle_contents_dir}}/Helpers/{{source_file_part}}" ]
public_deps = [
"//chrome/app_shim:app_mode_loader",
"//chrome/browser/web_applications/os_integration/mac:web_app_shortcut_copier",
"//components/crash/core/app:chrome_crashpad_handler",
]
foreach(helper_params, chrome_mac_helpers) {
sources +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.app" ]
public_deps += [ ":chrome_helper_app_${helper_params[0]}" ]
if (verify_dynamic_libraries) {
public_deps +=
[ ":verify_libraries_chrome_helper_app_${helper_params[0]}" ]
}
}
if (enable_updater) {
if (is_chrome_branded) {
sources += [ "//third_party/updater/chrome_mac_universal_prod/cipd/$
{updater_product_full_name}.app" ]
} else {
sources += [ "$root_out_dir/${updater_product_full_name}.app" ]
public_deps += [
"//chrome/updater/mac:browser_install_script",
"//chrome/updater/mac:updater_bundle",
"//chrome/updater/mac:updater_install_script",
]
}
}
}
bundle_data("chrome_framework_resources") {
sources = [
"//ui/gl/resources/angle-metal/gpu_shader_cache.bin",
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":packed_resources",
"//chrome/app_shim:app_mode_loader_plist_bundle_data",
"//chrome/browser/mac:install",
]
if (icu_use_data_file) {
sources += [ "$root_out_dir/[Link]" ]
public_deps += [ "//third_party/icu:icudata" ]
}
if (v8_use_external_startup_data) {
public_deps += [ "//v8" ]
if (use_v8_context_snapshot) {
sources += [ "$root_out_dir/$v8_context_snapshot_filename" ]
public_deps += [ "//tools/v8_context_snapshot" ]
}
if (!use_v8_context_snapshot || include_both_v8_snapshots) {
sources += [ "$root_out_dir/snapshot_blob.bin" ]
}
}
}
if (enable_nacl) {
bundle_data("chrome_framework_plugins") {
sources = []
outputs =
[ "{{bundle_contents_dir}}/Internet Plug-Ins/{{source_file_part}}" ]
public_deps = []
if (enable_nacl) {
if (current_cpu == "x86") {
sources += [ "$root_out_dir/nacl_irt_x86_32.nexe" ]
} else if (current_cpu == "x64") {
sources += [ "$root_out_dir/nacl_irt_x86_64.nexe" ]
}
public_deps += [ "//ppapi/native_client:irt" ]
}
}
} else {
group("chrome_framework_plugins") {
}
}
if (bundle_widevine_cdm) {
bundle_data("widevine_cdm_library_binaries") {
sources = [ "$root_out_dir/$widevine_cdm_path/[Link]" ]
if (enable_widevine_cdm_host_verification) {
sources +=
[ "$root_out_dir/$widevine_cdm_path/[Link]" ]
}
outputs = [
"{{bundle_contents_dir}}/Libraries/$widevine_cdm_path/{{source_file_part}}" ]
public_deps = [ "//third_party/widevine/cdm" ]
}
bundle_data("widevine_cdm_library_manifest_and_license_files") {
sources = [
"$root_out_dir/WidevineCdm/LICENSE",
"$root_out_dir/WidevineCdm/[Link]",
]
outputs = [
"{{bundle_contents_dir}}/Libraries/WidevineCdm/{{source_file_part}}",
]
public_deps = [ "//third_party/widevine/cdm" ]
}
}
group("widevine_cdm_library") {
if (bundle_widevine_cdm) {
deps = [
":widevine_cdm_library_binaries",
":widevine_cdm_library_manifest_and_license_files",
]
}
}
if (enable_widevine_cdm_host_verification) {
widevine_sign_file("sign_chrome_framework_for_widevine") {
file =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
flags = 1
signature_file = "$root_out_dir/$chrome_framework_name.sig"
deps = [ ":chrome_framework" ]
}
copy("chrome_framework_widevine_signature") {
deps = [ ":sign_chrome_framework_for_widevine" ]
sources = [ "$root_out_dir/$chrome_framework_name.sig" ]
outputs = [
"$root_out_dir/$chrome_framework_name.framework/Resources/{{source_file_part}}" ]
}
}
if (build_with_internal_optimization_guide) {
# Add the optimization guide .dylib in the MODULE_DIR of [Link]
bundle_data("optimization_guide_library") {
sources = [
"$root_out_dir/og_intermediates/liboptimization_guide_internal.dylib",
]
outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ]
public_deps = [
"//components/optimization_guide/core:optimization_guide_internal_library_copy" ]
}
} else {
group("optimization_guide_library") {
}
}
tweak_info_plist("chrome_framework_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=1",
"--branding",
chrome_product_short_name,
]
}
sources = [
"app/chrome_crash_reporter_client.cc",
"app/chrome_crash_reporter_client.h",
"app/chrome_crash_reporter_client_mac.mm",
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/chrome_main_mac.h",
"app/chrome_main_mac.mm",
"app/startup_timestamps.h",
]
deps = [
":dependencies",
"//build:chromeos_buildflags",
"//chrome/app:command_ids",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//headless:headless_shell_lib",
"//third_party/cld_3/src/src:cld_3",
]
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
if (is_component_build) {
frameworks = [ "[Link]" ]
}
ldflags = [ "-ObjC" ]
configs += [
":chrome_dll_symbol_order",
"//build/config/compiler:wexit_time_destructors",
]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
}
mac_framework_bundle("chrome_framework") {
output_name = chrome_framework_name
framework_version = chrome_framework_version
framework_contents = [
"Helpers",
"Libraries",
"Resources",
]
if (is_chrome_branded) {
framework_contents += [ "Default Apps" ]
}
if (enable_nacl) {
framework_contents += [ "Internet Plug-Ins" ]
}
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
info_plist_target = ":chrome_framework_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
]
public_deps = [ ":chrome_dll" ]
bundle_deps = [
":angle_binaries",
":chrome_framework_helpers",
":chrome_framework_plugins",
":chrome_framework_resources",
":optimization_guide_library",
":swiftshader_binaries",
":widevine_cdm_library",
"//chrome/browser/resources/media/mei_preload:component_bundle",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component_bundle",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component_bundle
",
]
if (is_chrome_branded) {
bundle_deps += [ ":preinstalled_apps" ]
}
configs += [ ":chrome_dll_symbol_order" ]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
ldflags = [
"-compatibility_version",
chrome_dylib_version,
"-current_version",
chrome_dylib_version,
]
if (!is_component_build) {
# Specify a sensible install_name for static builds. The library is
# dlopen()ed so this is not used to resolve the module.
ldflags += [
"-Wl,-install_name,@executable_path/../Frameworks/$chrome_framework_name.framework/
Versions/$chrome_framework_version/$chrome_framework_name" ]
} else {
# In the component build, both the :chrome_app and various
# :chrome_helper* targets directly link to the Framework target. Use
# @rpath-based loading so that the dylib ID does not have to be changed
# with install_name_tool.
ldflags += [
"-Wl,-install_name,@rpath/$chrome_framework_name.framework/$chrome_framework_name",
"-Wl,-rpath,@loader_path/../../../../../..",
"-Wl,-reexport_library,libchrome_dll.dylib",
]
data_deps = [ ":chrome_dll" ]
}
}
_framework_binary_path =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
assert(_framework_binary_path != "",
"Ignore configuration-dependent unused variable warning")
# This list must be updated with the two targets' deps list below, and
# the list of _dsyms in :chrome_dsym_archive.
_chrome_symbols_sources = [
"$root_out_dir/$chrome_product_full_name.app/Contents/MacOS/$chrome_product_full_na
me",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.dylib",
_framework_binary_path,
]
if (build_with_internal_optimization_guide) {
_chrome_symbols_sources +=
[ "$root_out_dir/liboptimization_guide_internal.dylib" ]
}
foreach(helper_params, chrome_mac_helpers) {
_chrome_symbols_sources += [ "$root_out_dir/${chrome_helper_name}$
{helper_params[2]}.app/Contents/MacOS/${chrome_helper_name}${helper_params[2]}" ]
}
action_foreach("chrome_dump_syms") {
script = "//build/redirect_stdout.py"
sources = _chrome_symbols_sources
outputs =
[ "$root_out_dir/{{source_file_part}}-$chrome_version_full.breakpad" ]
dump_syms =
"//third_party/breakpad:dump_syms($host_system_allocator_toolchain)"
args = rebase_path(outputs, root_build_dir) + [
rebase_path(get_label_info(dump_syms, "root_out_dir") + "/" +
get_label_info(dump_syms, "name"),
root_build_dir),
"-d",
"-m",
"-g",
rebase_path(
"$root_out_dir/{{source_file_part}}.dSYM/Contents/Resources/DWARF/
{{source_file_part}}",
root_build_dir),
"{{source}}",
]
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
dump_syms,
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
}
action("chrome_dsym_archive") {
script = "//chrome/tools/build/mac/archive_symbols.py"
# These are the dSYMs that will be archived. The sources list must be
# the target outputs that correspond to the dSYMs (since a dSYM is a
# directory it cannot be listed as a source file). The targets that
# generate both the dSYM and binary image are listed in deps.
_dsyms = [
"$root_out_dir/$chrome_framework_name.dSYM",
"$root_out_dir/$chrome_product_full_name.dSYM",
"$root_out_dir/chrome_crashpad_handler.dSYM",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.[Link]",
]
if (build_with_internal_optimization_guide) {
_dsyms += [ "$root_out_dir/liboptimization_guide_internal.[Link]" ]
}
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
_dsyms +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.dSYM" ]
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
sources = _chrome_symbols_sources
_output = "$root_out_dir/$chrome_product_full_name.[Link].bz2"
outputs = [ _output ]
group("dependencies") {
public_deps = [
"//build:branding_buildflags",
"//build:chromeos_buildflags",
"//chrome/browser",
"//chrome/browser:buildflags",
"//chrome/browser:shell_integration",
"//chrome/browser/policy:path_parser",
"//chrome/child",
"//chrome/common",
"//chrome/gpu",
"//chrome/renderer",
"//chrome/utility",
"//components/crash/core/app",
"//components/devtools/devtools_pipe",
"//components/memory_system",
"//components/startup_metric_utils",
"//components/sync",
"//components/upload_list:upload_list",
"//components/webui/about",
"//content/public/child",
"//pdf",
"//services/tracing/public/cpp",
"//third_party/blink/public:blink_devtools_frontend_resources",
"//third_party/blink/public:blink_devtools_inspector_resources",
"//v8:v8_headers",
]
if (enable_ppapi) {
public_deps += [ "//ppapi/host" ]
}
if (enable_printing) {
public_deps += [ "//printing" ]
}
if (enable_nacl) {
public_deps += [
"//components/nacl/browser",
"//components/nacl/renderer/plugin:nacl_trusted_plugin",
]
}
if (is_chromeos) {
public_deps += [
"//ash/constants",
"//chrome/browser/ash/boot_times_recorder",
"//chrome/browser/ash/dbus",
"//chrome/browser/ash/schedqos",
"//chromeos/ash/components/memory",
"//chromeos/dbus/constants",
]
}
}
if (is_win) {
process_version_rc_template("chrome_exe_version") {
sources = [ "app/chrome_exe.ver" ]
output = "$target_gen_dir/chrome_exe_version.rc"
}
process_version_rc_template("chrome_dll_version") {
sources = [ "app/chrome_dll.ver" ]
output = "$target_gen_dir/chrome_dll_version.rc"
}
# This manifest matches what GYP produced. It may not even be necessary.
windows_manifest("chrome_dll_manifest") {
sources = [
as_invoker_manifest,
common_controls_manifest,
]
}
process_version_rc_template("other_version") {
sources = [ "app/[Link]" ]
output = "$target_gen_dir/other_version.rc"
}
}
copy("visual_elements_resources") {
sources = [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"app/visual_elements_resources/[Link]",
]
if (is_chrome_branded) {
sources += [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
group("resources") {
public_deps = [
"//chrome/browser:resources",
"//chrome/common:resources",
"//chrome/renderer:resources",
]
}
group("extra_resources") {
# Deps should be same as those in chrome_extra_paks() within chrome_paks.gni.
public_deps = [
"//chrome/browser/resources:resources",
"//components/autofill/core/browser:autofill_address_rewriter_resources",
]
}
target(_preinstalled_apps_target_type, "preinstalled_apps") {
visibility = [ ":packed_resources" ]
if (is_mac) {
visibility += [
":chrome_framework",
":chrome_framework_shared_library",
]
}
sources = [ "browser/resources/default_apps/external_extensions.json" ]
if (!is_mac) {
outputs = [ "$root_out_dir/default_apps/{{source_file_part}}" ]
} else {
outputs = [ "{{bundle_contents_dir}}/Default Apps/{{source_file_part}}" ]
}
# Force anybody that depends on this to get the default apps as data files.
data = process_file_template(sources, outputs)
}
}
if (!is_android) {
chrome_paks("packed_resources") {
if (is_mac) {
output_dir = "$root_gen_dir/repack"
copy_data_to_bundle = true
} else {
output_dir = root_out_dir
mark_as_data = true
}
if (enable_resource_allowlist_generation) {
repack_allowlist = _chrome_resource_allowlist
deps = [ ":resource_allowlist" ]
}
repack("browser_tests_pak") {
testonly = true
sources = [ "$root_gen_dir/chrome/webui_test_resources.pak" ]
output = "$root_out_dir/browser_tests.pak"
deps = [ "//chrome/test/data/webui:resources" ]
}
group("strings") {
public_deps = [
"//chrome/app:branded_strings",
"//chrome/app:generated_resources",
"//chrome/app/resources:locale_settings",
]
}
if (is_android) {
java_cpp_enum("offline_pages_enum_javagen") {
sources = [ "browser/offline_pages/offline_page_utils.h" ]
}
java_cpp_enum("download_enum_javagen") {
sources = [
"browser/download/android/download_open_source.h",
"browser/download/download_dialog_types.h",
"browser/download/download_prompt_status.h",
]
}
source_set("chrome_android_core") {
sources = [
"app/android/chrome_jni_onload.cc",
"app/android/chrome_jni_onload.h",
"app/android/chrome_main_delegate_android.cc",
"app/android/chrome_main_delegate_android.h",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
libs = [
"android",
"jnigraphics",
]
public_deps = [
"//chrome/browser",
"//chrome/utility",
]
deps = [
":dependencies",
"//chrome/browser/flags:flags_android",
"//chrome/browser/ui",
"//chrome/child",
"//chrome/common",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/gpu",
"//chrome/renderer",
"//components/crash/android:crash_android",
"//components/minidump_uploader",
"//components/safe_browsing:buildflags",
"//components/safe_browsing/android:safe_browsing_api_handler",
"//components/safe_browsing/android:safe_browsing_mobile",
"//components/stylus_handwriting/android",
"//components/variations:variations_associated_data",
"//content/public/app",
]
# Explicit dependency required for JNI registration to be able to
# find the native side functions.
if (is_component_build) {
deps += [
"//components/viz/service",
"//device/gamepad",
"//ui/events/devices",
]
}
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
}
if (is_linux || is_chromeos) {
if (!(is_debug && use_debug_fission)) {
group("linux_symbols") {
deps = [
":angle_egl_symbols",
":angle_gles_symbols",
":chrome_crashpad_symbols",
":chrome_symbols",
]
if (is_linux) {
deps += [ ":swiftshader_vk_symbols" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
deps += [ ":angle_libvulkan_symbols" ]
}
if (build_with_internal_optimization_guide) {
deps += [ ":optimization_guide_symbols" ]
}
}
extract_symbols("chrome_symbols") {
binary = "$root_out_dir/chrome"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ ":chrome" ]
}
extract_symbols("chrome_crashpad_symbols") {
binary = "$root_out_dir/chrome_crashpad_handler"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ "//components/crash/core/app:chrome_crashpad_handler" ]
}
extract_symbols("swiftshader_vk_symbols") {
binary = "$root_out_dir/libvk_swiftshader.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.$current_cpu"
}
deps = [ "//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan" ]
}
extract_symbols("angle_egl_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libegl.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libegl.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libEGL" ]
}
extract_symbols("angle_gles_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libgles.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libgles.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libGLESv2" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
extract_symbols("angle_libvulkan_symbols") {
binary = "$root_out_dir/[Link].1"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.$current_cpu"
}
deps = [ "//third_party/vulkan-loader/src:libvulkan" ]
}
}
if (build_with_internal_optimization_guide) {
extract_symbols("optimization_guide_symbols") {
binary = "$root_out_dir/liboptimization_guide_internal.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.ia32"
} else {
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.$current_cpu"
}
deps = [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
}
}
# Copies some scripts and resources that are used for desktop integration.
copy("xdg_mime") {
sources = [
"//chrome/tools/build/linux/chrome-wrapper",
"//third_party/xdg-utils/scripts/xdg-mime",
"//third_party/xdg-utils/scripts/xdg-settings",
]
if (is_linux) {
sources += [
"//chrome/app/theme/$branding_path_component/linux/product_logo_48.png",
]
} else {
sources +=
[ "//chrome/app/theme/$branding_path_component/product_logo_48.png" ]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
}
if (_cros_generate_embed_section_target) {
embed_sections("section_embedded_chrome_binary") {
binary_input = "$root_out_dir/chrome"
sections_embedded_binary_output = "$root_out_dir/chrome.sections_embedded"
deps = [ ":chrome" ]
}
}
mport("//build/config/chrome_build.gni")
import("//build/config/chromeos/[Link]")
import("//build/config/chromeos/ui_mode.gni")
import("//build/config/compiler/[Link]")
import("//build/config/compiler/pgo/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/sanitizers/[Link]")
import("//build/config/[Link]")
import("//build/config/win/console_app.gni")
import("//build/config/win/[Link]")
import("//build/private_code_test/private_code_test.gni")
import("//build/toolchain/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/chrome_paks.gni")
import("//chrome/common/[Link]")
import("//chrome/process_version_rc_template.gni")
import("//components/nacl/[Link]")
import("//components/optimization_guide/[Link]")
import("//extensions/buildflags/[Link]")
import("//media/media_options.gni")
import("//ppapi/buildflags/[Link]")
import("//third_party/angle/gni/[Link]")
import("//third_party/blink/public/public_features.gni")
import("//third_party/widevine/cdm/[Link]")
import("//tools/resources/generate_resource_allowlist.gni")
import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
import("//ui/gl/[Link]")
import("//v8/gni/[Link]")
if (is_android) {
import("//build/config/android/[Link]")
} else if (is_linux || is_chromeos) {
import("//build/linux/extract_symbols.gni")
import("//build/linux/strip_binary.gni")
} else if (is_mac) {
import("//build/apple/compile_entitlements.gni")
import("//build/apple/compile_plist.gni")
import("//build/apple/tweak_info_plist.gni")
import("//build/compiled_action.gni")
import("//build/config/apple/[Link]")
import("//build/config/mac/mac_sdk.gni")
import("//build/config/mac/[Link]")
import("//build/util/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/updater/[Link]")
import("//chrome/[Link]")
import("//content/public/app/mac_helpers.gni")
import("//media/cdm/library_cdm/cdm_paths.gni")
import("//services/on_device_model/on_device_model.gni")
import("//third_party/icu/[Link]")
}
if (_cros_generate_embed_section_target) {
import("//build/chromeos/embed_sections.gni")
}
declare_args() {
# On macOS, `is_chrome_branded` builds that have been signed locally will not
# launch because certain entitlements are tied to the official Google code
# signing identity. If `include_branded_entitlements` is set to false, these
# entitlements will be skipped.
include_branded_entitlements = true
}
if (is_win) {
action("reorder_imports") {
script = "//build/win/[Link]"
# initialexe/ is used so that the we can reorder imports and write back to
# the final destination at $root_out_dir/.
inputs = [
"$root_out_dir/initialexe/[Link]",
"$root_out_dir/initialexe/[Link]",
]
outputs = [
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
]
args = [
"-i",
rebase_path("$root_out_dir/initialexe", root_build_dir),
"-o",
rebase_path("$root_out_dir", root_build_dir),
"-a",
current_cpu,
]
deps = [ ":chrome_initial" ]
}
}
if (is_android) {
deps += [ "//chrome/android:chrome_public_apk" ]
} else {
deps += [ ":chrome" ]
}
if (is_win) {
deps += [ ":chrome_dll" ]
}
# This should not pull in installer strings. This is will bloat the binary
# for no reason and is easy to mess up. See the comment at the top of
# //chrome/installer/util/[Link].
assert_no_deps = [ "//chrome/installer/util:strings" ]
}
if (is_win) {
_chrome_output_name = "initialexe/chrome"
} else {
_chrome_output_name = "chrome"
}
executable("chrome_initial") {
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
output_name = _chrome_output_name
if (is_chromeos) {
data_deps += [
"//components/variations/cros_evaluate_seed:evaluate_seed",
"//sandbox/linux:chrome_sandbox",
]
if (build_mojo_proxy) {
data_deps += [ "//mojo/proxy:mojo_proxy" ]
}
deps += [
"//components/exo/wayland:test_controller_stub",
"//components/exo/wayland:ui_controls_protocol_stub",
]
}
if (is_win) {
sources += [
"app/chrome_exe.rc",
"app/chrome_exe_main_win.cc",
"app/delay_load_failure_hook_win.cc",
"app/delay_load_failure_hook_win.h",
"app/main_dll_loader_win.cc",
"app/main_dll_loader_win.h",
"common/crash_keys.cc",
"common/crash_keys.h",
]
deps += [
":chrome_dll",
":chrome_exe_version",
":copy_first_run",
":packed_resources_integrity_header",
":visual_elements_resources",
"//base",
"//build:branding_buildflags",
"//chrome/app:chrome_exe_main_exports",
"//chrome/app:exit_code_watcher",
"//chrome/app/version_assembly:chrome_exe_manifest",
"//chrome/browser:active_use_util",
"//chrome/browser:chrome_process_finder",
"//chrome/browser/policy:path_parser",
"//chrome/chrome_elf",
"//chrome/common:constants",
"//chrome/common/win:delay_load_failure_support",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//chrome/installer/util:constants",
"//chrome/installer/util:did_run_support",
"//components/crash/core/app",
"//components/crash/core/app:run_as_crashpad_handler",
"//components/crash/core/common",
"//components/crash/win:chrome_wer",
"//components/webui/flags:switches",
"//content:sandbox_helper_win",
"//content/public/common:static_switches",
"//crypto",
"//gpu/command_buffer/service",
"//sandbox",
"//sandbox/policy",
"//sandbox/policy/mojom",
"//third_party/breakpad:breakpad_handler",
"//third_party/breakpad:breakpad_sender",
"//third_party/crashpad/crashpad/util",
"//ui/gl",
]
data_deps = [
"//chrome/app/version_assembly:version_assembly_manifest",
"//chrome/browser/web_applications/chrome_pwa_launcher",
"//chrome/chrome_proxy",
"//chrome/elevation_service",
"//chrome/notification_helper",
"//chrome/windows_services/elevated_tracing_service",
]
if (enable_platform_experience) {
data_deps +=
[ "//chrome/browser/platform_experience/win:os_update_handler" ]
}
defines += [ "CHROME_EXE_MAIN" ]
if (win_console_app) {
defines += [ "WIN_CONSOLE_APP" ]
} else {
# Set /SUBSYSTEM:WINDOWS for [Link] itself, unless a console build
# has been requested.
configs -= [ "//build/config/win:console" ]
configs += [ "//build/config/win:windowed" ]
}
configs += [
"//build/config/win:delayloads",
"//build/config/win:delayloads_not_for_child_dll",
]
if (current_cpu == "x86") {
# Set the initial stack size to 0.5MiB, instead of the 1.5MiB needed by
# Chrome's main thread. This saves significant memory on threads (like
# those in the Windows thread pool, and others) whose stack size we can
# only control through this setting. Because Chrome's main thread needs
# a minimum 1.5 MiB stack, the main thread (in 32-bit builds only) uses
# fibers to switch to a 1.5 MiB stack before running any other code.
ldflags = [ "/STACK:0x80000" ]
} else {
# Increase the initial stack size. The default is 1MB, this is 8MB.
ldflags = [ "/STACK:0x800000" ]
}
} else if (use_aura) {
# Non-Windows aura entrypoint.
sources += [ "app/chrome_exe_main_aura.cc" ]
}
if (is_linux || is_chromeos) {
sources += [
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
deps += [
# On Linux, link the dependencies (libraries) that make up actual
# Chromium functionality directly into the executable.
":dependencies",
"//chrome/common:version_header",
data_deps += [ "//components/crash/core/app:chrome_crashpad_handler" ]
ldflags = []
# Chrome OS debug builds for arm need to pass --long-plt to the linker.
# See [Link]
if (is_chromeos && is_debug && target_cpu == "arm") {
ldflags += [ "-Wl,--long-plt" ]
}
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [
"//chrome/browser/ash/locale",
"//chrome/browser/ash/schedqos",
]
}
if (use_ozone) {
deps += [ "//ui/ozone" ]
if (is_linux) {
deps += [ "//ui/linux:display_server_utils" ]
}
}
}
data_deps += [
"//chrome/browser/resources/media/mei_preload:component",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component",
"//third_party/widevine/cdm",
]
if (is_linux) {
sources += [
"app/chrome_main_linux.cc",
"app/chrome_main_linux.h",
]
}
}
if (is_win) {
shared_library("chrome_dll") {
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
defines = []
sources = [
"//base/win/[Link]",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
output_name = "chrome"
deps = [
":chrome_dll_manifest",
":chrome_dll_version",
":dependencies",
"//chrome/app:chrome_dll_resources",
"//chrome/app:command_ids",
"//chrome/app/theme:chrome_unscaled_resources",
"//chrome/chrome_elf",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//crypto",
"//headless:headless_non_renderer",
"//headless:headless_shell_browser_lib",
"//net:net_resources",
"//ppapi/buildflags",
"//sandbox/win:sandbox",
"//third_party/cld_3/src/src:cld_3",
"//third_party/wtl",
"//ui/views",
]
configs += [ "//build/config/win:delayloads" ]
if (use_aura) {
deps += [ "//ui/compositor" ]
}
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
copy("copy_first_run") {
sources = [ "app/FirstRun" ]
outputs = [ "$root_out_dir/First Run" ]
}
} else if (is_mac) {
chrome_helper_name = chrome_product_full_name + " Helper"
chrome_framework_name = chrome_product_full_name + " Framework"
chrome_framework_version = chrome_version_full
group("chrome") {
deps = [ ":chrome_app" ]
data_deps = [ ":chrome_app" ]
if (verify_dynamic_libraries) {
deps += [ ":verify_libraries_chrome_app" ]
}
tweak_info_plist("chrome_app_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--scm=1",
"--bundle_id=$chrome_mac_bundle_id",
]
if (enable_updater) {
args += [ "--privileged_helper_id=$privileged_helper_name" ]
if (is_chrome_branded) {
args += [ "--keystone=1" ]
if (current_cpu == "arm64") {
args += [ "--keystone-base-tag=arm64" ]
}
} else {
args += [ "--keystone=0" ]
}
} else {
args += [ "--keystone=0" ]
}
}
mac_app_bundle("chrome_app") {
output_name = chrome_product_full_name
info_plist_target = ":chrome_app_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_CREATOR=$chrome_mac_creator_code",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
":chrome_app_strings_bundle_data",
":chrome_resources",
":chrome_versioned_bundle_data",
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:buildflags",
"//chrome/common:version_header",
]
if (enable_updater) {
deps += [ ":chromium_updater_privileged_helper" ]
}
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags = [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link" ]
ldflags = [ "-Wl,-rpath,@executable_path/../Frameworks" ]
# The Framework is packaged inside the .app bundle. But when using the
# component build, all the dependent shared libraries of :chrome_dll are
# not packaged within the framework. This data_deps line makes all of
# those dependent libraries runtime dependencies of the .app bundle.
# This is a bit of a hack, since GN deliberately terminates its search
# for runtime_deps at create_bundle nodes ([Link]
data_deps = [ ":chrome_framework" ]
}
}
if (verify_dynamic_libraries) {
action("verify_libraries_chrome_app") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [ "${root_out_dir}/${chrome_product_full_name}.app/Contents/MacOS/$
{chrome_product_full_name}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
"--allow",
"/usr/lib/[Link]",
]
deps = [ ":chrome_app" ]
}
}
compiled_action("chrome_app_strings") {
tool = "//chrome/tools/build/mac:infoplist_strings_util"
inputs = []
outputs = []
foreach(locale, platform_pak_locales) {
inputs += [ "$root_gen_dir/chrome/branded_strings_${locale}.pak" ]
}
foreach(locale, locales_as_apple_outputs) {
outputs += [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
}
args =
[
"-b",
"branded_strings",
"-v",
chrome_version_full,
"-g",
rebase_path("$root_gen_dir/chrome", root_build_dir),
"-o",
rebase_path("$target_gen_dir/app_infoplist_strings", root_build_dir),
"-t",
"main",
] + platform_pak_locales
deps = [ "//chrome/app:branded_strings" ]
}
foreach(locale, locales_as_apple_outputs) {
bundle_data("chrome_app_strings_${locale}_bundle_data") {
sources = [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
outputs =
[ "{{bundle_resources_dir}}/$[Link]/{{source_file_part}}" ]
public_deps = [ ":chrome_app_strings" ]
}
}
group("chrome_app_strings_bundle_data") {
public_deps = []
foreach(locale, locales_as_apple_outputs) {
public_deps += [ ":chrome_app_strings_${locale}_bundle_data" ]
}
}
bundle_data("chrome_app_icon") {
sources = [ "app/theme/$branding_path_component/mac/[Link]" ]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
}
bundle_data("chrome_resources") {
sources = [
"$root_out_dir/$chrome_mac_bundle_id.manifest",
"app/theme/$branding_path_component/mac/[Link]",
"browser/ui/cocoa/applescript/[Link]",
]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":chrome_app_icon",
":chrome_app_strings",
"//components/policy:chrome_manifest_bundle",
]
}
bundle_data("chrome_versioned_bundle_data") {
sources = [ "$root_out_dir/$chrome_framework_name.framework" ]
outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
public_deps = [
# Before bundling the versioned app components, delete any existing
# versions.
":clean_up_old_versions",
if (enable_widevine_cdm_host_verification) {
# The :chrome_framework_widevine_signature target copies into the
# :chrome_framework bundle. But because the signing file depends on the
# framework itself, that would cause a cyclical dependency. Instead,
# this dependency directly copies the file into the framework's
# resources directory.
public_deps += [ ":chrome_framework_widevine_signature" ]
}
}
if (enable_updater) {
bundle_data("chromium_updater_privileged_helper") {
sources = [ "$root_out_dir/$privileged_helper_name" ]
outputs = [
"{{bundle_contents_dir}}/Library/LaunchServices/{{source_file_part}}",
]
public_deps = [ "//chrome/updater/mac:privileged_helper" ]
}
}
action("clean_up_old_versions") {
script = "//chrome/tools/build/mac/clean_up_old_versions.py"
_stamp_file = "$root_gen_dir/run_$target_name.stamp"
outputs = [ _stamp_file ]
_versions_dir =
"$root_out_dir/$chrome_product_full_name.app/Contents/Frameworks/$chrome_framework_
[Link]/Versions"
args = [
"--versions-dir",
rebase_path(_versions_dir, root_build_dir),
"--stamp",
rebase_path(_stamp_file, root_build_dir),
"--keep",
chrome_framework_version,
"--keep",
"Current",
]
}
tweak_info_plist("chrome_helper_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=0",
]
}
compile_entitlements("entitlements") {
entitlements_templates = [ "app/[Link]" ]
if (is_chrome_branded && include_branded_entitlements) {
# These entitlements are bound to the official Google Chrome signing
# certificate and will not necessarily work in any other build.
entitlements_templates += [ "app/[Link]" ]
}
output_name = "$target_gen_dir/[Link]"
substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_TEAM_ID=$chrome_mac_team_id",
]
visibility = [ "//chrome/installer/mac:copies" ]
}
template("chrome_helper_app") {
mac_app_bundle(target_name) {
assert(defined(invoker.helper_name_suffix))
assert(defined(invoker.helper_bundle_id_suffix))
if (defined(invoker.info_plist_target)) {
info_plist_target = invoker.info_plist_target
} else {
info_plist_target = ":chrome_helper_plist"
}
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_HELPER_SUFFIX=${invoker.helper_name_suffix}",
"CHROMIUM_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
defines = [ "HELPER_EXECUTABLE" ]
deps = [
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:version_header",
"//sandbox/mac:seatbelt",
]
if (defined([Link])) {
deps += [Link]
}
ldflags = []
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link_nested" ]
ldflags += [
# The helper is in [Link]/Contents/Frameworks/Chromium
[Link]/Versions/X/Helpers/Chromium [Link]/Contents/MacOS
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags += [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
}
}
# Create app for the alert helper manually here as we want to modify the plist
# to set the alert style and add the app icon to its resources.
tweak_info_plist("chrome_helper_app_alerts_plist") {
deps = [ ":chrome_helper_plist" ]
info_plists = get_target_outputs(":chrome_helper_plist") +
[ "app/[Link]" ]
}
chrome_helper_app("chrome_helper_app_${alert_helper_params[0]}") {
helper_name_suffix = alert_helper_params[2]
helper_bundle_id_suffix = alert_helper_params[1]
info_plist_target = ":chrome_helper_app_alerts_plist"
deps = [
":chrome_app_icon",
":chrome_helper_app_alerts_resources",
]
}
if (verify_dynamic_libraries) {
foreach(helper_params, chrome_mac_helpers) {
_helper_target = helper_params[0]
_helper_bundle_id = helper_params[1]
_helper_suffix = helper_params[2]
action("verify_libraries_chrome_helper_app_${_helper_target}") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [
"${root_out_dir}/${chrome_helper_name}${_helper_suffix}.app/Contents/MacOS/$
{chrome_helper_name}${_helper_suffix}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
bundle_data("chrome_framework_helpers") {
sources = [
"$root_out_dir/app_mode_loader",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/web_app_shortcut_copier",
]
outputs = [ "{{bundle_contents_dir}}/Helpers/{{source_file_part}}" ]
public_deps = [
"//chrome/app_shim:app_mode_loader",
"//chrome/browser/web_applications/os_integration/mac:web_app_shortcut_copier",
"//components/crash/core/app:chrome_crashpad_handler",
]
foreach(helper_params, chrome_mac_helpers) {
sources +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.app" ]
public_deps += [ ":chrome_helper_app_${helper_params[0]}" ]
if (verify_dynamic_libraries) {
public_deps +=
[ ":verify_libraries_chrome_helper_app_${helper_params[0]}" ]
}
}
if (enable_updater) {
if (is_chrome_branded) {
sources += [ "//third_party/updater/chrome_mac_universal_prod/cipd/$
{updater_product_full_name}.app" ]
} else {
sources += [ "$root_out_dir/${updater_product_full_name}.app" ]
public_deps += [
"//chrome/updater/mac:browser_install_script",
"//chrome/updater/mac:updater_bundle",
"//chrome/updater/mac:updater_install_script",
]
}
}
}
bundle_data("chrome_framework_resources") {
sources = [
"//ui/gl/resources/angle-metal/gpu_shader_cache.bin",
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":packed_resources",
"//chrome/app_shim:app_mode_loader_plist_bundle_data",
"//chrome/browser/mac:install",
]
if (icu_use_data_file) {
sources += [ "$root_out_dir/[Link]" ]
public_deps += [ "//third_party/icu:icudata" ]
}
if (v8_use_external_startup_data) {
public_deps += [ "//v8" ]
if (use_v8_context_snapshot) {
sources += [ "$root_out_dir/$v8_context_snapshot_filename" ]
public_deps += [ "//tools/v8_context_snapshot" ]
}
if (!use_v8_context_snapshot || include_both_v8_snapshots) {
sources += [ "$root_out_dir/snapshot_blob.bin" ]
}
}
}
if (enable_nacl) {
bundle_data("chrome_framework_plugins") {
sources = []
outputs =
[ "{{bundle_contents_dir}}/Internet Plug-Ins/{{source_file_part}}" ]
public_deps = []
if (enable_nacl) {
if (current_cpu == "x86") {
sources += [ "$root_out_dir/nacl_irt_x86_32.nexe" ]
} else if (current_cpu == "x64") {
sources += [ "$root_out_dir/nacl_irt_x86_64.nexe" ]
}
public_deps += [ "//ppapi/native_client:irt" ]
}
}
} else {
group("chrome_framework_plugins") {
}
}
if (bundle_widevine_cdm) {
bundle_data("widevine_cdm_library_binaries") {
sources = [ "$root_out_dir/$widevine_cdm_path/[Link]" ]
if (enable_widevine_cdm_host_verification) {
sources +=
[ "$root_out_dir/$widevine_cdm_path/[Link]" ]
}
outputs = [
"{{bundle_contents_dir}}/Libraries/$widevine_cdm_path/{{source_file_part}}" ]
public_deps = [ "//third_party/widevine/cdm" ]
}
bundle_data("widevine_cdm_library_manifest_and_license_files") {
sources = [
"$root_out_dir/WidevineCdm/LICENSE",
"$root_out_dir/WidevineCdm/[Link]",
]
outputs = [
"{{bundle_contents_dir}}/Libraries/WidevineCdm/{{source_file_part}}",
]
public_deps = [ "//third_party/widevine/cdm" ]
}
}
group("widevine_cdm_library") {
if (bundle_widevine_cdm) {
deps = [
":widevine_cdm_library_binaries",
":widevine_cdm_library_manifest_and_license_files",
]
}
}
if (enable_widevine_cdm_host_verification) {
widevine_sign_file("sign_chrome_framework_for_widevine") {
file =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
flags = 1
signature_file = "$root_out_dir/$chrome_framework_name.sig"
deps = [ ":chrome_framework" ]
}
copy("chrome_framework_widevine_signature") {
deps = [ ":sign_chrome_framework_for_widevine" ]
sources = [ "$root_out_dir/$chrome_framework_name.sig" ]
outputs = [
"$root_out_dir/$chrome_framework_name.framework/Resources/{{source_file_part}}" ]
}
}
if (build_with_internal_optimization_guide) {
# Add the optimization guide .dylib in the MODULE_DIR of [Link]
bundle_data("optimization_guide_library") {
sources = [
"$root_out_dir/og_intermediates/liboptimization_guide_internal.dylib",
]
outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ]
public_deps = [
"//components/optimization_guide/core:optimization_guide_internal_library_copy" ]
}
} else {
group("optimization_guide_library") {
}
}
tweak_info_plist("chrome_framework_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=1",
"--branding",
chrome_product_short_name,
]
}
sources = [
"app/chrome_crash_reporter_client.cc",
"app/chrome_crash_reporter_client.h",
"app/chrome_crash_reporter_client_mac.mm",
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/chrome_main_mac.h",
"app/chrome_main_mac.mm",
"app/startup_timestamps.h",
]
deps = [
":dependencies",
"//build:chromeos_buildflags",
"//chrome/app:command_ids",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//headless:headless_shell_lib",
"//third_party/cld_3/src/src:cld_3",
]
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
if (is_component_build) {
frameworks = [ "[Link]" ]
}
ldflags = [ "-ObjC" ]
configs += [
":chrome_dll_symbol_order",
"//build/config/compiler:wexit_time_destructors",
]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
}
mac_framework_bundle("chrome_framework") {
output_name = chrome_framework_name
framework_version = chrome_framework_version
framework_contents = [
"Helpers",
"Libraries",
"Resources",
]
if (is_chrome_branded) {
framework_contents += [ "Default Apps" ]
}
if (enable_nacl) {
framework_contents += [ "Internet Plug-Ins" ]
}
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
info_plist_target = ":chrome_framework_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
]
public_deps = [ ":chrome_dll" ]
bundle_deps = [
":angle_binaries",
":chrome_framework_helpers",
":chrome_framework_plugins",
":chrome_framework_resources",
":optimization_guide_library",
":swiftshader_binaries",
":widevine_cdm_library",
"//chrome/browser/resources/media/mei_preload:component_bundle",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component_bundle",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component_bundle
",
]
if (is_chrome_branded) {
bundle_deps += [ ":preinstalled_apps" ]
}
configs += [ ":chrome_dll_symbol_order" ]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
ldflags = [
"-compatibility_version",
chrome_dylib_version,
"-current_version",
chrome_dylib_version,
]
if (!is_component_build) {
# Specify a sensible install_name for static builds. The library is
# dlopen()ed so this is not used to resolve the module.
ldflags += [
"-Wl,-install_name,@executable_path/../Frameworks/$chrome_framework_name.framework/
Versions/$chrome_framework_version/$chrome_framework_name" ]
} else {
# In the component build, both the :chrome_app and various
# :chrome_helper* targets directly link to the Framework target. Use
# @rpath-based loading so that the dylib ID does not have to be changed
# with install_name_tool.
ldflags += [
"-Wl,-install_name,@rpath/$chrome_framework_name.framework/$chrome_framework_name",
"-Wl,-rpath,@loader_path/../../../../../..",
"-Wl,-reexport_library,libchrome_dll.dylib",
]
data_deps = [ ":chrome_dll" ]
}
}
_framework_binary_path =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
assert(_framework_binary_path != "",
"Ignore configuration-dependent unused variable warning")
# This list must be updated with the two targets' deps list below, and
# the list of _dsyms in :chrome_dsym_archive.
_chrome_symbols_sources = [
"$root_out_dir/$chrome_product_full_name.app/Contents/MacOS/$chrome_product_full_na
me",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.dylib",
_framework_binary_path,
]
if (build_with_internal_optimization_guide) {
_chrome_symbols_sources +=
[ "$root_out_dir/liboptimization_guide_internal.dylib" ]
}
foreach(helper_params, chrome_mac_helpers) {
_chrome_symbols_sources += [ "$root_out_dir/${chrome_helper_name}$
{helper_params[2]}.app/Contents/MacOS/${chrome_helper_name}${helper_params[2]}" ]
}
action_foreach("chrome_dump_syms") {
script = "//build/redirect_stdout.py"
sources = _chrome_symbols_sources
outputs =
[ "$root_out_dir/{{source_file_part}}-$chrome_version_full.breakpad" ]
dump_syms =
"//third_party/breakpad:dump_syms($host_system_allocator_toolchain)"
args = rebase_path(outputs, root_build_dir) + [
rebase_path(get_label_info(dump_syms, "root_out_dir") + "/" +
get_label_info(dump_syms, "name"),
root_build_dir),
"-d",
"-m",
"-g",
rebase_path(
"$root_out_dir/{{source_file_part}}.dSYM/Contents/Resources/DWARF/
{{source_file_part}}",
root_build_dir),
"{{source}}",
]
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
dump_syms,
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
}
action("chrome_dsym_archive") {
script = "//chrome/tools/build/mac/archive_symbols.py"
# These are the dSYMs that will be archived. The sources list must be
# the target outputs that correspond to the dSYMs (since a dSYM is a
# directory it cannot be listed as a source file). The targets that
# generate both the dSYM and binary image are listed in deps.
_dsyms = [
"$root_out_dir/$chrome_framework_name.dSYM",
"$root_out_dir/$chrome_product_full_name.dSYM",
"$root_out_dir/chrome_crashpad_handler.dSYM",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.[Link]",
]
if (build_with_internal_optimization_guide) {
_dsyms += [ "$root_out_dir/liboptimization_guide_internal.[Link]" ]
}
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
_dsyms +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.dSYM" ]
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
sources = _chrome_symbols_sources
_output = "$root_out_dir/$chrome_product_full_name.[Link].bz2"
outputs = [ _output ]
group("dependencies") {
public_deps = [
"//build:branding_buildflags",
"//build:chromeos_buildflags",
"//chrome/browser",
"//chrome/browser:buildflags",
"//chrome/browser:shell_integration",
"//chrome/browser/policy:path_parser",
"//chrome/child",
"//chrome/common",
"//chrome/gpu",
"//chrome/renderer",
"//chrome/utility",
"//components/crash/core/app",
"//components/devtools/devtools_pipe",
"//components/memory_system",
"//components/startup_metric_utils",
"//components/sync",
"//components/upload_list:upload_list",
"//components/webui/about",
"//content/public/child",
"//pdf",
"//services/tracing/public/cpp",
"//third_party/blink/public:blink_devtools_frontend_resources",
"//third_party/blink/public:blink_devtools_inspector_resources",
"//v8:v8_headers",
]
if (enable_ppapi) {
public_deps += [ "//ppapi/host" ]
}
if (enable_printing) {
public_deps += [ "//printing" ]
}
if (enable_nacl) {
public_deps += [
"//components/nacl/browser",
"//components/nacl/renderer/plugin:nacl_trusted_plugin",
]
}
if (is_chromeos) {
public_deps += [
"//ash/constants",
"//chrome/browser/ash/boot_times_recorder",
"//chrome/browser/ash/dbus",
"//chrome/browser/ash/schedqos",
"//chromeos/ash/components/memory",
"//chromeos/dbus/constants",
]
}
}
if (is_win) {
process_version_rc_template("chrome_exe_version") {
sources = [ "app/chrome_exe.ver" ]
output = "$target_gen_dir/chrome_exe_version.rc"
}
process_version_rc_template("chrome_dll_version") {
sources = [ "app/chrome_dll.ver" ]
output = "$target_gen_dir/chrome_dll_version.rc"
}
# This manifest matches what GYP produced. It may not even be necessary.
windows_manifest("chrome_dll_manifest") {
sources = [
as_invoker_manifest,
common_controls_manifest,
]
}
process_version_rc_template("other_version") {
sources = [ "app/[Link]" ]
output = "$target_gen_dir/other_version.rc"
}
}
copy("visual_elements_resources") {
sources = [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"app/visual_elements_resources/[Link]",
]
if (is_chrome_branded) {
sources += [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
group("resources") {
public_deps = [
"//chrome/browser:resources",
"//chrome/common:resources",
"//chrome/renderer:resources",
]
}
group("extra_resources") {
# Deps should be same as those in chrome_extra_paks() within chrome_paks.gni.
public_deps = [
"//chrome/browser/resources:resources",
"//components/autofill/core/browser:autofill_address_rewriter_resources",
]
}
target(_preinstalled_apps_target_type, "preinstalled_apps") {
visibility = [ ":packed_resources" ]
if (is_mac) {
visibility += [
":chrome_framework",
":chrome_framework_shared_library",
]
}
sources = [ "browser/resources/default_apps/external_extensions.json" ]
if (!is_mac) {
outputs = [ "$root_out_dir/default_apps/{{source_file_part}}" ]
} else {
outputs = [ "{{bundle_contents_dir}}/Default Apps/{{source_file_part}}" ]
}
# Force anybody that depends on this to get the default apps as data files.
data = process_file_template(sources, outputs)
}
}
if (!is_android) {
chrome_paks("packed_resources") {
if (is_mac) {
output_dir = "$root_gen_dir/repack"
copy_data_to_bundle = true
} else {
output_dir = root_out_dir
mark_as_data = true
}
if (enable_resource_allowlist_generation) {
repack_allowlist = _chrome_resource_allowlist
deps = [ ":resource_allowlist" ]
}
repack("browser_tests_pak") {
testonly = true
sources = [ "$root_gen_dir/chrome/webui_test_resources.pak" ]
output = "$root_out_dir/browser_tests.pak"
deps = [ "//chrome/test/data/webui:resources" ]
}
group("strings") {
public_deps = [
"//chrome/app:branded_strings",
"//chrome/app:generated_resources",
"//chrome/app/resources:locale_settings",
]
}
if (is_android) {
java_cpp_enum("offline_pages_enum_javagen") {
sources = [ "browser/offline_pages/offline_page_utils.h" ]
}
java_cpp_enum("download_enum_javagen") {
sources = [
"browser/download/android/download_open_source.h",
"browser/download/download_dialog_types.h",
"browser/download/download_prompt_status.h",
]
}
source_set("chrome_android_core") {
sources = [
"app/android/chrome_jni_onload.cc",
"app/android/chrome_jni_onload.h",
"app/android/chrome_main_delegate_android.cc",
"app/android/chrome_main_delegate_android.h",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
libs = [
"android",
"jnigraphics",
]
public_deps = [
"//chrome/browser",
"//chrome/utility",
]
deps = [
":dependencies",
"//chrome/browser/flags:flags_android",
"//chrome/browser/ui",
"//chrome/child",
"//chrome/common",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/gpu",
"//chrome/renderer",
"//components/crash/android:crash_android",
"//components/minidump_uploader",
"//components/safe_browsing:buildflags",
"//components/safe_browsing/android:safe_browsing_api_handler",
"//components/safe_browsing/android:safe_browsing_mobile",
"//components/stylus_handwriting/android",
"//components/variations:variations_associated_data",
"//content/public/app",
]
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
}
if (is_linux || is_chromeos) {
if (!(is_debug && use_debug_fission)) {
group("linux_symbols") {
deps = [
":angle_egl_symbols",
":angle_gles_symbols",
":chrome_crashpad_symbols",
":chrome_symbols",
]
if (is_linux) {
deps += [ ":swiftshader_vk_symbols" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
deps += [ ":angle_libvulkan_symbols" ]
}
if (build_with_internal_optimization_guide) {
deps += [ ":optimization_guide_symbols" ]
}
}
extract_symbols("chrome_symbols") {
binary = "$root_out_dir/chrome"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ ":chrome" ]
}
extract_symbols("chrome_crashpad_symbols") {
binary = "$root_out_dir/chrome_crashpad_handler"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ "//components/crash/core/app:chrome_crashpad_handler" ]
}
extract_symbols("swiftshader_vk_symbols") {
binary = "$root_out_dir/libvk_swiftshader.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.$current_cpu"
}
deps = [ "//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan" ]
}
extract_symbols("angle_egl_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libegl.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libegl.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libEGL" ]
}
extract_symbols("angle_gles_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libgles.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libgles.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libGLESv2" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
extract_symbols("angle_libvulkan_symbols") {
binary = "$root_out_dir/[Link].1"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.$current_cpu"
}
deps = [ "//third_party/vulkan-loader/src:libvulkan" ]
}
}
if (build_with_internal_optimization_guide) {
extract_symbols("optimization_guide_symbols") {
binary = "$root_out_dir/liboptimization_guide_internal.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.ia32"
} else {
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.$current_cpu"
}
deps = [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
}
}
# Copies some scripts and resources that are used for desktop integration.
copy("xdg_mime") {
sources = [
"//chrome/tools/build/linux/chrome-wrapper",
"//third_party/xdg-utils/scripts/xdg-mime",
"//third_party/xdg-utils/scripts/xdg-settings",
]
if (is_linux) {
sources += [
"//chrome/app/theme/$branding_path_component/linux/product_logo_48.png",
]
} else {
sources +=
[ "//chrome/app/theme/$branding_path_component/product_logo_48.png" ]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
}
if (_cros_generate_embed_section_target) {
embed_sections("section_embedded_chrome_binary") {
binary_input = "$root_out_dir/chrome"
sections_embedded_binary_output = "$root_out_dir/chrome.sections_embedded"
deps = [ ":chrome" ]
}
}
mport("//build/config/chrome_build.gni")
import("//build/config/chromeos/[Link]")
import("//build/config/chromeos/ui_mode.gni")
import("//build/config/compiler/[Link]")
import("//build/config/compiler/pgo/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/sanitizers/[Link]")
import("//build/config/[Link]")
import("//build/config/win/console_app.gni")
import("//build/config/win/[Link]")
import("//build/private_code_test/private_code_test.gni")
import("//build/toolchain/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/chrome_paks.gni")
import("//chrome/common/[Link]")
import("//chrome/process_version_rc_template.gni")
import("//components/nacl/[Link]")
import("//components/optimization_guide/[Link]")
import("//extensions/buildflags/[Link]")
import("//media/media_options.gni")
import("//ppapi/buildflags/[Link]")
import("//third_party/angle/gni/[Link]")
import("//third_party/blink/public/public_features.gni")
import("//third_party/widevine/cdm/[Link]")
import("//tools/resources/generate_resource_allowlist.gni")
import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
import("//ui/gl/[Link]")
import("//v8/gni/[Link]")
if (is_android) {
import("//build/config/android/[Link]")
} else if (is_linux || is_chromeos) {
import("//build/linux/extract_symbols.gni")
import("//build/linux/strip_binary.gni")
} else if (is_mac) {
import("//build/apple/compile_entitlements.gni")
import("//build/apple/compile_plist.gni")
import("//build/apple/tweak_info_plist.gni")
import("//build/compiled_action.gni")
import("//build/config/apple/[Link]")
import("//build/config/mac/mac_sdk.gni")
import("//build/config/mac/[Link]")
import("//build/util/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/updater/[Link]")
import("//chrome/[Link]")
import("//content/public/app/mac_helpers.gni")
import("//media/cdm/library_cdm/cdm_paths.gni")
import("//services/on_device_model/on_device_model.gni")
import("//third_party/icu/[Link]")
}
if (_cros_generate_embed_section_target) {
import("//build/chromeos/embed_sections.gni")
}
declare_args() {
# On macOS, `is_chrome_branded` builds that have been signed locally will not
# launch because certain entitlements are tied to the official Google code
# signing identity. If `include_branded_entitlements` is set to false, these
# entitlements will be skipped.
include_branded_entitlements = true
}
if (is_win) {
action("reorder_imports") {
script = "//build/win/[Link]"
# initialexe/ is used so that the we can reorder imports and write back to
# the final destination at $root_out_dir/.
inputs = [
"$root_out_dir/initialexe/[Link]",
"$root_out_dir/initialexe/[Link]",
]
outputs = [
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
]
args = [
"-i",
rebase_path("$root_out_dir/initialexe", root_build_dir),
"-o",
rebase_path("$root_out_dir", root_build_dir),
"-a",
current_cpu,
]
deps = [ ":chrome_initial" ]
}
}
# This does not currently work. See [Link]/1311822.
# This target exists above chrome and it's main components in the dependency
# tree as a central place to put assert_no_deps annotations. Since this depends
# on Chrome and the main DLLs it uses, it will transitively assert that those
# targets also have no deps on disallowed things.
group("assert_no_deps") {
deps = []
if (is_android) {
deps += [ "//chrome/android:chrome_public_apk" ]
} else {
deps += [ ":chrome" ]
}
if (is_win) {
deps += [ ":chrome_dll" ]
}
# This should not pull in installer strings. This is will bloat the binary
# for no reason and is easy to mess up. See the comment at the top of
# //chrome/installer/util/[Link].
assert_no_deps = [ "//chrome/installer/util:strings" ]
}
if (is_win) {
_chrome_output_name = "initialexe/chrome"
} else {
_chrome_output_name = "chrome"
}
executable("chrome_initial") {
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
output_name = _chrome_output_name
if (is_chromeos) {
data_deps += [
"//components/variations/cros_evaluate_seed:evaluate_seed",
"//sandbox/linux:chrome_sandbox",
]
if (build_mojo_proxy) {
data_deps += [ "//mojo/proxy:mojo_proxy" ]
}
deps += [
"//components/exo/wayland:test_controller_stub",
"//components/exo/wayland:ui_controls_protocol_stub",
]
}
if (is_win) {
sources += [
"app/chrome_exe.rc",
"app/chrome_exe_main_win.cc",
"app/delay_load_failure_hook_win.cc",
"app/delay_load_failure_hook_win.h",
"app/main_dll_loader_win.cc",
"app/main_dll_loader_win.h",
"common/crash_keys.cc",
"common/crash_keys.h",
]
deps += [
":chrome_dll",
":chrome_exe_version",
":copy_first_run",
":packed_resources_integrity_header",
":visual_elements_resources",
"//base",
"//build:branding_buildflags",
"//chrome/app:chrome_exe_main_exports",
"//chrome/app:exit_code_watcher",
"//chrome/app/version_assembly:chrome_exe_manifest",
"//chrome/browser:active_use_util",
"//chrome/browser:chrome_process_finder",
"//chrome/browser/policy:path_parser",
"//chrome/chrome_elf",
"//chrome/common:constants",
"//chrome/common/win:delay_load_failure_support",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//chrome/installer/util:constants",
"//chrome/installer/util:did_run_support",
"//components/crash/core/app",
"//components/crash/core/app:run_as_crashpad_handler",
"//components/crash/core/common",
"//components/crash/win:chrome_wer",
"//components/webui/flags:switches",
"//content:sandbox_helper_win",
"//content/public/common:static_switches",
"//crypto",
"//gpu/command_buffer/service",
"//sandbox",
"//sandbox/policy",
"//sandbox/policy/mojom",
"//third_party/breakpad:breakpad_handler",
"//third_party/breakpad:breakpad_sender",
"//third_party/crashpad/crashpad/util",
"//ui/gl",
]
data_deps = [
"//chrome/app/version_assembly:version_assembly_manifest",
"//chrome/browser/web_applications/chrome_pwa_launcher",
"//chrome/chrome_proxy",
"//chrome/elevation_service",
"//chrome/notification_helper",
"//chrome/windows_services/elevated_tracing_service",
]
if (enable_platform_experience) {
data_deps +=
[ "//chrome/browser/platform_experience/win:os_update_handler" ]
}
defines += [ "CHROME_EXE_MAIN" ]
if (win_console_app) {
defines += [ "WIN_CONSOLE_APP" ]
} else {
# Set /SUBSYSTEM:WINDOWS for [Link] itself, unless a console build
# has been requested.
configs -= [ "//build/config/win:console" ]
configs += [ "//build/config/win:windowed" ]
}
configs += [
"//build/config/win:delayloads",
"//build/config/win:delayloads_not_for_child_dll",
]
if (current_cpu == "x86") {
# Set the initial stack size to 0.5MiB, instead of the 1.5MiB needed by
# Chrome's main thread. This saves significant memory on threads (like
# those in the Windows thread pool, and others) whose stack size we can
# only control through this setting. Because Chrome's main thread needs
# a minimum 1.5 MiB stack, the main thread (in 32-bit builds only) uses
# fibers to switch to a 1.5 MiB stack before running any other code.
ldflags = [ "/STACK:0x80000" ]
} else {
# Increase the initial stack size. The default is 1MB, this is 8MB.
ldflags = [ "/STACK:0x800000" ]
}
} else if (use_aura) {
# Non-Windows aura entrypoint.
sources += [ "app/chrome_exe_main_aura.cc" ]
}
if (is_linux || is_chromeos) {
sources += [
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
deps += [
# On Linux, link the dependencies (libraries) that make up actual
# Chromium functionality directly into the executable.
":dependencies",
"//chrome/common:version_header",
public_deps = [
":xdg_mime", # Needs to be public for installer to consume files.
"//chrome/common:buildflags",
]
data_deps += [ "//components/crash/core/app:chrome_crashpad_handler" ]
ldflags = []
# Chrome OS debug builds for arm need to pass --long-plt to the linker.
# See [Link]
if (is_chromeos && is_debug && target_cpu == "arm") {
ldflags += [ "-Wl,--long-plt" ]
}
if (use_ozone) {
deps += [ "//ui/ozone" ]
if (is_linux) {
deps += [ "//ui/linux:display_server_utils" ]
}
}
}
data_deps += [
"//chrome/browser/resources/media/mei_preload:component",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component",
"//third_party/widevine/cdm",
]
if (is_linux) {
sources += [
"app/chrome_main_linux.cc",
"app/chrome_main_linux.h",
]
}
}
if (is_win) {
shared_library("chrome_dll") {
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
defines = []
sources = [
"//base/win/[Link]",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
output_name = "chrome"
deps = [
":chrome_dll_manifest",
":chrome_dll_version",
":dependencies",
"//chrome/app:chrome_dll_resources",
"//chrome/app:command_ids",
"//chrome/app/theme:chrome_unscaled_resources",
"//chrome/chrome_elf",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//crypto",
"//headless:headless_non_renderer",
"//headless:headless_shell_browser_lib",
"//net:net_resources",
"//ppapi/buildflags",
"//sandbox/win:sandbox",
"//third_party/cld_3/src/src:cld_3",
"//third_party/wtl",
"//ui/views",
]
configs += [ "//build/config/win:delayloads" ]
if (use_aura) {
deps += [ "//ui/compositor" ]
}
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
copy("copy_first_run") {
sources = [ "app/FirstRun" ]
outputs = [ "$root_out_dir/First Run" ]
}
} else if (is_mac) {
chrome_helper_name = chrome_product_full_name + " Helper"
chrome_framework_name = chrome_product_full_name + " Framework"
chrome_framework_version = chrome_version_full
group("chrome") {
deps = [ ":chrome_app" ]
data_deps = [ ":chrome_app" ]
if (verify_dynamic_libraries) {
deps += [ ":verify_libraries_chrome_app" ]
}
tweak_info_plist("chrome_app_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--scm=1",
"--bundle_id=$chrome_mac_bundle_id",
]
if (enable_updater) {
args += [ "--privileged_helper_id=$privileged_helper_name" ]
if (is_chrome_branded) {
args += [ "--keystone=1" ]
if (current_cpu == "arm64") {
args += [ "--keystone-base-tag=arm64" ]
}
} else {
args += [ "--keystone=0" ]
}
} else {
args += [ "--keystone=0" ]
}
}
mac_app_bundle("chrome_app") {
output_name = chrome_product_full_name
info_plist_target = ":chrome_app_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_CREATOR=$chrome_mac_creator_code",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
":chrome_app_strings_bundle_data",
":chrome_resources",
":chrome_versioned_bundle_data",
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:buildflags",
"//chrome/common:version_header",
]
if (enable_updater) {
deps += [ ":chromium_updater_privileged_helper" ]
}
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags = [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link" ]
ldflags = [ "-Wl,-rpath,@executable_path/../Frameworks" ]
# The Framework is packaged inside the .app bundle. But when using the
# component build, all the dependent shared libraries of :chrome_dll are
# not packaged within the framework. This data_deps line makes all of
# those dependent libraries runtime dependencies of the .app bundle.
# This is a bit of a hack, since GN deliberately terminates its search
# for runtime_deps at create_bundle nodes ([Link]
data_deps = [ ":chrome_framework" ]
}
}
if (verify_dynamic_libraries) {
action("verify_libraries_chrome_app") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [ "${root_out_dir}/${chrome_product_full_name}.app/Contents/MacOS/$
{chrome_product_full_name}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
"--allow",
"/usr/lib/[Link]",
]
deps = [ ":chrome_app" ]
}
}
compiled_action("chrome_app_strings") {
tool = "//chrome/tools/build/mac:infoplist_strings_util"
inputs = []
outputs = []
foreach(locale, platform_pak_locales) {
inputs += [ "$root_gen_dir/chrome/branded_strings_${locale}.pak" ]
}
foreach(locale, locales_as_apple_outputs) {
outputs += [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
}
args =
[
"-b",
"branded_strings",
"-v",
chrome_version_full,
"-g",
rebase_path("$root_gen_dir/chrome", root_build_dir),
"-o",
rebase_path("$target_gen_dir/app_infoplist_strings", root_build_dir),
"-t",
"main",
] + platform_pak_locales
deps = [ "//chrome/app:branded_strings" ]
}
foreach(locale, locales_as_apple_outputs) {
bundle_data("chrome_app_strings_${locale}_bundle_data") {
sources = [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
outputs =
[ "{{bundle_resources_dir}}/$[Link]/{{source_file_part}}" ]
public_deps = [ ":chrome_app_strings" ]
}
}
group("chrome_app_strings_bundle_data") {
public_deps = []
foreach(locale, locales_as_apple_outputs) {
public_deps += [ ":chrome_app_strings_${locale}_bundle_data" ]
}
}
bundle_data("chrome_app_icon") {
sources = [ "app/theme/$branding_path_component/mac/[Link]" ]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
}
bundle_data("chrome_resources") {
sources = [
"$root_out_dir/$chrome_mac_bundle_id.manifest",
"app/theme/$branding_path_component/mac/[Link]",
"browser/ui/cocoa/applescript/[Link]",
]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":chrome_app_icon",
":chrome_app_strings",
"//components/policy:chrome_manifest_bundle",
]
}
bundle_data("chrome_versioned_bundle_data") {
sources = [ "$root_out_dir/$chrome_framework_name.framework" ]
outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
public_deps = [
# Before bundling the versioned app components, delete any existing
# versions.
":clean_up_old_versions",
if (enable_widevine_cdm_host_verification) {
# The :chrome_framework_widevine_signature target copies into the
# :chrome_framework bundle. But because the signing file depends on the
# framework itself, that would cause a cyclical dependency. Instead,
# this dependency directly copies the file into the framework's
# resources directory.
public_deps += [ ":chrome_framework_widevine_signature" ]
}
}
if (enable_updater) {
bundle_data("chromium_updater_privileged_helper") {
sources = [ "$root_out_dir/$privileged_helper_name" ]
outputs = [
"{{bundle_contents_dir}}/Library/LaunchServices/{{source_file_part}}",
]
public_deps = [ "//chrome/updater/mac:privileged_helper" ]
}
}
action("clean_up_old_versions") {
script = "//chrome/tools/build/mac/clean_up_old_versions.py"
_stamp_file = "$root_gen_dir/run_$target_name.stamp"
outputs = [ _stamp_file ]
_versions_dir =
"$root_out_dir/$chrome_product_full_name.app/Contents/Frameworks/$chrome_framework_
[Link]/Versions"
args = [
"--versions-dir",
rebase_path(_versions_dir, root_build_dir),
"--stamp",
rebase_path(_stamp_file, root_build_dir),
"--keep",
chrome_framework_version,
"--keep",
"Current",
]
}
tweak_info_plist("chrome_helper_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=0",
]
}
compile_entitlements("entitlements") {
entitlements_templates = [ "app/[Link]" ]
if (is_chrome_branded && include_branded_entitlements) {
# These entitlements are bound to the official Google Chrome signing
# certificate and will not necessarily work in any other build.
entitlements_templates += [ "app/[Link]" ]
}
output_name = "$target_gen_dir/[Link]"
substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_TEAM_ID=$chrome_mac_team_id",
]
visibility = [ "//chrome/installer/mac:copies" ]
}
template("chrome_helper_app") {
mac_app_bundle(target_name) {
assert(defined(invoker.helper_name_suffix))
assert(defined(invoker.helper_bundle_id_suffix))
if (defined(invoker.info_plist_target)) {
info_plist_target = invoker.info_plist_target
} else {
info_plist_target = ":chrome_helper_plist"
}
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_HELPER_SUFFIX=${invoker.helper_name_suffix}",
"CHROMIUM_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
defines = [ "HELPER_EXECUTABLE" ]
deps = [
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:version_header",
"//sandbox/mac:seatbelt",
]
if (defined([Link])) {
deps += [Link]
}
ldflags = []
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link_nested" ]
ldflags += [
# The helper is in [Link]/Contents/Frameworks/Chromium
[Link]/Versions/X/Helpers/Chromium [Link]/Contents/MacOS
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags += [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
}
}
# Create app for the alert helper manually here as we want to modify the plist
# to set the alert style and add the app icon to its resources.
tweak_info_plist("chrome_helper_app_alerts_plist") {
deps = [ ":chrome_helper_plist" ]
info_plists = get_target_outputs(":chrome_helper_plist") +
[ "app/[Link]" ]
}
chrome_helper_app("chrome_helper_app_${alert_helper_params[0]}") {
helper_name_suffix = alert_helper_params[2]
helper_bundle_id_suffix = alert_helper_params[1]
info_plist_target = ":chrome_helper_app_alerts_plist"
deps = [
":chrome_app_icon",
":chrome_helper_app_alerts_resources",
]
}
if (verify_dynamic_libraries) {
foreach(helper_params, chrome_mac_helpers) {
_helper_target = helper_params[0]
_helper_bundle_id = helper_params[1]
_helper_suffix = helper_params[2]
action("verify_libraries_chrome_helper_app_${_helper_target}") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [
"${root_out_dir}/${chrome_helper_name}${_helper_suffix}.app/Contents/MacOS/$
{chrome_helper_name}${_helper_suffix}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
bundle_data("chrome_framework_helpers") {
sources = [
"$root_out_dir/app_mode_loader",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/web_app_shortcut_copier",
]
outputs = [ "{{bundle_contents_dir}}/Helpers/{{source_file_part}}" ]
public_deps = [
"//chrome/app_shim:app_mode_loader",
"//chrome/browser/web_applications/os_integration/mac:web_app_shortcut_copier",
"//components/crash/core/app:chrome_crashpad_handler",
]
foreach(helper_params, chrome_mac_helpers) {
sources +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.app" ]
public_deps += [ ":chrome_helper_app_${helper_params[0]}" ]
if (verify_dynamic_libraries) {
public_deps +=
[ ":verify_libraries_chrome_helper_app_${helper_params[0]}" ]
}
}
if (enable_updater) {
if (is_chrome_branded) {
sources += [ "//third_party/updater/chrome_mac_universal_prod/cipd/$
{updater_product_full_name}.app" ]
} else {
sources += [ "$root_out_dir/${updater_product_full_name}.app" ]
public_deps += [
"//chrome/updater/mac:browser_install_script",
"//chrome/updater/mac:updater_bundle",
"//chrome/updater/mac:updater_install_script",
]
}
}
}
bundle_data("chrome_framework_resources") {
sources = [
"//ui/gl/resources/angle-metal/gpu_shader_cache.bin",
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":packed_resources",
"//chrome/app_shim:app_mode_loader_plist_bundle_data",
"//chrome/browser/mac:install",
]
if (icu_use_data_file) {
sources += [ "$root_out_dir/[Link]" ]
public_deps += [ "//third_party/icu:icudata" ]
}
if (v8_use_external_startup_data) {
public_deps += [ "//v8" ]
if (use_v8_context_snapshot) {
sources += [ "$root_out_dir/$v8_context_snapshot_filename" ]
public_deps += [ "//tools/v8_context_snapshot" ]
}
if (!use_v8_context_snapshot || include_both_v8_snapshots) {
sources += [ "$root_out_dir/snapshot_blob.bin" ]
}
}
}
if (enable_nacl) {
bundle_data("chrome_framework_plugins") {
sources = []
outputs =
[ "{{bundle_contents_dir}}/Internet Plug-Ins/{{source_file_part}}" ]
public_deps = []
if (enable_nacl) {
if (current_cpu == "x86") {
sources += [ "$root_out_dir/nacl_irt_x86_32.nexe" ]
} else if (current_cpu == "x64") {
sources += [ "$root_out_dir/nacl_irt_x86_64.nexe" ]
}
public_deps += [ "//ppapi/native_client:irt" ]
}
}
} else {
group("chrome_framework_plugins") {
}
}
if (bundle_widevine_cdm) {
bundle_data("widevine_cdm_library_binaries") {
sources = [ "$root_out_dir/$widevine_cdm_path/[Link]" ]
if (enable_widevine_cdm_host_verification) {
sources +=
[ "$root_out_dir/$widevine_cdm_path/[Link]" ]
}
outputs = [
"{{bundle_contents_dir}}/Libraries/$widevine_cdm_path/{{source_file_part}}" ]
public_deps = [ "//third_party/widevine/cdm" ]
}
bundle_data("widevine_cdm_library_manifest_and_license_files") {
sources = [
"$root_out_dir/WidevineCdm/LICENSE",
"$root_out_dir/WidevineCdm/[Link]",
]
outputs = [
"{{bundle_contents_dir}}/Libraries/WidevineCdm/{{source_file_part}}",
]
public_deps = [ "//third_party/widevine/cdm" ]
}
}
group("widevine_cdm_library") {
if (bundle_widevine_cdm) {
deps = [
":widevine_cdm_library_binaries",
":widevine_cdm_library_manifest_and_license_files",
]
}
}
if (enable_widevine_cdm_host_verification) {
widevine_sign_file("sign_chrome_framework_for_widevine") {
file =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
flags = 1
signature_file = "$root_out_dir/$chrome_framework_name.sig"
deps = [ ":chrome_framework" ]
}
copy("chrome_framework_widevine_signature") {
deps = [ ":sign_chrome_framework_for_widevine" ]
sources = [ "$root_out_dir/$chrome_framework_name.sig" ]
outputs = [
"$root_out_dir/$chrome_framework_name.framework/Resources/{{source_file_part}}" ]
}
}
if (build_with_internal_optimization_guide) {
# Add the optimization guide .dylib in the MODULE_DIR of [Link]
bundle_data("optimization_guide_library") {
sources = [
"$root_out_dir/og_intermediates/liboptimization_guide_internal.dylib",
]
outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ]
public_deps = [
"//components/optimization_guide/core:optimization_guide_internal_library_copy" ]
}
} else {
group("optimization_guide_library") {
}
}
tweak_info_plist("chrome_framework_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=1",
"--branding",
chrome_product_short_name,
]
}
sources = [
"app/chrome_crash_reporter_client.cc",
"app/chrome_crash_reporter_client.h",
"app/chrome_crash_reporter_client_mac.mm",
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/chrome_main_mac.h",
"app/chrome_main_mac.mm",
"app/startup_timestamps.h",
]
deps = [
":dependencies",
"//build:chromeos_buildflags",
"//chrome/app:command_ids",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//headless:headless_shell_lib",
"//third_party/cld_3/src/src:cld_3",
]
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
if (is_component_build) {
frameworks = [ "[Link]" ]
}
ldflags = [ "-ObjC" ]
configs += [
":chrome_dll_symbol_order",
"//build/config/compiler:wexit_time_destructors",
]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
}
mac_framework_bundle("chrome_framework") {
output_name = chrome_framework_name
framework_version = chrome_framework_version
framework_contents = [
"Helpers",
"Libraries",
"Resources",
]
if (is_chrome_branded) {
framework_contents += [ "Default Apps" ]
}
if (enable_nacl) {
framework_contents += [ "Internet Plug-Ins" ]
}
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
info_plist_target = ":chrome_framework_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
]
public_deps = [ ":chrome_dll" ]
bundle_deps = [
":angle_binaries",
":chrome_framework_helpers",
":chrome_framework_plugins",
":chrome_framework_resources",
":optimization_guide_library",
":swiftshader_binaries",
":widevine_cdm_library",
"//chrome/browser/resources/media/mei_preload:component_bundle",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component_bundle",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component_bundle
",
]
if (is_chrome_branded) {
bundle_deps += [ ":preinstalled_apps" ]
}
configs += [ ":chrome_dll_symbol_order" ]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
ldflags = [
"-compatibility_version",
chrome_dylib_version,
"-current_version",
chrome_dylib_version,
]
if (!is_component_build) {
# Specify a sensible install_name for static builds. The library is
# dlopen()ed so this is not used to resolve the module.
ldflags += [
"-Wl,-install_name,@executable_path/../Frameworks/$chrome_framework_name.framework/
Versions/$chrome_framework_version/$chrome_framework_name" ]
} else {
# In the component build, both the :chrome_app and various
# :chrome_helper* targets directly link to the Framework target. Use
# @rpath-based loading so that the dylib ID does not have to be changed
# with install_name_tool.
ldflags += [
"-Wl,-install_name,@rpath/$chrome_framework_name.framework/$chrome_framework_name",
"-Wl,-rpath,@loader_path/../../../../../..",
"-Wl,-reexport_library,libchrome_dll.dylib",
]
data_deps = [ ":chrome_dll" ]
}
}
_framework_binary_path =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
assert(_framework_binary_path != "",
"Ignore configuration-dependent unused variable warning")
# This list must be updated with the two targets' deps list below, and
# the list of _dsyms in :chrome_dsym_archive.
_chrome_symbols_sources = [
"$root_out_dir/$chrome_product_full_name.app/Contents/MacOS/$chrome_product_full_na
me",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.dylib",
_framework_binary_path,
]
if (build_with_internal_optimization_guide) {
_chrome_symbols_sources +=
[ "$root_out_dir/liboptimization_guide_internal.dylib" ]
}
foreach(helper_params, chrome_mac_helpers) {
_chrome_symbols_sources += [ "$root_out_dir/${chrome_helper_name}$
{helper_params[2]}.app/Contents/MacOS/${chrome_helper_name}${helper_params[2]}" ]
}
action_foreach("chrome_dump_syms") {
script = "//build/redirect_stdout.py"
sources = _chrome_symbols_sources
outputs =
[ "$root_out_dir/{{source_file_part}}-$chrome_version_full.breakpad" ]
dump_syms =
"//third_party/breakpad:dump_syms($host_system_allocator_toolchain)"
args = rebase_path(outputs, root_build_dir) + [
rebase_path(get_label_info(dump_syms, "root_out_dir") + "/" +
get_label_info(dump_syms, "name"),
root_build_dir),
"-d",
"-m",
"-g",
rebase_path(
"$root_out_dir/{{source_file_part}}.dSYM/Contents/Resources/DWARF/
{{source_file_part}}",
root_build_dir),
"{{source}}",
]
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
dump_syms,
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
}
action("chrome_dsym_archive") {
script = "//chrome/tools/build/mac/archive_symbols.py"
# These are the dSYMs that will be archived. The sources list must be
# the target outputs that correspond to the dSYMs (since a dSYM is a
# directory it cannot be listed as a source file). The targets that
# generate both the dSYM and binary image are listed in deps.
_dsyms = [
"$root_out_dir/$chrome_framework_name.dSYM",
"$root_out_dir/$chrome_product_full_name.dSYM",
"$root_out_dir/chrome_crashpad_handler.dSYM",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.[Link]",
]
if (build_with_internal_optimization_guide) {
_dsyms += [ "$root_out_dir/liboptimization_guide_internal.[Link]" ]
}
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
_dsyms +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.dSYM" ]
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
sources = _chrome_symbols_sources
_output = "$root_out_dir/$chrome_product_full_name.[Link].bz2"
outputs = [ _output ]
group("dependencies") {
public_deps = [
"//build:branding_buildflags",
"//build:chromeos_buildflags",
"//chrome/browser",
"//chrome/browser:buildflags",
"//chrome/browser:shell_integration",
"//chrome/browser/policy:path_parser",
"//chrome/child",
"//chrome/common",
"//chrome/gpu",
"//chrome/renderer",
"//chrome/utility",
"//components/crash/core/app",
"//components/devtools/devtools_pipe",
"//components/memory_system",
"//components/startup_metric_utils",
"//components/sync",
"//components/upload_list:upload_list",
"//components/webui/about",
"//content/public/child",
"//pdf",
"//services/tracing/public/cpp",
"//third_party/blink/public:blink_devtools_frontend_resources",
"//third_party/blink/public:blink_devtools_inspector_resources",
"//v8:v8_headers",
]
if (enable_ppapi) {
public_deps += [ "//ppapi/host" ]
}
if (enable_printing) {
public_deps += [ "//printing" ]
}
if (enable_nacl) {
public_deps += [
"//components/nacl/browser",
"//components/nacl/renderer/plugin:nacl_trusted_plugin",
]
}
if (is_chromeos) {
public_deps += [
"//ash/constants",
"//chrome/browser/ash/boot_times_recorder",
"//chrome/browser/ash/dbus",
"//chrome/browser/ash/schedqos",
"//chromeos/ash/components/memory",
"//chromeos/dbus/constants",
]
}
}
if (is_win) {
process_version_rc_template("chrome_exe_version") {
sources = [ "app/chrome_exe.ver" ]
output = "$target_gen_dir/chrome_exe_version.rc"
}
process_version_rc_template("chrome_dll_version") {
sources = [ "app/chrome_dll.ver" ]
output = "$target_gen_dir/chrome_dll_version.rc"
}
# This manifest matches what GYP produced. It may not even be necessary.
windows_manifest("chrome_dll_manifest") {
sources = [
as_invoker_manifest,
common_controls_manifest,
]
}
process_version_rc_template("other_version") {
sources = [ "app/[Link]" ]
output = "$target_gen_dir/other_version.rc"
}
}
copy("visual_elements_resources") {
sources = [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"app/visual_elements_resources/[Link]",
]
if (is_chrome_branded) {
sources += [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
group("resources") {
public_deps = [
"//chrome/browser:resources",
"//chrome/common:resources",
"//chrome/renderer:resources",
]
}
group("extra_resources") {
# Deps should be same as those in chrome_extra_paks() within chrome_paks.gni.
public_deps = [
"//chrome/browser/resources:resources",
"//components/autofill/core/browser:autofill_address_rewriter_resources",
]
}
target(_preinstalled_apps_target_type, "preinstalled_apps") {
visibility = [ ":packed_resources" ]
if (is_mac) {
visibility += [
":chrome_framework",
":chrome_framework_shared_library",
]
}
sources = [ "browser/resources/default_apps/external_extensions.json" ]
if (!is_mac) {
outputs = [ "$root_out_dir/default_apps/{{source_file_part}}" ]
} else {
outputs = [ "{{bundle_contents_dir}}/Default Apps/{{source_file_part}}" ]
}
# Force anybody that depends on this to get the default apps as data files.
data = process_file_template(sources, outputs)
}
}
if (!is_android) {
chrome_paks("packed_resources") {
if (is_mac) {
output_dir = "$root_gen_dir/repack"
copy_data_to_bundle = true
} else {
output_dir = root_out_dir
mark_as_data = true
}
if (enable_resource_allowlist_generation) {
repack_allowlist = _chrome_resource_allowlist
deps = [ ":resource_allowlist" ]
}
repack("browser_tests_pak") {
testonly = true
sources = [ "$root_gen_dir/chrome/webui_test_resources.pak" ]
output = "$root_out_dir/browser_tests.pak"
deps = [ "//chrome/test/data/webui:resources" ]
}
group("strings") {
public_deps = [
"//chrome/app:branded_strings",
"//chrome/app:generated_resources",
"//chrome/app/resources:locale_settings",
]
}
if (is_android) {
java_cpp_enum("offline_pages_enum_javagen") {
sources = [ "browser/offline_pages/offline_page_utils.h" ]
}
java_cpp_enum("download_enum_javagen") {
sources = [
"browser/download/android/download_open_source.h",
"browser/download/download_dialog_types.h",
"browser/download/download_prompt_status.h",
]
}
source_set("chrome_android_core") {
sources = [
"app/android/chrome_jni_onload.cc",
"app/android/chrome_jni_onload.h",
"app/android/chrome_main_delegate_android.cc",
"app/android/chrome_main_delegate_android.h",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
libs = [
"android",
"jnigraphics",
]
public_deps = [
"//chrome/browser",
"//chrome/utility",
]
deps = [
":dependencies",
"//chrome/browser/flags:flags_android",
"//chrome/browser/ui",
"//chrome/child",
"//chrome/common",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/gpu",
"//chrome/renderer",
"//components/crash/android:crash_android",
"//components/minidump_uploader",
"//components/safe_browsing:buildflags",
"//components/safe_browsing/android:safe_browsing_api_handler",
"//components/safe_browsing/android:safe_browsing_mobile",
"//components/stylus_handwriting/android",
"//components/variations:variations_associated_data",
"//content/public/app",
]
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
}
if (is_linux || is_chromeos) {
if (!(is_debug && use_debug_fission)) {
group("linux_symbols") {
deps = [
":angle_egl_symbols",
":angle_gles_symbols",
":chrome_crashpad_symbols",
":chrome_symbols",
]
if (is_linux) {
deps += [ ":swiftshader_vk_symbols" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
deps += [ ":angle_libvulkan_symbols" ]
}
if (build_with_internal_optimization_guide) {
deps += [ ":optimization_guide_symbols" ]
}
}
extract_symbols("chrome_symbols") {
binary = "$root_out_dir/chrome"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ ":chrome" ]
}
extract_symbols("chrome_crashpad_symbols") {
binary = "$root_out_dir/chrome_crashpad_handler"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ "//components/crash/core/app:chrome_crashpad_handler" ]
}
extract_symbols("swiftshader_vk_symbols") {
binary = "$root_out_dir/libvk_swiftshader.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.$current_cpu"
}
deps = [ "//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan" ]
}
extract_symbols("angle_egl_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libegl.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libegl.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libEGL" ]
}
extract_symbols("angle_gles_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libgles.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libgles.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libGLESv2" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
extract_symbols("angle_libvulkan_symbols") {
binary = "$root_out_dir/[Link].1"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.$current_cpu"
}
deps = [ "//third_party/vulkan-loader/src:libvulkan" ]
}
}
if (build_with_internal_optimization_guide) {
extract_symbols("optimization_guide_symbols") {
binary = "$root_out_dir/liboptimization_guide_internal.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.ia32"
} else {
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.$current_cpu"
}
deps = [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
}
}
# Copies some scripts and resources that are used for desktop integration.
copy("xdg_mime") {
sources = [
"//chrome/tools/build/linux/chrome-wrapper",
"//third_party/xdg-utils/scripts/xdg-mime",
"//third_party/xdg-utils/scripts/xdg-settings",
]
if (is_linux) {
sources += [
"//chrome/app/theme/$branding_path_component/linux/product_logo_48.png",
]
} else {
sources +=
[ "//chrome/app/theme/$branding_path_component/product_logo_48.png" ]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
}
if (_cros_generate_embed_section_target) {
embed_sections("section_embedded_chrome_binary") {
binary_input = "$root_out_dir/chrome"
sections_embedded_binary_output = "$root_out_dir/chrome.sections_embedded"
deps = [ ":chrome" ]
}
}
mport("//build/config/chrome_build.gni")
import("//build/config/chromeos/[Link]")
import("//build/config/chromeos/ui_mode.gni")
import("//build/config/compiler/[Link]")
import("//build/config/compiler/pgo/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/sanitizers/[Link]")
import("//build/config/[Link]")
import("//build/config/win/console_app.gni")
import("//build/config/win/[Link]")
import("//build/private_code_test/private_code_test.gni")
import("//build/toolchain/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/chrome_paks.gni")
import("//chrome/common/[Link]")
import("//chrome/process_version_rc_template.gni")
import("//components/nacl/[Link]")
import("//components/optimization_guide/[Link]")
import("//extensions/buildflags/[Link]")
import("//media/media_options.gni")
import("//ppapi/buildflags/[Link]")
import("//third_party/angle/gni/[Link]")
import("//third_party/blink/public/public_features.gni")
import("//third_party/widevine/cdm/[Link]")
import("//tools/resources/generate_resource_allowlist.gni")
import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
import("//ui/gl/[Link]")
import("//v8/gni/[Link]")
if (is_android) {
import("//build/config/android/[Link]")
} else if (is_linux || is_chromeos) {
import("//build/linux/extract_symbols.gni")
import("//build/linux/strip_binary.gni")
} else if (is_mac) {
import("//build/apple/compile_entitlements.gni")
import("//build/apple/compile_plist.gni")
import("//build/apple/tweak_info_plist.gni")
import("//build/compiled_action.gni")
import("//build/config/apple/[Link]")
import("//build/config/mac/mac_sdk.gni")
import("//build/config/mac/[Link]")
import("//build/util/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/updater/[Link]")
import("//chrome/[Link]")
import("//content/public/app/mac_helpers.gni")
import("//media/cdm/library_cdm/cdm_paths.gni")
import("//services/on_device_model/on_device_model.gni")
import("//third_party/icu/[Link]")
}
if (_cros_generate_embed_section_target) {
import("//build/chromeos/embed_sections.gni")
}
declare_args() {
# On macOS, `is_chrome_branded` builds that have been signed locally will not
# launch because certain entitlements are tied to the official Google code
# signing identity. If `include_branded_entitlements` is set to false, these
# entitlements will be skipped.
include_branded_entitlements = true
}
# initialexe/ is used so that the we can reorder imports and write back to
# the final destination at $root_out_dir/.
inputs = [
"$root_out_dir/initialexe/[Link]",
"$root_out_dir/initialexe/[Link]",
]
outputs = [
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
]
args = [
"-i",
rebase_path("$root_out_dir/initialexe", root_build_dir),
"-o",
rebase_path("$root_out_dir", root_build_dir),
"-a",
current_cpu,
]
deps = [ ":chrome_initial" ]
}
}
if (is_android) {
deps += [ "//chrome/android:chrome_public_apk" ]
} else {
deps += [ ":chrome" ]
}
if (is_win) {
deps += [ ":chrome_dll" ]
}
# This should not pull in installer strings. This is will bloat the binary
# for no reason and is easy to mess up. See the comment at the top of
# //chrome/installer/util/[Link].
assert_no_deps = [ "//chrome/installer/util:strings" ]
}
if (is_win) {
_chrome_output_name = "initialexe/chrome"
} else {
_chrome_output_name = "chrome"
}
executable("chrome_initial") {
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
output_name = _chrome_output_name
if (is_chromeos) {
data_deps += [
"//components/variations/cros_evaluate_seed:evaluate_seed",
"//sandbox/linux:chrome_sandbox",
]
if (build_mojo_proxy) {
data_deps += [ "//mojo/proxy:mojo_proxy" ]
}
deps += [
"//components/exo/wayland:test_controller_stub",
"//components/exo/wayland:ui_controls_protocol_stub",
]
}
if (is_win) {
sources += [
"app/chrome_exe.rc",
"app/chrome_exe_main_win.cc",
"app/delay_load_failure_hook_win.cc",
"app/delay_load_failure_hook_win.h",
"app/main_dll_loader_win.cc",
"app/main_dll_loader_win.h",
"common/crash_keys.cc",
"common/crash_keys.h",
]
deps += [
":chrome_dll",
":chrome_exe_version",
":copy_first_run",
":packed_resources_integrity_header",
":visual_elements_resources",
"//base",
"//build:branding_buildflags",
"//chrome/app:chrome_exe_main_exports",
"//chrome/app:exit_code_watcher",
"//chrome/app/version_assembly:chrome_exe_manifest",
"//chrome/browser:active_use_util",
"//chrome/browser:chrome_process_finder",
"//chrome/browser/policy:path_parser",
"//chrome/chrome_elf",
"//chrome/common:constants",
"//chrome/common/win:delay_load_failure_support",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//chrome/installer/util:constants",
"//chrome/installer/util:did_run_support",
"//components/crash/core/app",
"//components/crash/core/app:run_as_crashpad_handler",
"//components/crash/core/common",
"//components/crash/win:chrome_wer",
"//components/webui/flags:switches",
"//content:sandbox_helper_win",
"//content/public/common:static_switches",
"//crypto",
"//gpu/command_buffer/service",
"//sandbox",
"//sandbox/policy",
"//sandbox/policy/mojom",
"//third_party/breakpad:breakpad_handler",
"//third_party/breakpad:breakpad_sender",
"//third_party/crashpad/crashpad/util",
"//ui/gl",
]
data_deps = [
"//chrome/app/version_assembly:version_assembly_manifest",
"//chrome/browser/web_applications/chrome_pwa_launcher",
"//chrome/chrome_proxy",
"//chrome/elevation_service",
"//chrome/notification_helper",
"//chrome/windows_services/elevated_tracing_service",
]
if (enable_platform_experience) {
data_deps +=
[ "//chrome/browser/platform_experience/win:os_update_handler" ]
}
defines += [ "CHROME_EXE_MAIN" ]
if (win_console_app) {
defines += [ "WIN_CONSOLE_APP" ]
} else {
# Set /SUBSYSTEM:WINDOWS for [Link] itself, unless a console build
# has been requested.
configs -= [ "//build/config/win:console" ]
configs += [ "//build/config/win:windowed" ]
}
configs += [
"//build/config/win:delayloads",
"//build/config/win:delayloads_not_for_child_dll",
]
if (current_cpu == "x86") {
# Set the initial stack size to 0.5MiB, instead of the 1.5MiB needed by
# Chrome's main thread. This saves significant memory on threads (like
# those in the Windows thread pool, and others) whose stack size we can
# only control through this setting. Because Chrome's main thread needs
# a minimum 1.5 MiB stack, the main thread (in 32-bit builds only) uses
# fibers to switch to a 1.5 MiB stack before running any other code.
ldflags = [ "/STACK:0x80000" ]
} else {
# Increase the initial stack size. The default is 1MB, this is 8MB.
ldflags = [ "/STACK:0x800000" ]
}
} else if (use_aura) {
# Non-Windows aura entrypoint.
sources += [ "app/chrome_exe_main_aura.cc" ]
}
if (is_linux || is_chromeos) {
sources += [
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
deps += [
# On Linux, link the dependencies (libraries) that make up actual
# Chromium functionality directly into the executable.
":dependencies",
"//chrome/common:version_header",
public_deps = [
":xdg_mime", # Needs to be public for installer to consume files.
"//chrome/common:buildflags",
]
data_deps += [ "//components/crash/core/app:chrome_crashpad_handler" ]
ldflags = []
# Chrome OS debug builds for arm need to pass --long-plt to the linker.
# See [Link]
if (is_chromeos && is_debug && target_cpu == "arm") {
ldflags += [ "-Wl,--long-plt" ]
}
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [
"//chrome/browser/ash/locale",
"//chrome/browser/ash/schedqos",
]
}
if (use_ozone) {
deps += [ "//ui/ozone" ]
if (is_linux) {
deps += [ "//ui/linux:display_server_utils" ]
}
}
}
data_deps += [
"//chrome/browser/resources/media/mei_preload:component",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component",
"//third_party/widevine/cdm",
]
if (is_linux) {
sources += [
"app/chrome_main_linux.cc",
"app/chrome_main_linux.h",
]
}
}
if (is_win) {
shared_library("chrome_dll") {
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
defines = []
sources = [
"//base/win/[Link]",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
output_name = "chrome"
deps = [
":chrome_dll_manifest",
":chrome_dll_version",
":dependencies",
"//chrome/app:chrome_dll_resources",
"//chrome/app:command_ids",
"//chrome/app/theme:chrome_unscaled_resources",
"//chrome/chrome_elf",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//crypto",
"//headless:headless_non_renderer",
"//headless:headless_shell_browser_lib",
"//net:net_resources",
"//ppapi/buildflags",
"//sandbox/win:sandbox",
"//third_party/cld_3/src/src:cld_3",
"//third_party/wtl",
"//ui/views",
]
configs += [ "//build/config/win:delayloads" ]
if (use_aura) {
deps += [ "//ui/compositor" ]
}
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
copy("copy_first_run") {
sources = [ "app/FirstRun" ]
outputs = [ "$root_out_dir/First Run" ]
}
} else if (is_mac) {
chrome_helper_name = chrome_product_full_name + " Helper"
chrome_framework_name = chrome_product_full_name + " Framework"
chrome_framework_version = chrome_version_full
group("chrome") {
deps = [ ":chrome_app" ]
data_deps = [ ":chrome_app" ]
if (verify_dynamic_libraries) {
deps += [ ":verify_libraries_chrome_app" ]
}
tweak_info_plist("chrome_app_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--scm=1",
"--bundle_id=$chrome_mac_bundle_id",
]
if (enable_updater) {
args += [ "--privileged_helper_id=$privileged_helper_name" ]
if (is_chrome_branded) {
args += [ "--keystone=1" ]
if (current_cpu == "arm64") {
args += [ "--keystone-base-tag=arm64" ]
}
} else {
args += [ "--keystone=0" ]
}
} else {
args += [ "--keystone=0" ]
}
}
mac_app_bundle("chrome_app") {
output_name = chrome_product_full_name
info_plist_target = ":chrome_app_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_CREATOR=$chrome_mac_creator_code",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
":chrome_app_strings_bundle_data",
":chrome_resources",
":chrome_versioned_bundle_data",
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:buildflags",
"//chrome/common:version_header",
]
if (enable_updater) {
deps += [ ":chromium_updater_privileged_helper" ]
}
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags = [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link" ]
ldflags = [ "-Wl,-rpath,@executable_path/../Frameworks" ]
# The Framework is packaged inside the .app bundle. But when using the
# component build, all the dependent shared libraries of :chrome_dll are
# not packaged within the framework. This data_deps line makes all of
# those dependent libraries runtime dependencies of the .app bundle.
# This is a bit of a hack, since GN deliberately terminates its search
# for runtime_deps at create_bundle nodes ([Link]
data_deps = [ ":chrome_framework" ]
}
}
if (verify_dynamic_libraries) {
action("verify_libraries_chrome_app") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [ "${root_out_dir}/${chrome_product_full_name}.app/Contents/MacOS/$
{chrome_product_full_name}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
"--allow",
"/usr/lib/[Link]",
]
deps = [ ":chrome_app" ]
}
}
compiled_action("chrome_app_strings") {
tool = "//chrome/tools/build/mac:infoplist_strings_util"
inputs = []
outputs = []
foreach(locale, platform_pak_locales) {
inputs += [ "$root_gen_dir/chrome/branded_strings_${locale}.pak" ]
}
foreach(locale, locales_as_apple_outputs) {
outputs += [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
}
args =
[
"-b",
"branded_strings",
"-v",
chrome_version_full,
"-g",
rebase_path("$root_gen_dir/chrome", root_build_dir),
"-o",
rebase_path("$target_gen_dir/app_infoplist_strings", root_build_dir),
"-t",
"main",
] + platform_pak_locales
deps = [ "//chrome/app:branded_strings" ]
}
foreach(locale, locales_as_apple_outputs) {
bundle_data("chrome_app_strings_${locale}_bundle_data") {
sources = [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
outputs =
[ "{{bundle_resources_dir}}/$[Link]/{{source_file_part}}" ]
public_deps = [ ":chrome_app_strings" ]
}
}
group("chrome_app_strings_bundle_data") {
public_deps = []
foreach(locale, locales_as_apple_outputs) {
public_deps += [ ":chrome_app_strings_${locale}_bundle_data" ]
}
}
bundle_data("chrome_app_icon") {
sources = [ "app/theme/$branding_path_component/mac/[Link]" ]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
}
bundle_data("chrome_resources") {
sources = [
"$root_out_dir/$chrome_mac_bundle_id.manifest",
"app/theme/$branding_path_component/mac/[Link]",
"browser/ui/cocoa/applescript/[Link]",
]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":chrome_app_icon",
":chrome_app_strings",
"//components/policy:chrome_manifest_bundle",
]
}
bundle_data("chrome_versioned_bundle_data") {
sources = [ "$root_out_dir/$chrome_framework_name.framework" ]
outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
public_deps = [
# Before bundling the versioned app components, delete any existing
# versions.
":clean_up_old_versions",
if (enable_widevine_cdm_host_verification) {
# The :chrome_framework_widevine_signature target copies into the
# :chrome_framework bundle. But because the signing file depends on the
# framework itself, that would cause a cyclical dependency. Instead,
# this dependency directly copies the file into the framework's
# resources directory.
public_deps += [ ":chrome_framework_widevine_signature" ]
}
}
if (enable_updater) {
bundle_data("chromium_updater_privileged_helper") {
sources = [ "$root_out_dir/$privileged_helper_name" ]
outputs = [
"{{bundle_contents_dir}}/Library/LaunchServices/{{source_file_part}}",
]
public_deps = [ "//chrome/updater/mac:privileged_helper" ]
}
}
action("clean_up_old_versions") {
script = "//chrome/tools/build/mac/clean_up_old_versions.py"
_stamp_file = "$root_gen_dir/run_$target_name.stamp"
outputs = [ _stamp_file ]
_versions_dir =
"$root_out_dir/$chrome_product_full_name.app/Contents/Frameworks/$chrome_framework_
[Link]/Versions"
args = [
"--versions-dir",
rebase_path(_versions_dir, root_build_dir),
"--stamp",
rebase_path(_stamp_file, root_build_dir),
"--keep",
chrome_framework_version,
"--keep",
"Current",
]
}
tweak_info_plist("chrome_helper_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=0",
]
}
compile_entitlements("entitlements") {
entitlements_templates = [ "app/[Link]" ]
if (is_chrome_branded && include_branded_entitlements) {
# These entitlements are bound to the official Google Chrome signing
# certificate and will not necessarily work in any other build.
entitlements_templates += [ "app/[Link]" ]
}
output_name = "$target_gen_dir/[Link]"
substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_TEAM_ID=$chrome_mac_team_id",
]
visibility = [ "//chrome/installer/mac:copies" ]
}
template("chrome_helper_app") {
mac_app_bundle(target_name) {
assert(defined(invoker.helper_name_suffix))
assert(defined(invoker.helper_bundle_id_suffix))
if (defined(invoker.info_plist_target)) {
info_plist_target = invoker.info_plist_target
} else {
info_plist_target = ":chrome_helper_plist"
}
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_HELPER_SUFFIX=${invoker.helper_name_suffix}",
"CHROMIUM_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
defines = [ "HELPER_EXECUTABLE" ]
deps = [
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:version_header",
"//sandbox/mac:seatbelt",
]
if (defined([Link])) {
deps += [Link]
}
ldflags = []
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link_nested" ]
ldflags += [
# The helper is in [Link]/Contents/Frameworks/Chromium
[Link]/Versions/X/Helpers/Chromium [Link]/Contents/MacOS
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags += [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
}
}
# Create app for the alert helper manually here as we want to modify the plist
# to set the alert style and add the app icon to its resources.
tweak_info_plist("chrome_helper_app_alerts_plist") {
deps = [ ":chrome_helper_plist" ]
info_plists = get_target_outputs(":chrome_helper_plist") +
[ "app/[Link]" ]
}
# Create and bundle an [Link] for the alert helper app.
# TODO([Link]/40751430): Disambiguate and localize alert helper app name.
compile_plist("chrome_helper_app_alerts_plist_strings") {
format = "binary1"
plist_templates = [ "app/[Link]" ]
substitutions = [ "CHROMIUM_FULL_NAME=$chrome_product_full_name" ]
output_name =
"$target_gen_dir/helper_alerts_infoplist_strings/[Link]/[Link]"
}
bundle_data("chrome_helper_app_alerts_resources") {
sources = get_target_outputs(":chrome_helper_app_alerts_plist_strings")
outputs = [ "{{bundle_resources_dir}}/[Link]/{{source_file_part}}" ]
public_deps = [ ":chrome_helper_app_alerts_plist_strings" ]
}
chrome_helper_app("chrome_helper_app_${alert_helper_params[0]}") {
helper_name_suffix = alert_helper_params[2]
helper_bundle_id_suffix = alert_helper_params[1]
info_plist_target = ":chrome_helper_app_alerts_plist"
deps = [
":chrome_app_icon",
":chrome_helper_app_alerts_resources",
]
}
if (verify_dynamic_libraries) {
foreach(helper_params, chrome_mac_helpers) {
_helper_target = helper_params[0]
_helper_bundle_id = helper_params[1]
_helper_suffix = helper_params[2]
action("verify_libraries_chrome_helper_app_${_helper_target}") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [
"${root_out_dir}/${chrome_helper_name}${_helper_suffix}.app/Contents/MacOS/$
{chrome_helper_name}${_helper_suffix}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
bundle_data("chrome_framework_helpers") {
sources = [
"$root_out_dir/app_mode_loader",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/web_app_shortcut_copier",
]
outputs = [ "{{bundle_contents_dir}}/Helpers/{{source_file_part}}" ]
public_deps = [
"//chrome/app_shim:app_mode_loader",
"//chrome/browser/web_applications/os_integration/mac:web_app_shortcut_copier",
"//components/crash/core/app:chrome_crashpad_handler",
]
foreach(helper_params, chrome_mac_helpers) {
sources +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.app" ]
public_deps += [ ":chrome_helper_app_${helper_params[0]}" ]
if (verify_dynamic_libraries) {
public_deps +=
[ ":verify_libraries_chrome_helper_app_${helper_params[0]}" ]
}
}
if (enable_updater) {
if (is_chrome_branded) {
sources += [ "//third_party/updater/chrome_mac_universal_prod/cipd/$
{updater_product_full_name}.app" ]
} else {
sources += [ "$root_out_dir/${updater_product_full_name}.app" ]
public_deps += [
"//chrome/updater/mac:browser_install_script",
"//chrome/updater/mac:updater_bundle",
"//chrome/updater/mac:updater_install_script",
]
}
}
}
bundle_data("chrome_framework_resources") {
sources = [
"//ui/gl/resources/angle-metal/gpu_shader_cache.bin",
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":packed_resources",
"//chrome/app_shim:app_mode_loader_plist_bundle_data",
"//chrome/browser/mac:install",
]
if (icu_use_data_file) {
sources += [ "$root_out_dir/[Link]" ]
public_deps += [ "//third_party/icu:icudata" ]
}
if (v8_use_external_startup_data) {
public_deps += [ "//v8" ]
if (use_v8_context_snapshot) {
sources += [ "$root_out_dir/$v8_context_snapshot_filename" ]
public_deps += [ "//tools/v8_context_snapshot" ]
}
if (!use_v8_context_snapshot || include_both_v8_snapshots) {
sources += [ "$root_out_dir/snapshot_blob.bin" ]
}
}
}
if (enable_nacl) {
bundle_data("chrome_framework_plugins") {
sources = []
outputs =
[ "{{bundle_contents_dir}}/Internet Plug-Ins/{{source_file_part}}" ]
public_deps = []
if (enable_nacl) {
if (current_cpu == "x86") {
sources += [ "$root_out_dir/nacl_irt_x86_32.nexe" ]
} else if (current_cpu == "x64") {
sources += [ "$root_out_dir/nacl_irt_x86_64.nexe" ]
}
public_deps += [ "//ppapi/native_client:irt" ]
}
}
} else {
group("chrome_framework_plugins") {
}
}
if (bundle_widevine_cdm) {
bundle_data("widevine_cdm_library_binaries") {
sources = [ "$root_out_dir/$widevine_cdm_path/[Link]" ]
if (enable_widevine_cdm_host_verification) {
sources +=
[ "$root_out_dir/$widevine_cdm_path/[Link]" ]
}
outputs = [
"{{bundle_contents_dir}}/Libraries/$widevine_cdm_path/{{source_file_part}}" ]
public_deps = [ "//third_party/widevine/cdm" ]
}
bundle_data("widevine_cdm_library_manifest_and_license_files") {
sources = [
"$root_out_dir/WidevineCdm/LICENSE",
"$root_out_dir/WidevineCdm/[Link]",
]
outputs = [
"{{bundle_contents_dir}}/Libraries/WidevineCdm/{{source_file_part}}",
]
public_deps = [ "//third_party/widevine/cdm" ]
}
}
group("widevine_cdm_library") {
if (bundle_widevine_cdm) {
deps = [
":widevine_cdm_library_binaries",
":widevine_cdm_library_manifest_and_license_files",
]
}
}
if (enable_widevine_cdm_host_verification) {
widevine_sign_file("sign_chrome_framework_for_widevine") {
file =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
flags = 1
signature_file = "$root_out_dir/$chrome_framework_name.sig"
deps = [ ":chrome_framework" ]
}
copy("chrome_framework_widevine_signature") {
deps = [ ":sign_chrome_framework_for_widevine" ]
sources = [ "$root_out_dir/$chrome_framework_name.sig" ]
outputs = [
"$root_out_dir/$chrome_framework_name.framework/Resources/{{source_file_part}}" ]
}
}
if (build_with_internal_optimization_guide) {
# Add the optimization guide .dylib in the MODULE_DIR of [Link]
bundle_data("optimization_guide_library") {
sources = [
"$root_out_dir/og_intermediates/liboptimization_guide_internal.dylib",
]
outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ]
public_deps = [
"//components/optimization_guide/core:optimization_guide_internal_library_copy" ]
}
} else {
group("optimization_guide_library") {
}
}
tweak_info_plist("chrome_framework_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=1",
"--branding",
chrome_product_short_name,
]
}
sources = [
"app/chrome_crash_reporter_client.cc",
"app/chrome_crash_reporter_client.h",
"app/chrome_crash_reporter_client_mac.mm",
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/chrome_main_mac.h",
"app/chrome_main_mac.mm",
"app/startup_timestamps.h",
]
deps = [
":dependencies",
"//build:chromeos_buildflags",
"//chrome/app:command_ids",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//headless:headless_shell_lib",
"//third_party/cld_3/src/src:cld_3",
]
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
if (is_component_build) {
frameworks = [ "[Link]" ]
}
ldflags = [ "-ObjC" ]
configs += [
":chrome_dll_symbol_order",
"//build/config/compiler:wexit_time_destructors",
]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
}
mac_framework_bundle("chrome_framework") {
output_name = chrome_framework_name
framework_version = chrome_framework_version
framework_contents = [
"Helpers",
"Libraries",
"Resources",
]
if (is_chrome_branded) {
framework_contents += [ "Default Apps" ]
}
if (enable_nacl) {
framework_contents += [ "Internet Plug-Ins" ]
}
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
info_plist_target = ":chrome_framework_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
]
public_deps = [ ":chrome_dll" ]
bundle_deps = [
":angle_binaries",
":chrome_framework_helpers",
":chrome_framework_plugins",
":chrome_framework_resources",
":optimization_guide_library",
":swiftshader_binaries",
":widevine_cdm_library",
"//chrome/browser/resources/media/mei_preload:component_bundle",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component_bundle",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component_bundle
",
]
if (is_chrome_branded) {
bundle_deps += [ ":preinstalled_apps" ]
}
configs += [ ":chrome_dll_symbol_order" ]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
ldflags = [
"-compatibility_version",
chrome_dylib_version,
"-current_version",
chrome_dylib_version,
]
if (!is_component_build) {
# Specify a sensible install_name for static builds. The library is
# dlopen()ed so this is not used to resolve the module.
ldflags += [
"-Wl,-install_name,@executable_path/../Frameworks/$chrome_framework_name.framework/
Versions/$chrome_framework_version/$chrome_framework_name" ]
} else {
# In the component build, both the :chrome_app and various
# :chrome_helper* targets directly link to the Framework target. Use
# @rpath-based loading so that the dylib ID does not have to be changed
# with install_name_tool.
ldflags += [
"-Wl,-install_name,@rpath/$chrome_framework_name.framework/$chrome_framework_name",
"-Wl,-rpath,@loader_path/../../../../../..",
"-Wl,-reexport_library,libchrome_dll.dylib",
]
data_deps = [ ":chrome_dll" ]
}
}
_framework_binary_path =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
assert(_framework_binary_path != "",
"Ignore configuration-dependent unused variable warning")
# This list must be updated with the two targets' deps list below, and
# the list of _dsyms in :chrome_dsym_archive.
_chrome_symbols_sources = [
"$root_out_dir/$chrome_product_full_name.app/Contents/MacOS/$chrome_product_full_na
me",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.dylib",
_framework_binary_path,
]
if (build_with_internal_optimization_guide) {
_chrome_symbols_sources +=
[ "$root_out_dir/liboptimization_guide_internal.dylib" ]
}
foreach(helper_params, chrome_mac_helpers) {
_chrome_symbols_sources += [ "$root_out_dir/${chrome_helper_name}$
{helper_params[2]}.app/Contents/MacOS/${chrome_helper_name}${helper_params[2]}" ]
}
action_foreach("chrome_dump_syms") {
script = "//build/redirect_stdout.py"
sources = _chrome_symbols_sources
outputs =
[ "$root_out_dir/{{source_file_part}}-$chrome_version_full.breakpad" ]
dump_syms =
"//third_party/breakpad:dump_syms($host_system_allocator_toolchain)"
args = rebase_path(outputs, root_build_dir) + [
rebase_path(get_label_info(dump_syms, "root_out_dir") + "/" +
get_label_info(dump_syms, "name"),
root_build_dir),
"-d",
"-m",
"-g",
rebase_path(
"$root_out_dir/{{source_file_part}}.dSYM/Contents/Resources/DWARF/
{{source_file_part}}",
root_build_dir),
"{{source}}",
]
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
dump_syms,
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
}
action("chrome_dsym_archive") {
script = "//chrome/tools/build/mac/archive_symbols.py"
# These are the dSYMs that will be archived. The sources list must be
# the target outputs that correspond to the dSYMs (since a dSYM is a
# directory it cannot be listed as a source file). The targets that
# generate both the dSYM and binary image are listed in deps.
_dsyms = [
"$root_out_dir/$chrome_framework_name.dSYM",
"$root_out_dir/$chrome_product_full_name.dSYM",
"$root_out_dir/chrome_crashpad_handler.dSYM",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.[Link]",
]
if (build_with_internal_optimization_guide) {
_dsyms += [ "$root_out_dir/liboptimization_guide_internal.[Link]" ]
}
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
_dsyms +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.dSYM" ]
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
sources = _chrome_symbols_sources
_output = "$root_out_dir/$chrome_product_full_name.[Link].bz2"
outputs = [ _output ]
group("dependencies") {
public_deps = [
"//build:branding_buildflags",
"//build:chromeos_buildflags",
"//chrome/browser",
"//chrome/browser:buildflags",
"//chrome/browser:shell_integration",
"//chrome/browser/policy:path_parser",
"//chrome/child",
"//chrome/common",
"//chrome/gpu",
"//chrome/renderer",
"//chrome/utility",
"//components/crash/core/app",
"//components/devtools/devtools_pipe",
"//components/memory_system",
"//components/startup_metric_utils",
"//components/sync",
"//components/upload_list:upload_list",
"//components/webui/about",
"//content/public/child",
"//pdf",
"//services/tracing/public/cpp",
"//third_party/blink/public:blink_devtools_frontend_resources",
"//third_party/blink/public:blink_devtools_inspector_resources",
"//v8:v8_headers",
]
if (enable_ppapi) {
public_deps += [ "//ppapi/host" ]
}
if (enable_printing) {
public_deps += [ "//printing" ]
}
if (enable_nacl) {
public_deps += [
"//components/nacl/browser",
"//components/nacl/renderer/plugin:nacl_trusted_plugin",
]
}
if (is_chromeos) {
public_deps += [
"//ash/constants",
"//chrome/browser/ash/boot_times_recorder",
"//chrome/browser/ash/dbus",
"//chrome/browser/ash/schedqos",
"//chromeos/ash/components/memory",
"//chromeos/dbus/constants",
]
}
}
if (is_win) {
process_version_rc_template("chrome_exe_version") {
sources = [ "app/chrome_exe.ver" ]
output = "$target_gen_dir/chrome_exe_version.rc"
}
process_version_rc_template("chrome_dll_version") {
sources = [ "app/chrome_dll.ver" ]
output = "$target_gen_dir/chrome_dll_version.rc"
}
# This manifest matches what GYP produced. It may not even be necessary.
windows_manifest("chrome_dll_manifest") {
sources = [
as_invoker_manifest,
common_controls_manifest,
]
}
process_version_rc_template("other_version") {
sources = [ "app/[Link]" ]
output = "$target_gen_dir/other_version.rc"
}
}
copy("visual_elements_resources") {
sources = [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"app/visual_elements_resources/[Link]",
]
if (is_chrome_branded) {
sources += [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
group("resources") {
public_deps = [
"//chrome/browser:resources",
"//chrome/common:resources",
"//chrome/renderer:resources",
]
}
group("extra_resources") {
# Deps should be same as those in chrome_extra_paks() within chrome_paks.gni.
public_deps = [
"//chrome/browser/resources:resources",
"//components/autofill/core/browser:autofill_address_rewriter_resources",
]
}
if (is_chrome_branded && !is_android) {
if (!is_mac) {
_preinstalled_apps_target_type = "copy"
} else {
_preinstalled_apps_target_type = "bundle_data"
}
target(_preinstalled_apps_target_type, "preinstalled_apps") {
visibility = [ ":packed_resources" ]
if (is_mac) {
visibility += [
":chrome_framework",
":chrome_framework_shared_library",
]
}
sources = [ "browser/resources/default_apps/external_extensions.json" ]
if (!is_mac) {
outputs = [ "$root_out_dir/default_apps/{{source_file_part}}" ]
} else {
outputs = [ "{{bundle_contents_dir}}/Default Apps/{{source_file_part}}" ]
}
# Force anybody that depends on this to get the default apps as data files.
data = process_file_template(sources, outputs)
}
}
if (!is_android) {
chrome_paks("packed_resources") {
if (is_mac) {
output_dir = "$root_gen_dir/repack"
copy_data_to_bundle = true
} else {
output_dir = root_out_dir
mark_as_data = true
}
if (enable_resource_allowlist_generation) {
repack_allowlist = _chrome_resource_allowlist
deps = [ ":resource_allowlist" ]
}
repack("browser_tests_pak") {
testonly = true
sources = [ "$root_gen_dir/chrome/webui_test_resources.pak" ]
output = "$root_out_dir/browser_tests.pak"
deps = [ "//chrome/test/data/webui:resources" ]
}
group("strings") {
public_deps = [
"//chrome/app:branded_strings",
"//chrome/app:generated_resources",
"//chrome/app/resources:locale_settings",
]
}
if (is_android) {
java_cpp_enum("offline_pages_enum_javagen") {
sources = [ "browser/offline_pages/offline_page_utils.h" ]
}
java_cpp_enum("download_enum_javagen") {
sources = [
"browser/download/android/download_open_source.h",
"browser/download/download_dialog_types.h",
"browser/download/download_prompt_status.h",
]
}
source_set("chrome_android_core") {
sources = [
"app/android/chrome_jni_onload.cc",
"app/android/chrome_jni_onload.h",
"app/android/chrome_main_delegate_android.cc",
"app/android/chrome_main_delegate_android.h",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
libs = [
"android",
"jnigraphics",
]
public_deps = [
"//chrome/browser",
"//chrome/utility",
]
deps = [
":dependencies",
"//chrome/browser/flags:flags_android",
"//chrome/browser/ui",
"//chrome/child",
"//chrome/common",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/gpu",
"//chrome/renderer",
"//components/crash/android:crash_android",
"//components/minidump_uploader",
"//components/safe_browsing:buildflags",
"//components/safe_browsing/android:safe_browsing_api_handler",
"//components/safe_browsing/android:safe_browsing_mobile",
"//components/stylus_handwriting/android",
"//components/variations:variations_associated_data",
"//content/public/app",
]
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
}
if (is_linux || is_chromeos) {
if (!(is_debug && use_debug_fission)) {
group("linux_symbols") {
deps = [
":angle_egl_symbols",
":angle_gles_symbols",
":chrome_crashpad_symbols",
":chrome_symbols",
]
if (is_linux) {
deps += [ ":swiftshader_vk_symbols" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
deps += [ ":angle_libvulkan_symbols" ]
}
if (build_with_internal_optimization_guide) {
deps += [ ":optimization_guide_symbols" ]
}
}
extract_symbols("chrome_symbols") {
binary = "$root_out_dir/chrome"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ ":chrome" ]
}
extract_symbols("chrome_crashpad_symbols") {
binary = "$root_out_dir/chrome_crashpad_handler"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ "//components/crash/core/app:chrome_crashpad_handler" ]
}
extract_symbols("swiftshader_vk_symbols") {
binary = "$root_out_dir/libvk_swiftshader.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.$current_cpu"
}
deps = [ "//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan" ]
}
extract_symbols("angle_egl_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libegl.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libegl.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libEGL" ]
}
extract_symbols("angle_gles_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libgles.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libgles.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libGLESv2" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
extract_symbols("angle_libvulkan_symbols") {
binary = "$root_out_dir/[Link].1"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.$current_cpu"
}
deps = [ "//third_party/vulkan-loader/src:libvulkan" ]
}
}
if (build_with_internal_optimization_guide) {
extract_symbols("optimization_guide_symbols") {
binary = "$root_out_dir/liboptimization_guide_internal.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.ia32"
} else {
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.$current_cpu"
}
deps = [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
}
}
# Copies some scripts and resources that are used for desktop integration.
copy("xdg_mime") {
sources = [
"//chrome/tools/build/linux/chrome-wrapper",
"//third_party/xdg-utils/scripts/xdg-mime",
"//third_party/xdg-utils/scripts/xdg-settings",
]
if (is_linux) {
sources += [
"//chrome/app/theme/$branding_path_component/linux/product_logo_48.png",
]
} else {
sources +=
[ "//chrome/app/theme/$branding_path_component/product_logo_48.png" ]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
}
if (_cros_generate_embed_section_target) {
embed_sections("section_embedded_chrome_binary") {
binary_input = "$root_out_dir/chrome"
sections_embedded_binary_output = "$root_out_dir/chrome.sections_embedded"
deps = [ ":chrome" ]
}
}
mport("//build/config/chrome_build.gni")
import("//build/config/chromeos/[Link]")
import("//build/config/chromeos/ui_mode.gni")
import("//build/config/compiler/[Link]")
import("//build/config/compiler/pgo/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/[Link]")
import("//build/config/sanitizers/[Link]")
import("//build/config/[Link]")
import("//build/config/win/console_app.gni")
import("//build/config/win/[Link]")
import("//build/private_code_test/private_code_test.gni")
import("//build/toolchain/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/chrome_paks.gni")
import("//chrome/common/[Link]")
import("//chrome/process_version_rc_template.gni")
import("//components/nacl/[Link]")
import("//components/optimization_guide/[Link]")
import("//extensions/buildflags/[Link]")
import("//media/media_options.gni")
import("//ppapi/buildflags/[Link]")
import("//third_party/angle/gni/[Link]")
import("//third_party/blink/public/public_features.gni")
import("//third_party/widevine/cdm/[Link]")
import("//tools/resources/generate_resource_allowlist.gni")
import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
import("//ui/gl/[Link]")
import("//v8/gni/[Link]")
if (is_android) {
import("//build/config/android/[Link]")
} else if (is_linux || is_chromeos) {
import("//build/linux/extract_symbols.gni")
import("//build/linux/strip_binary.gni")
} else if (is_mac) {
import("//build/apple/compile_entitlements.gni")
import("//build/apple/compile_plist.gni")
import("//build/apple/tweak_info_plist.gni")
import("//build/compiled_action.gni")
import("//build/config/apple/[Link]")
import("//build/config/mac/mac_sdk.gni")
import("//build/config/mac/[Link]")
import("//build/util/[Link]")
import("//chrome/browser/[Link]")
import("//chrome/updater/[Link]")
import("//chrome/[Link]")
import("//content/public/app/mac_helpers.gni")
import("//media/cdm/library_cdm/cdm_paths.gni")
import("//services/on_device_model/on_device_model.gni")
import("//third_party/icu/[Link]")
}
if (_cros_generate_embed_section_target) {
import("//build/chromeos/embed_sections.gni")
}
declare_args() {
# On macOS, `is_chrome_branded` builds that have been signed locally will not
# launch because certain entitlements are tied to the official Google code
# signing identity. If `include_branded_entitlements` is set to false, these
# entitlements will be skipped.
include_branded_entitlements = true
}
if (is_win) {
action("reorder_imports") {
script = "//build/win/[Link]"
# initialexe/ is used so that the we can reorder imports and write back to
# the final destination at $root_out_dir/.
inputs = [
"$root_out_dir/initialexe/[Link]",
"$root_out_dir/initialexe/[Link]",
]
outputs = [
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
]
args = [
"-i",
rebase_path("$root_out_dir/initialexe", root_build_dir),
"-o",
rebase_path("$root_out_dir", root_build_dir),
"-a",
current_cpu,
]
deps = [ ":chrome_initial" ]
}
}
if (is_android) {
deps += [ "//chrome/android:chrome_public_apk" ]
} else {
deps += [ ":chrome" ]
}
if (is_win) {
deps += [ ":chrome_dll" ]
}
# This should not pull in installer strings. This is will bloat the binary
# for no reason and is easy to mess up. See the comment at the top of
# //chrome/installer/util/[Link].
assert_no_deps = [ "//chrome/installer/util:strings" ]
}
if (is_win) {
_chrome_output_name = "initialexe/chrome"
} else {
_chrome_output_name = "chrome"
}
executable("chrome_initial") {
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
output_name = _chrome_output_name
if (is_chromeos) {
data_deps += [
"//components/variations/cros_evaluate_seed:evaluate_seed",
"//sandbox/linux:chrome_sandbox",
]
if (build_mojo_proxy) {
data_deps += [ "//mojo/proxy:mojo_proxy" ]
}
deps += [
"//components/exo/wayland:test_controller_stub",
"//components/exo/wayland:ui_controls_protocol_stub",
]
}
if (is_win) {
sources += [
"app/chrome_exe.rc",
"app/chrome_exe_main_win.cc",
"app/delay_load_failure_hook_win.cc",
"app/delay_load_failure_hook_win.h",
"app/main_dll_loader_win.cc",
"app/main_dll_loader_win.h",
"common/crash_keys.cc",
"common/crash_keys.h",
]
deps += [
":chrome_dll",
":chrome_exe_version",
":copy_first_run",
":packed_resources_integrity_header",
":visual_elements_resources",
"//base",
"//build:branding_buildflags",
"//chrome/app:chrome_exe_main_exports",
"//chrome/app:exit_code_watcher",
"//chrome/app/version_assembly:chrome_exe_manifest",
"//chrome/browser:active_use_util",
"//chrome/browser:chrome_process_finder",
"//chrome/browser/policy:path_parser",
"//chrome/chrome_elf",
"//chrome/common:constants",
"//chrome/common/win:delay_load_failure_support",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//chrome/installer/util:constants",
"//chrome/installer/util:did_run_support",
"//components/crash/core/app",
"//components/crash/core/app:run_as_crashpad_handler",
"//components/crash/core/common",
"//components/crash/win:chrome_wer",
"//components/webui/flags:switches",
"//content:sandbox_helper_win",
"//content/public/common:static_switches",
"//crypto",
"//gpu/command_buffer/service",
"//sandbox",
"//sandbox/policy",
"//sandbox/policy/mojom",
"//third_party/breakpad:breakpad_handler",
"//third_party/breakpad:breakpad_sender",
"//third_party/crashpad/crashpad/util",
"//ui/gl",
]
data_deps = [
"//chrome/app/version_assembly:version_assembly_manifest",
"//chrome/browser/web_applications/chrome_pwa_launcher",
"//chrome/chrome_proxy",
"//chrome/elevation_service",
"//chrome/notification_helper",
"//chrome/windows_services/elevated_tracing_service",
]
if (enable_platform_experience) {
data_deps +=
[ "//chrome/browser/platform_experience/win:os_update_handler" ]
}
defines += [ "CHROME_EXE_MAIN" ]
if (win_console_app) {
defines += [ "WIN_CONSOLE_APP" ]
} else {
# Set /SUBSYSTEM:WINDOWS for [Link] itself, unless a console build
# has been requested.
configs -= [ "//build/config/win:console" ]
configs += [ "//build/config/win:windowed" ]
}
configs += [
"//build/config/win:delayloads",
"//build/config/win:delayloads_not_for_child_dll",
]
if (current_cpu == "x86") {
# Set the initial stack size to 0.5MiB, instead of the 1.5MiB needed by
# Chrome's main thread. This saves significant memory on threads (like
# those in the Windows thread pool, and others) whose stack size we can
# only control through this setting. Because Chrome's main thread needs
# a minimum 1.5 MiB stack, the main thread (in 32-bit builds only) uses
# fibers to switch to a 1.5 MiB stack before running any other code.
ldflags = [ "/STACK:0x80000" ]
} else {
# Increase the initial stack size. The default is 1MB, this is 8MB.
ldflags = [ "/STACK:0x800000" ]
}
} else if (use_aura) {
# Non-Windows aura entrypoint.
sources += [ "app/chrome_exe_main_aura.cc" ]
}
if (is_linux || is_chromeos) {
sources += [
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
deps += [
# On Linux, link the dependencies (libraries) that make up actual
# Chromium functionality directly into the executable.
":dependencies",
"//chrome/common:version_header",
public_deps = [
":xdg_mime", # Needs to be public for installer to consume files.
"//chrome/common:buildflags",
]
data_deps += [ "//components/crash/core/app:chrome_crashpad_handler" ]
ldflags = []
# Chrome OS debug builds for arm need to pass --long-plt to the linker.
# See [Link]
if (is_chromeos && is_debug && target_cpu == "arm") {
ldflags += [ "-Wl,--long-plt" ]
}
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [
"//chrome/browser/ash/locale",
"//chrome/browser/ash/schedqos",
]
}
if (use_ozone) {
deps += [ "//ui/ozone" ]
if (is_linux) {
deps += [ "//ui/linux:display_server_utils" ]
}
}
}
data_deps += [
"//chrome/browser/resources/media/mei_preload:component",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component",
"//third_party/widevine/cdm",
]
if (is_linux) {
sources += [
"app/chrome_main_linux.cc",
"app/chrome_main_linux.h",
]
}
}
if (is_win) {
shared_library("chrome_dll") {
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
defines = []
sources = [
"//base/win/[Link]",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
output_name = "chrome"
deps = [
":chrome_dll_manifest",
":chrome_dll_version",
":dependencies",
"//chrome/app:chrome_dll_resources",
"//chrome/app:command_ids",
"//chrome/app/theme:chrome_unscaled_resources",
"//chrome/chrome_elf",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/install_static:install_static_util",
"//chrome/install_static:secondary_module",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//crypto",
"//headless:headless_non_renderer",
"//headless:headless_shell_browser_lib",
"//net:net_resources",
"//ppapi/buildflags",
"//sandbox/win:sandbox",
"//third_party/cld_3/src/src:cld_3",
"//third_party/wtl",
"//ui/views",
]
configs += [ "//build/config/win:delayloads" ]
if (use_aura) {
deps += [ "//ui/compositor" ]
}
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
copy("copy_first_run") {
sources = [ "app/FirstRun" ]
outputs = [ "$root_out_dir/First Run" ]
}
} else if (is_mac) {
chrome_helper_name = chrome_product_full_name + " Helper"
chrome_framework_name = chrome_product_full_name + " Framework"
chrome_framework_version = chrome_version_full
group("chrome") {
deps = [ ":chrome_app" ]
data_deps = [ ":chrome_app" ]
if (verify_dynamic_libraries) {
deps += [ ":verify_libraries_chrome_app" ]
}
tweak_info_plist("chrome_app_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--scm=1",
"--bundle_id=$chrome_mac_bundle_id",
]
if (enable_updater) {
args += [ "--privileged_helper_id=$privileged_helper_name" ]
if (is_chrome_branded) {
args += [ "--keystone=1" ]
if (current_cpu == "arm64") {
args += [ "--keystone-base-tag=arm64" ]
}
} else {
args += [ "--keystone=0" ]
}
} else {
args += [ "--keystone=0" ]
}
}
mac_app_bundle("chrome_app") {
output_name = chrome_product_full_name
info_plist_target = ":chrome_app_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_CREATOR=$chrome_mac_creator_code",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
":chrome_app_strings_bundle_data",
":chrome_resources",
":chrome_versioned_bundle_data",
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:buildflags",
"//chrome/common:version_header",
]
if (enable_updater) {
deps += [ ":chromium_updater_privileged_helper" ]
}
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags = [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link" ]
ldflags = [ "-Wl,-rpath,@executable_path/../Frameworks" ]
# The Framework is packaged inside the .app bundle. But when using the
# component build, all the dependent shared libraries of :chrome_dll are
# not packaged within the framework. This data_deps line makes all of
# those dependent libraries runtime dependencies of the .app bundle.
# This is a bit of a hack, since GN deliberately terminates its search
# for runtime_deps at create_bundle nodes ([Link]
data_deps = [ ":chrome_framework" ]
}
}
if (verify_dynamic_libraries) {
action("verify_libraries_chrome_app") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [ "${root_out_dir}/${chrome_product_full_name}.app/Contents/MacOS/$
{chrome_product_full_name}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
"--allow",
"/usr/lib/[Link]",
]
deps = [ ":chrome_app" ]
}
}
compiled_action("chrome_app_strings") {
tool = "//chrome/tools/build/mac:infoplist_strings_util"
inputs = []
outputs = []
foreach(locale, platform_pak_locales) {
inputs += [ "$root_gen_dir/chrome/branded_strings_${locale}.pak" ]
}
foreach(locale, locales_as_apple_outputs) {
outputs += [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
}
args =
[
"-b",
"branded_strings",
"-v",
chrome_version_full,
"-g",
rebase_path("$root_gen_dir/chrome", root_build_dir),
"-o",
rebase_path("$target_gen_dir/app_infoplist_strings", root_build_dir),
"-t",
"main",
] + platform_pak_locales
deps = [ "//chrome/app:branded_strings" ]
}
foreach(locale, locales_as_apple_outputs) {
bundle_data("chrome_app_strings_${locale}_bundle_data") {
sources = [
"$target_gen_dir/app_infoplist_strings/$[Link]/[Link]",
]
outputs =
[ "{{bundle_resources_dir}}/$[Link]/{{source_file_part}}" ]
public_deps = [ ":chrome_app_strings" ]
}
}
group("chrome_app_strings_bundle_data") {
public_deps = []
foreach(locale, locales_as_apple_outputs) {
public_deps += [ ":chrome_app_strings_${locale}_bundle_data" ]
}
}
bundle_data("chrome_app_icon") {
sources = [ "app/theme/$branding_path_component/mac/[Link]" ]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
}
bundle_data("chrome_resources") {
sources = [
"$root_out_dir/$chrome_mac_bundle_id.manifest",
"app/theme/$branding_path_component/mac/[Link]",
"browser/ui/cocoa/applescript/[Link]",
]
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":chrome_app_icon",
":chrome_app_strings",
"//components/policy:chrome_manifest_bundle",
]
}
bundle_data("chrome_versioned_bundle_data") {
sources = [ "$root_out_dir/$chrome_framework_name.framework" ]
outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
public_deps = [
# Before bundling the versioned app components, delete any existing
# versions.
":clean_up_old_versions",
if (enable_widevine_cdm_host_verification) {
# The :chrome_framework_widevine_signature target copies into the
# :chrome_framework bundle. But because the signing file depends on the
# framework itself, that would cause a cyclical dependency. Instead,
# this dependency directly copies the file into the framework's
# resources directory.
public_deps += [ ":chrome_framework_widevine_signature" ]
}
}
if (enable_updater) {
bundle_data("chromium_updater_privileged_helper") {
sources = [ "$root_out_dir/$privileged_helper_name" ]
outputs = [
"{{bundle_contents_dir}}/Library/LaunchServices/{{source_file_part}}",
]
public_deps = [ "//chrome/updater/mac:privileged_helper" ]
}
}
action("clean_up_old_versions") {
script = "//chrome/tools/build/mac/clean_up_old_versions.py"
_stamp_file = "$root_gen_dir/run_$target_name.stamp"
outputs = [ _stamp_file ]
_versions_dir =
"$root_out_dir/$chrome_product_full_name.app/Contents/Frameworks/$chrome_framework_
[Link]/Versions"
args = [
"--versions-dir",
rebase_path(_versions_dir, root_build_dir),
"--stamp",
rebase_path(_stamp_file, root_build_dir),
"--keep",
chrome_framework_version,
"--keep",
"Current",
]
}
tweak_info_plist("chrome_helper_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=0",
]
}
compile_entitlements("entitlements") {
entitlements_templates = [ "app/[Link]" ]
if (is_chrome_branded && include_branded_entitlements) {
# These entitlements are bound to the official Google Chrome signing
# certificate and will not necessarily work in any other build.
entitlements_templates += [ "app/[Link]" ]
}
output_name = "$target_gen_dir/[Link]"
substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_TEAM_ID=$chrome_mac_team_id",
]
visibility = [ "//chrome/installer/mac:copies" ]
}
template("chrome_helper_app") {
mac_app_bundle(target_name) {
assert(defined(invoker.helper_name_suffix))
assert(defined(invoker.helper_bundle_id_suffix))
if (defined(invoker.info_plist_target)) {
info_plist_target = invoker.info_plist_target
} else {
info_plist_target = ":chrome_helper_plist"
}
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
"CHROMIUM_HELPER_SUFFIX=${invoker.helper_name_suffix}",
"CHROMIUM_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
]
sources = [ "app/chrome_exe_main_mac.cc" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
defines = [ "HELPER_EXECUTABLE" ]
deps = [
"//base/allocator:early_zone_registration_apple",
"//build:branding_buildflags",
"//chrome/common:version_header",
"//sandbox/mac:seatbelt",
]
if (defined([Link])) {
deps += [Link]
}
ldflags = []
if (is_component_build) {
# In a component build, the framework is directly linked to the
# executable because dlopen() and loading all the dependent dylibs
# is time-consuming, see [Link]
deps += [ ":chrome_framework+link_nested" ]
ldflags += [
# The helper is in [Link]/Contents/Frameworks/Chromium
[Link]/Versions/X/Helpers/Chromium [Link]/Contents/MacOS
if (enable_stripping) {
# At link time, preserve the global symbols specified in the .exports
# file. All other global symbols will be marked as private. The default
# //build/config/apple:strip_all config will then remove the remaining
# local and debug symbols.
ldflags += [ "-Wl,-exported_symbols_list," +
rebase_path("app/[Link]", root_build_dir) ]
}
}
}
# Create app for the alert helper manually here as we want to modify the plist
# to set the alert style and add the app icon to its resources.
tweak_info_plist("chrome_helper_app_alerts_plist") {
deps = [ ":chrome_helper_plist" ]
info_plists = get_target_outputs(":chrome_helper_plist") +
[ "app/[Link]" ]
}
chrome_helper_app("chrome_helper_app_${alert_helper_params[0]}") {
helper_name_suffix = alert_helper_params[2]
helper_bundle_id_suffix = alert_helper_params[1]
info_plist_target = ":chrome_helper_app_alerts_plist"
deps = [
":chrome_app_icon",
":chrome_helper_app_alerts_resources",
]
}
if (verify_dynamic_libraries) {
foreach(helper_params, chrome_mac_helpers) {
_helper_target = helper_params[0]
_helper_bundle_id = helper_params[1]
_helper_suffix = helper_params[2]
action("verify_libraries_chrome_helper_app_${_helper_target}") {
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
inputs = [
"${root_out_dir}/${chrome_helper_name}${_helper_suffix}.app/Contents/MacOS/$
{chrome_helper_name}${_helper_suffix}" ]
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
args = [
"--stamp",
rebase_path(outputs[0], root_out_dir),
"-B",
objdump_path,
"--image",
rebase_path(inputs[0], root_out_dir),
bundle_data("chrome_framework_helpers") {
sources = [
"$root_out_dir/app_mode_loader",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/web_app_shortcut_copier",
]
outputs = [ "{{bundle_contents_dir}}/Helpers/{{source_file_part}}" ]
public_deps = [
"//chrome/app_shim:app_mode_loader",
"//chrome/browser/web_applications/os_integration/mac:web_app_shortcut_copier",
"//components/crash/core/app:chrome_crashpad_handler",
]
foreach(helper_params, chrome_mac_helpers) {
sources +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.app" ]
public_deps += [ ":chrome_helper_app_${helper_params[0]}" ]
if (verify_dynamic_libraries) {
public_deps +=
[ ":verify_libraries_chrome_helper_app_${helper_params[0]}" ]
}
}
if (enable_updater) {
if (is_chrome_branded) {
sources += [ "//third_party/updater/chrome_mac_universal_prod/cipd/$
{updater_product_full_name}.app" ]
} else {
sources += [ "$root_out_dir/${updater_product_full_name}.app" ]
public_deps += [
"//chrome/updater/mac:browser_install_script",
"//chrome/updater/mac:updater_bundle",
"//chrome/updater/mac:updater_install_script",
]
}
}
}
bundle_data("chrome_framework_resources") {
sources = [
"//ui/gl/resources/angle-metal/gpu_shader_cache.bin",
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
public_deps = [
":packed_resources",
"//chrome/app_shim:app_mode_loader_plist_bundle_data",
"//chrome/browser/mac:install",
]
if (icu_use_data_file) {
sources += [ "$root_out_dir/[Link]" ]
public_deps += [ "//third_party/icu:icudata" ]
}
if (v8_use_external_startup_data) {
public_deps += [ "//v8" ]
if (use_v8_context_snapshot) {
sources += [ "$root_out_dir/$v8_context_snapshot_filename" ]
public_deps += [ "//tools/v8_context_snapshot" ]
}
if (!use_v8_context_snapshot || include_both_v8_snapshots) {
sources += [ "$root_out_dir/snapshot_blob.bin" ]
}
}
}
if (enable_nacl) {
bundle_data("chrome_framework_plugins") {
sources = []
outputs =
[ "{{bundle_contents_dir}}/Internet Plug-Ins/{{source_file_part}}" ]
public_deps = []
if (enable_nacl) {
if (current_cpu == "x86") {
sources += [ "$root_out_dir/nacl_irt_x86_32.nexe" ]
} else if (current_cpu == "x64") {
sources += [ "$root_out_dir/nacl_irt_x86_64.nexe" ]
}
public_deps += [ "//ppapi/native_client:irt" ]
}
}
} else {
group("chrome_framework_plugins") {
}
}
if (bundle_widevine_cdm) {
bundle_data("widevine_cdm_library_binaries") {
sources = [ "$root_out_dir/$widevine_cdm_path/[Link]" ]
if (enable_widevine_cdm_host_verification) {
sources +=
[ "$root_out_dir/$widevine_cdm_path/[Link]" ]
}
outputs = [
"{{bundle_contents_dir}}/Libraries/$widevine_cdm_path/{{source_file_part}}" ]
public_deps = [ "//third_party/widevine/cdm" ]
}
bundle_data("widevine_cdm_library_manifest_and_license_files") {
sources = [
"$root_out_dir/WidevineCdm/LICENSE",
"$root_out_dir/WidevineCdm/[Link]",
]
outputs = [
"{{bundle_contents_dir}}/Libraries/WidevineCdm/{{source_file_part}}",
]
public_deps = [ "//third_party/widevine/cdm" ]
}
}
group("widevine_cdm_library") {
if (bundle_widevine_cdm) {
deps = [
":widevine_cdm_library_binaries",
":widevine_cdm_library_manifest_and_license_files",
]
}
}
if (enable_widevine_cdm_host_verification) {
widevine_sign_file("sign_chrome_framework_for_widevine") {
file =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
flags = 1
signature_file = "$root_out_dir/$chrome_framework_name.sig"
deps = [ ":chrome_framework" ]
}
copy("chrome_framework_widevine_signature") {
deps = [ ":sign_chrome_framework_for_widevine" ]
sources = [ "$root_out_dir/$chrome_framework_name.sig" ]
outputs = [
"$root_out_dir/$chrome_framework_name.framework/Resources/{{source_file_part}}" ]
}
}
if (build_with_internal_optimization_guide) {
# Add the optimization guide .dylib in the MODULE_DIR of [Link]
bundle_data("optimization_guide_library") {
sources = [
"$root_out_dir/og_intermediates/liboptimization_guide_internal.dylib",
]
outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ]
public_deps = [
"//components/optimization_guide/core:optimization_guide_internal_library_copy" ]
}
} else {
group("optimization_guide_library") {
}
}
tweak_info_plist("chrome_framework_plist") {
info_plist = "app/[Link]"
args = [
"--breakpad=0",
"--keystone=0",
"--scm=1",
"--branding",
chrome_product_short_name,
]
}
sources = [
"app/chrome_crash_reporter_client.cc",
"app/chrome_crash_reporter_client.h",
"app/chrome_crash_reporter_client_mac.mm",
"app/chrome_dll_resource.h",
"app/chrome_main.cc",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/chrome_main_mac.h",
"app/chrome_main_mac.mm",
"app/startup_timestamps.h",
]
deps = [
":dependencies",
"//build:chromeos_buildflags",
"//chrome/app:command_ids",
"//chrome/common:buildflags",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//components/crash/core/app",
"//components/memory_system",
"//components/policy:generated",
"//content/public/app",
"//headless:headless_shell_lib",
"//third_party/cld_3/src/src:cld_3",
]
if (is_chromeos) {
deps += [ "//chrome/browser/ash/schedqos" ]
}
if (is_component_build) {
frameworks = [ "[Link]" ]
}
ldflags = [ "-ObjC" ]
configs += [
":chrome_dll_symbol_order",
"//build/config/compiler:wexit_time_destructors",
]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
}
mac_framework_bundle("chrome_framework") {
output_name = chrome_framework_name
framework_version = chrome_framework_version
framework_contents = [
"Helpers",
"Libraries",
"Resources",
]
if (is_chrome_branded) {
framework_contents += [ "Default Apps" ]
}
if (enable_nacl) {
framework_contents += [ "Internet Plug-Ins" ]
}
configs += [ "//build/config/compiler:wexit_time_destructors" ]
configs -= [ "//build/config/compiler:thinlto_optimize_default" ]
configs += [ "//build/config/compiler:thinlto_optimize_max" ]
info_plist_target = ":chrome_framework_plist"
extra_substitutions = [
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
"CHROMIUM_SHORT_NAME=$chrome_product_short_name",
]
public_deps = [ ":chrome_dll" ]
bundle_deps = [
":angle_binaries",
":chrome_framework_helpers",
":chrome_framework_plugins",
":chrome_framework_resources",
":optimization_guide_library",
":swiftshader_binaries",
":widevine_cdm_library",
"//chrome/browser/resources/media/mei_preload:component_bundle",
"//chrome/browser/web_applications/isolated_web_apps/key_distribution/
preload:component_bundle",
"//components/privacy_sandbox/privacy_sandbox_attestations/preload:component_bundle
",
]
if (is_chrome_branded) {
bundle_deps += [ ":preinstalled_apps" ]
}
configs += [ ":chrome_dll_symbol_order" ]
if (!is_component_build && !using_sanitizer) {
configs += [ ":chrome_dll_symbol_exports" ]
}
ldflags = [
"-compatibility_version",
chrome_dylib_version,
"-current_version",
chrome_dylib_version,
]
if (!is_component_build) {
# Specify a sensible install_name for static builds. The library is
# dlopen()ed so this is not used to resolve the module.
ldflags += [
"-Wl,-install_name,@executable_path/../Frameworks/$chrome_framework_name.framework/
Versions/$chrome_framework_version/$chrome_framework_name" ]
} else {
# In the component build, both the :chrome_app and various
# :chrome_helper* targets directly link to the Framework target. Use
# @rpath-based loading so that the dylib ID does not have to be changed
# with install_name_tool.
ldflags += [
"-Wl,-install_name,@rpath/$chrome_framework_name.framework/$chrome_framework_name",
"-Wl,-rpath,@loader_path/../../../../../..",
"-Wl,-reexport_library,libchrome_dll.dylib",
]
data_deps = [ ":chrome_dll" ]
}
}
_framework_binary_path =
"$root_out_dir/$chrome_framework_name.framework/Versions/$chrome_framework_version/
$chrome_framework_name"
assert(_framework_binary_path != "",
"Ignore configuration-dependent unused variable warning")
# This list must be updated with the two targets' deps list below, and
# the list of _dsyms in :chrome_dsym_archive.
_chrome_symbols_sources = [
"$root_out_dir/$chrome_product_full_name.app/Contents/MacOS/$chrome_product_full_na
me",
"$root_out_dir/chrome_crashpad_handler",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.dylib",
_framework_binary_path,
]
if (build_with_internal_optimization_guide) {
_chrome_symbols_sources +=
[ "$root_out_dir/liboptimization_guide_internal.dylib" ]
}
foreach(helper_params, chrome_mac_helpers) {
_chrome_symbols_sources += [ "$root_out_dir/${chrome_helper_name}$
{helper_params[2]}.app/Contents/MacOS/${chrome_helper_name}${helper_params[2]}" ]
}
action_foreach("chrome_dump_syms") {
script = "//build/redirect_stdout.py"
sources = _chrome_symbols_sources
outputs =
[ "$root_out_dir/{{source_file_part}}-$chrome_version_full.breakpad" ]
dump_syms =
"//third_party/breakpad:dump_syms($host_system_allocator_toolchain)"
args = rebase_path(outputs, root_build_dir) + [
rebase_path(get_label_info(dump_syms, "root_out_dir") + "/" +
get_label_info(dump_syms, "name"),
root_build_dir),
"-d",
"-m",
"-g",
rebase_path(
"$root_out_dir/{{source_file_part}}.dSYM/Contents/Resources/DWARF/
{{source_file_part}}",
root_build_dir),
"{{source}}",
]
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
dump_syms,
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
}
action("chrome_dsym_archive") {
script = "//chrome/tools/build/mac/archive_symbols.py"
# These are the dSYMs that will be archived. The sources list must be
# the target outputs that correspond to the dSYMs (since a dSYM is a
# directory it cannot be listed as a source file). The targets that
# generate both the dSYM and binary image are listed in deps.
_dsyms = [
"$root_out_dir/$chrome_framework_name.dSYM",
"$root_out_dir/$chrome_product_full_name.dSYM",
"$root_out_dir/chrome_crashpad_handler.dSYM",
"$root_out_dir/[Link]",
"$root_out_dir/[Link]",
"$root_out_dir/libvk_swiftshader.[Link]",
]
if (build_with_internal_optimization_guide) {
_dsyms += [ "$root_out_dir/liboptimization_guide_internal.[Link]" ]
}
deps = [
":chrome_app",
":chrome_framework",
"//components/crash/core/app:chrome_crashpad_handler",
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
"//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan",
]
if (build_with_internal_optimization_guide) {
deps += [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
foreach(helper_params, chrome_mac_helpers) {
_dsyms +=
[ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.dSYM" ]
deps += [ ":chrome_helper_app_${helper_params[0]}" ]
}
sources = _chrome_symbols_sources
_output = "$root_out_dir/$chrome_product_full_name.[Link].bz2"
outputs = [ _output ]
group("dependencies") {
public_deps = [
"//build:branding_buildflags",
"//build:chromeos_buildflags",
"//chrome/browser",
"//chrome/browser:buildflags",
"//chrome/browser:shell_integration",
"//chrome/browser/policy:path_parser",
"//chrome/child",
"//chrome/common",
"//chrome/gpu",
"//chrome/renderer",
"//chrome/utility",
"//components/crash/core/app",
"//components/devtools/devtools_pipe",
"//components/memory_system",
"//components/startup_metric_utils",
"//components/sync",
"//components/upload_list:upload_list",
"//components/webui/about",
"//content/public/child",
"//pdf",
"//services/tracing/public/cpp",
"//third_party/blink/public:blink_devtools_frontend_resources",
"//third_party/blink/public:blink_devtools_inspector_resources",
"//v8:v8_headers",
]
if (enable_ppapi) {
public_deps += [ "//ppapi/host" ]
}
if (enable_printing) {
public_deps += [ "//printing" ]
}
if (enable_nacl) {
public_deps += [
"//components/nacl/browser",
"//components/nacl/renderer/plugin:nacl_trusted_plugin",
]
}
if (is_chromeos) {
public_deps += [
"//ash/constants",
"//chrome/browser/ash/boot_times_recorder",
"//chrome/browser/ash/dbus",
"//chrome/browser/ash/schedqos",
"//chromeos/ash/components/memory",
"//chromeos/dbus/constants",
]
}
}
if (is_win) {
process_version_rc_template("chrome_exe_version") {
sources = [ "app/chrome_exe.ver" ]
output = "$target_gen_dir/chrome_exe_version.rc"
}
process_version_rc_template("chrome_dll_version") {
sources = [ "app/chrome_dll.ver" ]
output = "$target_gen_dir/chrome_dll_version.rc"
}
# This manifest matches what GYP produced. It may not even be necessary.
windows_manifest("chrome_dll_manifest") {
sources = [
as_invoker_manifest,
common_controls_manifest,
]
}
process_version_rc_template("other_version") {
sources = [ "app/[Link]" ]
output = "$target_gen_dir/other_version.rc"
}
}
copy("visual_elements_resources") {
sources = [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"app/visual_elements_resources/[Link]",
]
if (is_chrome_branded) {
sources += [
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
"//chrome/app/theme/$branding_path_component/win/tiles/[Link]",
]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
group("resources") {
public_deps = [
"//chrome/browser:resources",
"//chrome/common:resources",
"//chrome/renderer:resources",
]
}
group("extra_resources") {
# Deps should be same as those in chrome_extra_paks() within chrome_paks.gni.
public_deps = [
"//chrome/browser/resources:resources",
"//components/autofill/core/browser:autofill_address_rewriter_resources",
]
}
target(_preinstalled_apps_target_type, "preinstalled_apps") {
visibility = [ ":packed_resources" ]
if (is_mac) {
visibility += [
":chrome_framework",
":chrome_framework_shared_library",
]
}
sources = [ "browser/resources/default_apps/external_extensions.json" ]
if (!is_mac) {
outputs = [ "$root_out_dir/default_apps/{{source_file_part}}" ]
} else {
outputs = [ "{{bundle_contents_dir}}/Default Apps/{{source_file_part}}" ]
}
# Force anybody that depends on this to get the default apps as data files.
data = process_file_template(sources, outputs)
}
}
if (!is_android) {
chrome_paks("packed_resources") {
if (is_mac) {
output_dir = "$root_gen_dir/repack"
copy_data_to_bundle = true
} else {
output_dir = root_out_dir
mark_as_data = true
}
if (enable_resource_allowlist_generation) {
repack_allowlist = _chrome_resource_allowlist
deps = [ ":resource_allowlist" ]
}
repack("browser_tests_pak") {
testonly = true
sources = [ "$root_gen_dir/chrome/webui_test_resources.pak" ]
output = "$root_out_dir/browser_tests.pak"
deps = [ "//chrome/test/data/webui:resources" ]
}
group("strings") {
public_deps = [
"//chrome/app:branded_strings",
"//chrome/app:generated_resources",
"//chrome/app/resources:locale_settings",
]
}
if (is_android) {
java_cpp_enum("offline_pages_enum_javagen") {
sources = [ "browser/offline_pages/offline_page_utils.h" ]
}
java_cpp_enum("download_enum_javagen") {
sources = [
"browser/download/android/download_open_source.h",
"browser/download/download_dialog_types.h",
"browser/download/download_prompt_status.h",
]
}
source_set("chrome_android_core") {
sources = [
"app/android/chrome_jni_onload.cc",
"app/android/chrome_jni_onload.h",
"app/android/chrome_main_delegate_android.cc",
"app/android/chrome_main_delegate_android.h",
"app/chrome_main_delegate.cc",
"app/chrome_main_delegate.h",
"app/startup_timestamps.h",
]
libs = [
"android",
"jnigraphics",
]
public_deps = [
"//chrome/browser",
"//chrome/utility",
]
deps = [
":dependencies",
"//chrome/browser/flags:flags_android",
"//chrome/browser/ui",
"//chrome/child",
"//chrome/common",
"//chrome/common:version_header",
"//chrome/common/profiler",
"//chrome/gpu",
"//chrome/renderer",
"//components/crash/android:crash_android",
"//components/minidump_uploader",
"//components/safe_browsing:buildflags",
"//components/safe_browsing/android:safe_browsing_api_handler",
"//components/safe_browsing/android:safe_browsing_mobile",
"//components/stylus_handwriting/android",
"//components/variations:variations_associated_data",
"//content/public/app",
]
if (is_chromeos) {
public_deps += [ "//ui/lottie" ]
deps += [ "//chrome/browser/ash/schedqos" ]
}
}
}
if (is_linux || is_chromeos) {
if (!(is_debug && use_debug_fission)) {
group("linux_symbols") {
deps = [
":angle_egl_symbols",
":angle_gles_symbols",
":chrome_crashpad_symbols",
":chrome_symbols",
]
if (is_linux) {
deps += [ ":swiftshader_vk_symbols" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
deps += [ ":angle_libvulkan_symbols" ]
}
if (build_with_internal_optimization_guide) {
deps += [ ":optimization_guide_symbols" ]
}
}
extract_symbols("chrome_symbols") {
binary = "$root_out_dir/chrome"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ ":chrome" ]
}
extract_symbols("chrome_crashpad_symbols") {
binary = "$root_out_dir/chrome_crashpad_handler"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/[Link].ia32"
} else {
symbol_file = "$root_out_dir/[Link].$current_cpu"
}
deps = [ "//components/crash/core/app:chrome_crashpad_handler" ]
}
extract_symbols("swiftshader_vk_symbols") {
binary = "$root_out_dir/libvk_swiftshader.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/libvk_swiftshader.breakpad.$current_cpu"
}
deps = [ "//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan" ]
}
extract_symbols("angle_egl_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libegl.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libegl.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libEGL" ]
}
extract_symbols("angle_gles_symbols") {
binary = "$root_out_dir/[Link]"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libgles.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libgles.breakpad.$current_cpu"
}
deps = [ "//third_party/angle:libGLESv2" ]
}
if (!is_chromeos && angle_shared_libvulkan) {
extract_symbols("angle_libvulkan_symbols") {
binary = "$root_out_dir/[Link].1"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.ia32"
} else {
symbol_file = "$root_out_dir/angle_libvulkan.breakpad.$current_cpu"
}
deps = [ "//third_party/vulkan-loader/src:libvulkan" ]
}
}
if (build_with_internal_optimization_guide) {
extract_symbols("optimization_guide_symbols") {
binary = "$root_out_dir/liboptimization_guide_internal.so"
if (current_cpu == "x86") {
# GYP used "ia32" so keep that naming for back-compat.
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.ia32"
} else {
symbol_file =
"$root_out_dir/optimization_guide_internal.breakpad.$current_cpu"
}
deps = [
"//components/optimization_guide/internal:optimization_guide_internal" ]
}
}
}
# Copies some scripts and resources that are used for desktop integration.
copy("xdg_mime") {
sources = [
"//chrome/tools/build/linux/chrome-wrapper",
"//third_party/xdg-utils/scripts/xdg-mime",
"//third_party/xdg-utils/scripts/xdg-settings",
]
if (is_linux) {
sources += [
"//chrome/app/theme/$branding_path_component/linux/product_logo_48.png",
]
} else {
sources +=
[ "//chrome/app/theme/$branding_path_component/product_logo_48.png" ]
}
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}
}
if (_cros_generate_embed_section_target) {
embed_sections("section_embedded_chrome_binary") {
binary_input = "$root_out_dir/chrome"
sections_embedded_binary_output = "$root_out_dir/chrome.sections_embedded"
deps = [ ":chrome" ]
}
}