Skip to content

Commit

Permalink
Add BackgroundDownloader for Mac
Browse files Browse the repository at this point in the history
Implement a background CRX downloader for Mac using NSURLSession's
background transfer capabilities. This is intended to work similarly
to the BITS-backed downloader on Windows.

Downloads started by this implementation can continue even if Chrome
is suspended/terminated and can persist through network errors,
reboots, etc.

When the downloader is instantiated, MacOS may notify it of downloads
which were completed in the background. Thus, a cache of unclaimed
downloads is maintained.


Low-Coverage-Reason: TRIVIAL_CHANGE changes to chrome_component_updater_configurator.cc and crx_downloader_factory.cc are trivial
Bug: 1493709
Change-Id: Ief188e6769a846486e1b558469fdfcfe0b12f566
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4973235
Reviewed-by: Avi Drissman <avi@chromium.org>
Commit-Queue: Noah Rose Ledesma <noahrose@google.com>
Reviewed-by: Sorin Jianu <sorin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1216377}
  • Loading branch information
Noah Rose Ledesma authored and Chromium LUCI CQ committed Oct 27, 2023
1 parent abf1339 commit 53fa3f9
Show file tree
Hide file tree
Showing 14 changed files with 1,227 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class ChromeConfigurator : public update_client::Configurator {
private:
friend class base::RefCountedThreadSafe<ChromeConfigurator>;

absl::optional<base::FilePath> GetBackgroundDownloaderCache() const;

ConfiguratorImpl configurator_impl_;
raw_ptr<PrefService>
pref_service_; // This member is not owned by this class.
Expand Down Expand Up @@ -191,8 +193,8 @@ ChromeConfigurator::GetNetworkFetcherFactory() {
scoped_refptr<update_client::CrxDownloaderFactory>
ChromeConfigurator::GetCrxDownloaderFactory() {
if (!crx_downloader_factory_) {
crx_downloader_factory_ =
update_client::MakeCrxDownloaderFactory(GetNetworkFetcherFactory());
crx_downloader_factory_ = update_client::MakeCrxDownloaderFactory(
GetNetworkFetcherFactory(), GetBackgroundDownloaderCache());
}
return crx_downloader_factory_;
}
Expand Down Expand Up @@ -268,6 +270,16 @@ absl::optional<base::FilePath> ChromeConfigurator::GetCrxCachePath() const {
: absl::nullopt;
}

// TODO(crbug/1496582): Consolidate the cache path getters.
absl::optional<base::FilePath>
ChromeConfigurator::GetBackgroundDownloaderCache() const {
base::FilePath path;
bool result = base::PathService::Get(chrome::DIR_USER_DATA, &path);
return result ? absl::optional<base::FilePath>(
path.AppendASCII("download_cache"))
: absl::nullopt;
}

} // namespace

scoped_refptr<update_client::Configurator>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,20 @@ const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates";
// value is in seconds.
const char kInitialDelay[] = "initial-delay";

#if BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
// Disables background downloads.
const char kSwitchDisableBackgroundDownloads[] = "disable-background-downloads";
#endif // BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)

// If there is an element of |vec| of the form |test|=.*, returns the right-
// hand side of that assignment. Otherwise, returns an empty string.
// The right-hand side may contain additional '=' characters, allowing for
// further nesting of switch arguments.
std::string GetSwitchArgument(const std::vector<std::string>& vec,
const char* test) {
if (vec.empty())
if (vec.empty()) {
return std::string();
}
for (auto it = vec.begin(); it != vec.end(); ++it) {
const std::size_t found = it->find("=");
if (found != std::string::npos) {
Expand All @@ -76,7 +77,7 @@ ComponentUpdaterCommandLineConfigPolicy::
cmdline->GetSwitchValueASCII(switches::kComponentUpdater), ",",
base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);

#if BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
background_downloads_enabled_ =
!base::Contains(switch_values, kSwitchDisableBackgroundDownloads);
#else
Expand All @@ -98,8 +99,9 @@ ComponentUpdaterCommandLineConfigPolicy::
const std::string initial_delay =
GetSwitchArgument(switch_values, kInitialDelay);
double initial_delay_seconds = 0;
if (base::StringToDouble(initial_delay, &initial_delay_seconds))
if (base::StringToDouble(initial_delay, &initial_delay_seconds)) {
initial_delay_ = base::Seconds(initial_delay_seconds);
}
}

bool ComponentUpdaterCommandLineConfigPolicy::BackgroundDownloadsEnabled()
Expand Down
12 changes: 12 additions & 0 deletions components/update_client/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ static_library("update_client") {
"//url",
]

if (is_mac) {
sources += [
"background_downloader_mac.h",
"background_downloader_mac.mm",
]
frameworks = [ "Foundation.framework" ]
}

if (is_win) {
sources += [
"background_downloader_win.cc",
Expand Down Expand Up @@ -286,6 +294,10 @@ source_set("unit_tests") {
if (is_win) {
sources += [ "background_downloader_win_unittest.cc" ]
}

if (is_mac) {
sources += [ "background_downloader_mac_unittest.cc" ]
}
}

deps = [
Expand Down
80 changes: 80 additions & 0 deletions components/update_client/background_downloader_mac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_UPDATE_CLIENT_BACKGROUND_DOWNLOADER_MAC_H_
#define COMPONENTS_UPDATE_CLIENT_BACKGROUND_DOWNLOADER_MAC_H_

#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "components/update_client/crx_downloader.h"

namespace update_client {
namespace {
// TODO(crbug.com/1493709): The session identifier might need to be more complex
// to accommodate multiple Chrome processes.
static constexpr char kDefaultBackgroundSessionId[] = "CrxDownloader";
} // namespace

class BackgroundDownloaderSharedSession
: public base::RefCountedThreadSafe<BackgroundDownloaderSharedSession> {
public:
using OnDownloadCompleteCallback = base::RepeatingCallback<void(
bool,
const update_client::CrxDownloader::Result&,
const update_client::CrxDownloader::DownloadMetrics&)>;

virtual void DoStartDownload(
const GURL& url,
OnDownloadCompleteCallback on_download_complete_callback) = 0;

// Cancel all download tasks and invalidates this session. Future calls to
// DoStartDownload will fail until the session is recreated.
virtual void InvalidateAndCancel() = 0;

protected:
friend class base::RefCountedThreadSafe<BackgroundDownloaderSharedSession>;
virtual ~BackgroundDownloaderSharedSession() = default;
};

class BackgroundDownloader : public CrxDownloader {
public:
BackgroundDownloader(
scoped_refptr<CrxDownloader> successor,
scoped_refptr<BackgroundDownloaderSharedSession> shared_session,
scoped_refptr<base::SequencedTaskRunner> background_sequence_);

private:
friend class BackgroundDownloaderTest;
friend class BackgroundDownloaderCrashingClientTest;
FRIEND_TEST_ALL_PREFIXES(BackgroundDownloaderTest, ConcurrentDownloaders);

// Overrides for CrxDownloader.
~BackgroundDownloader() override;
base::OnceClosure DoStartDownload(const GURL& url) override;

base::OnceClosure DoStartDownload(
const GURL& url,
BackgroundDownloaderSharedSession::OnDownloadCompleteCallback);

SEQUENCE_CHECKER(sequence_checker_);
scoped_refptr<BackgroundDownloaderSharedSession> shared_session_;
scoped_refptr<base::SequencedTaskRunner> background_sequence_;
base::WeakPtrFactory<BackgroundDownloader> weak_ptr_factory_{this};
};

scoped_refptr<BackgroundDownloaderSharedSession>
MakeBackgroundDownloaderSharedSession(
scoped_refptr<base::SequencedTaskRunner> background_sequence,
const base::FilePath& download_cache,
const std::string& session_identifier = kDefaultBackgroundSessionId);

} // namespace update_client

#endif // COMPONENTS_UPDATE_CLIENT_BACKGROUND_DOWNLOADER_MAC_H_

0 comments on commit 53fa3f9

Please sign in to comment.