Remove SetupOnUIThread for EmbeddedWorkerInstance
Thanks to ServiceWorkerOnUI, we can eliminate the class and function to manage thread-hoppings for starting a service worker. This CL moves tasks in SetupOnUIThread into EmbeddedWorkerInstance::Start(). Bug: 1138155 Change-Id: I15c72d0d45e792e229a4a8f19972b5d90253fc87 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2578717 Commit-Queue: Makoto Shimazu <shimazu@chromium.org> Reviewed-by: Asami Doi <asamidoi@chromium.org> Cr-Commit-Position: refs/heads/master@{#835989}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
b6f42464a4
commit
e38dded5c9
content/browser/service_worker
@@ -57,9 +57,6 @@ namespace content {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Used for tracing.
|
|
||||||
constexpr char kEmbeddedWorkerInstanceScope[] = "EmbeddedWorkerInstance";
|
|
||||||
|
|
||||||
// When a service worker version's failure count exceeds
|
// When a service worker version's failure count exceeds
|
||||||
// |kMaxSameProcessFailureCount|, the embedded worker is forced to start in a
|
// |kMaxSameProcessFailureCount|, the embedded worker is forced to start in a
|
||||||
// new process.
|
// new process.
|
||||||
@@ -79,206 +76,6 @@ void NotifyWorkerVersionDoomedOnUI(
|
|||||||
worker_process_id, worker_route_id, context_wrapper, version_id);
|
worker_process_id, worker_route_id, context_wrapper, version_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
using SetupProcessCallback = base::OnceCallback<void(
|
|
||||||
blink::ServiceWorkerStatusCode,
|
|
||||||
blink::mojom::EmbeddedWorkerStartParamsPtr,
|
|
||||||
std::unique_ptr<ServiceWorkerProcessManager::AllocatedProcessInfo>,
|
|
||||||
std::unique_ptr<EmbeddedWorkerInstance::DevToolsProxy>,
|
|
||||||
std::unique_ptr<
|
|
||||||
blink::PendingURLLoaderFactoryBundle> /* factory_bundle_for_new_scripts
|
|
||||||
*/
|
|
||||||
,
|
|
||||||
std::unique_ptr<
|
|
||||||
blink::PendingURLLoaderFactoryBundle> /* factory_bundle_for_renderer */,
|
|
||||||
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>,
|
|
||||||
mojo::PendingReceiver<blink::mojom::ReportingObserver>,
|
|
||||||
const base::Optional<base::TimeDelta>& thread_hop_time,
|
|
||||||
const base::Optional<base::Time>& ui_post_time)>;
|
|
||||||
|
|
||||||
// Allocates a renderer process for starting a worker and does setup like
|
|
||||||
// registering with DevTools. Called on the UI thread. Calls |callback| on the
|
|
||||||
// core thread. |context| and |weak_context| are only for passing to DevTools
|
|
||||||
// and must not be dereferenced here on the UI thread.
|
|
||||||
//
|
|
||||||
// This also sets up two URLLoaderFactoryBundles, one for
|
|
||||||
// ServiceWorkerScriptLoaderFactory and the other is for passing to the
|
|
||||||
// renderer. |cross_origin_embedder_policy| is respected to make these bundles.
|
|
||||||
// These bundles include factories for non-network URLs like chrome-extension://
|
|
||||||
// as needed.
|
|
||||||
void SetupOnUIThread(
|
|
||||||
int embedded_worker_id,
|
|
||||||
base::WeakPtr<ServiceWorkerProcessManager> process_manager,
|
|
||||||
bool can_use_existing_process,
|
|
||||||
const base::Optional<network::CrossOriginEmbedderPolicy>&
|
|
||||||
cross_origin_embedder_policy,
|
|
||||||
blink::mojom::EmbeddedWorkerStartParamsPtr params,
|
|
||||||
mojo::PendingReceiver<blink::mojom::EmbeddedWorkerInstanceClient> receiver,
|
|
||||||
scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
|
|
||||||
const base::Optional<base::Time>& io_post_time,
|
|
||||||
SetupProcessCallback callback) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
||||||
base::Optional<base::TimeDelta> thread_hop_time;
|
|
||||||
|
|
||||||
auto process_info =
|
|
||||||
std::make_unique<ServiceWorkerProcessManager::AllocatedProcessInfo>();
|
|
||||||
std::unique_ptr<EmbeddedWorkerInstance::DevToolsProxy> devtools_proxy;
|
|
||||||
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
|
|
||||||
factory_bundle_for_new_scripts;
|
|
||||||
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
|
|
||||||
factory_bundle_for_renderer;
|
|
||||||
mojo::PendingReceiver<blink::mojom::ReportingObserver>
|
|
||||||
reporting_observer_receiver;
|
|
||||||
|
|
||||||
if (!process_manager) {
|
|
||||||
base::Optional<base::Time> ui_post_time;
|
|
||||||
|
|
||||||
ServiceWorkerContextWrapper::RunOrPostTaskOnCoreThread(
|
|
||||||
FROM_HERE, base::BindOnce(std::move(callback),
|
|
||||||
blink::ServiceWorkerStatusCode::kErrorAbort,
|
|
||||||
std::move(params), std::move(process_info),
|
|
||||||
std::move(devtools_proxy),
|
|
||||||
std::move(factory_bundle_for_new_scripts),
|
|
||||||
std::move(factory_bundle_for_renderer),
|
|
||||||
/*coep_reporter=*/mojo::NullRemote(),
|
|
||||||
std::move(reporting_observer_receiver),
|
|
||||||
thread_hop_time, ui_post_time));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a process.
|
|
||||||
blink::ServiceWorkerStatusCode status =
|
|
||||||
process_manager->AllocateWorkerProcess(
|
|
||||||
embedded_worker_id, params->script_url, cross_origin_embedder_policy,
|
|
||||||
can_use_existing_process, process_info.get());
|
|
||||||
if (status != blink::ServiceWorkerStatusCode::kOk) {
|
|
||||||
base::Optional<base::Time> ui_post_time;
|
|
||||||
|
|
||||||
ServiceWorkerContextWrapper::RunOrPostTaskOnCoreThread(
|
|
||||||
FROM_HERE,
|
|
||||||
base::BindOnce(std::move(callback), status, std::move(params),
|
|
||||||
std::move(process_info), std::move(devtools_proxy),
|
|
||||||
std::move(factory_bundle_for_new_scripts),
|
|
||||||
std::move(factory_bundle_for_renderer),
|
|
||||||
/*coep_reporter=*/mojo::NullRemote(),
|
|
||||||
std::move(reporting_observer_receiver), thread_hop_time,
|
|
||||||
ui_post_time));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const int process_id = process_info->process_id;
|
|
||||||
RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
|
|
||||||
// TODO(falken): This CHECK should no longer fail, so turn to a DCHECK it if
|
|
||||||
// crash reports agree. Consider also checking for
|
|
||||||
// rph->IsInitializedAndNotDead().
|
|
||||||
CHECK(rph);
|
|
||||||
|
|
||||||
// Bind |receiver|, which is attached to |EmbeddedWorkerInstance::client_|, to
|
|
||||||
// the process. If the process dies, |client_|'s connection error callback
|
|
||||||
// will be called on the core thread.
|
|
||||||
if (receiver.is_valid())
|
|
||||||
rph->BindReceiver(std::move(receiver));
|
|
||||||
|
|
||||||
// Create COEP reporter if COEP value is already available (= this worker is
|
|
||||||
// not a worker which is going to be newly registered).
|
|
||||||
mojo::Remote<network::mojom::CrossOriginEmbedderPolicyReporter> coep_reporter;
|
|
||||||
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
|
|
||||||
coep_reporter_for_devtools;
|
|
||||||
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
|
|
||||||
coep_reporter_for_scripts;
|
|
||||||
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
|
|
||||||
coep_reporter_for_subresources;
|
|
||||||
if (cross_origin_embedder_policy) {
|
|
||||||
mojo::PendingRemote<blink::mojom::ReportingObserver>
|
|
||||||
reporting_observer_remote;
|
|
||||||
reporting_observer_receiver =
|
|
||||||
reporting_observer_remote.InitWithNewPipeAndPassReceiver();
|
|
||||||
auto reporter = std::make_unique<CrossOriginEmbedderPolicyReporter>(
|
|
||||||
rph->GetStoragePartition(), params->script_url,
|
|
||||||
cross_origin_embedder_policy->reporting_endpoint,
|
|
||||||
cross_origin_embedder_policy->report_only_reporting_endpoint,
|
|
||||||
// TODO(https://crbug.com/1147281): This is the NetworkIsolationKey of a
|
|
||||||
// top-level browsing context, which shouldn't be use for ServiceWorkers
|
|
||||||
// used in iframes.
|
|
||||||
net::NetworkIsolationKey::ToDoUseTopFrameOriginAsWell(
|
|
||||||
url::Origin::Create(params->script_url)));
|
|
||||||
reporter->BindObserver(std::move(reporting_observer_remote));
|
|
||||||
mojo::MakeSelfOwnedReceiver(std::move(reporter),
|
|
||||||
coep_reporter.BindNewPipeAndPassReceiver());
|
|
||||||
coep_reporter->Clone(
|
|
||||||
coep_reporter_for_devtools.InitWithNewPipeAndPassReceiver());
|
|
||||||
coep_reporter->Clone(
|
|
||||||
coep_reporter_for_scripts.InitWithNewPipeAndPassReceiver());
|
|
||||||
coep_reporter->Clone(
|
|
||||||
coep_reporter_for_subresources.InitWithNewPipeAndPassReceiver());
|
|
||||||
}
|
|
||||||
// Register to DevTools and update params accordingly.
|
|
||||||
const int routing_id = rph->GetNextRoutingID();
|
|
||||||
ServiceWorkerDevToolsManager::GetInstance()->WorkerStarting(
|
|
||||||
process_id, routing_id, std::move(context_wrapper),
|
|
||||||
params->service_worker_version_id, params->script_url, params->scope,
|
|
||||||
params->is_installed, cross_origin_embedder_policy,
|
|
||||||
std::move(coep_reporter_for_devtools), ¶ms->devtools_worker_token,
|
|
||||||
¶ms->wait_for_debugger);
|
|
||||||
params->service_worker_route_id = routing_id;
|
|
||||||
// Create DevToolsProxy here to ensure that the WorkerCreated() call is
|
|
||||||
// balanced by DevToolsProxy's destructor calling WorkerStopped().
|
|
||||||
devtools_proxy = std::make_unique<EmbeddedWorkerInstance::DevToolsProxy>(
|
|
||||||
process_id, routing_id);
|
|
||||||
|
|
||||||
// Create factory bundles for this worker to do loading. These bundles don't
|
|
||||||
// support reconnection to the network service, see below comments.
|
|
||||||
const url::Origin origin = url::Origin::Create(params->script_url);
|
|
||||||
|
|
||||||
// The bundle for new scripts is passed to ServiceWorkerScriptLoaderFactory
|
|
||||||
// and used to request non-installed service worker scripts. It's only needed
|
|
||||||
// for non-installed workers. It's OK to not support reconnection to the
|
|
||||||
// network service because it can only used until the service worker reaches
|
|
||||||
// the 'installed' state.
|
|
||||||
if (!params->is_installed) {
|
|
||||||
factory_bundle_for_new_scripts =
|
|
||||||
EmbeddedWorkerInstance::CreateFactoryBundleOnUI(
|
|
||||||
rph, routing_id, origin, cross_origin_embedder_policy,
|
|
||||||
std::move(coep_reporter_for_scripts),
|
|
||||||
ContentBrowserClient::URLLoaderFactoryType::kServiceWorkerScript);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The bundle for the renderer is passed to the service worker, and
|
|
||||||
// used for subresource loading from the service worker (i.e., fetch()).
|
|
||||||
// It's OK to not support reconnection to the network service because the
|
|
||||||
// service worker terminates itself when the connection breaks, so a new
|
|
||||||
// instance can be started.
|
|
||||||
factory_bundle_for_renderer = EmbeddedWorkerInstance::CreateFactoryBundleOnUI(
|
|
||||||
rph, routing_id, origin, cross_origin_embedder_policy,
|
|
||||||
std::move(coep_reporter_for_subresources),
|
|
||||||
ContentBrowserClient::URLLoaderFactoryType::kServiceWorkerSubResource);
|
|
||||||
|
|
||||||
// TODO(crbug.com/862854): Support changes to blink::RendererPreferences while
|
|
||||||
// the worker is running.
|
|
||||||
DCHECK(process_manager->browser_context() || process_manager->IsShutdown());
|
|
||||||
params->renderer_preferences = blink::RendererPreferences();
|
|
||||||
GetContentClient()->browser()->UpdateRendererPreferencesForWorker(
|
|
||||||
process_manager->browser_context(), ¶ms->renderer_preferences);
|
|
||||||
|
|
||||||
// Create a RendererPreferenceWatcher to observe updates in the preferences.
|
|
||||||
mojo::PendingRemote<blink::mojom::RendererPreferenceWatcher> watcher_remote;
|
|
||||||
params->preference_watcher_receiver =
|
|
||||||
watcher_remote.InitWithNewPipeAndPassReceiver();
|
|
||||||
GetContentClient()->browser()->RegisterRendererPreferenceWatcher(
|
|
||||||
process_manager->browser_context(), std::move(watcher_remote));
|
|
||||||
|
|
||||||
// Continue to OnSetupCompleted on the core thread.
|
|
||||||
base::Optional<base::Time> ui_post_time;
|
|
||||||
RunOrPostTaskOnThread(
|
|
||||||
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
|
|
||||||
base::BindOnce(
|
|
||||||
std::move(callback), status, std::move(params),
|
|
||||||
std::move(process_info), std::move(devtools_proxy),
|
|
||||||
std::move(factory_bundle_for_new_scripts),
|
|
||||||
std::move(factory_bundle_for_renderer),
|
|
||||||
coep_reporter ? coep_reporter.Unbind() : mojo::NullRemote(),
|
|
||||||
std::move(reporting_observer_receiver), thread_hop_time,
|
|
||||||
ui_post_time));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasSentStartWorker(EmbeddedWorkerInstance::StartingPhase phase) {
|
bool HasSentStartWorker(EmbeddedWorkerInstance::StartingPhase phase) {
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case EmbeddedWorkerInstance::NOT_STARTING:
|
case EmbeddedWorkerInstance::NOT_STARTING:
|
||||||
@@ -327,16 +124,17 @@ void BindCacheStorageOnUIThread(
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Created on the UI thread when the worker version is allcated a render process
|
// Created when a renderer process is allocated for the worker. It is destroyed
|
||||||
// and then moved to the core thread. It is destroyed when the worker stops.
|
// when the worker stops, and this proxies notifications to DevToolsManager.
|
||||||
// Proxies notifications to DevToolsManager that lives on UI thread.
|
|
||||||
// Owned by EmbeddedWorkerInstance.
|
// Owned by EmbeddedWorkerInstance.
|
||||||
|
//
|
||||||
|
// TODO(https://crbug.com/1138155): Remove this because we no longer need
|
||||||
|
// proxying the notifications becuase there's no thread hopping thanks to
|
||||||
|
// ServiceWorkerOnUI.
|
||||||
class EmbeddedWorkerInstance::DevToolsProxy {
|
class EmbeddedWorkerInstance::DevToolsProxy {
|
||||||
public:
|
public:
|
||||||
DevToolsProxy(int process_id, int agent_route_id)
|
DevToolsProxy(int process_id, int agent_route_id)
|
||||||
: process_id_(process_id),
|
: process_id_(process_id), agent_route_id_(agent_route_id) {}
|
||||||
agent_route_id_(agent_route_id),
|
|
||||||
ui_task_runner_(GetUIThreadTaskRunner({})) {}
|
|
||||||
|
|
||||||
~DevToolsProxy() {
|
~DevToolsProxy() {
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||||
@@ -370,7 +168,6 @@ class EmbeddedWorkerInstance::DevToolsProxy {
|
|||||||
private:
|
private:
|
||||||
const int process_id_;
|
const int process_id_;
|
||||||
const int agent_route_id_;
|
const int agent_route_id_;
|
||||||
const scoped_refptr<base::TaskRunner> ui_task_runner_;
|
|
||||||
bool worker_stop_ignored_notified_ = false;
|
bool worker_stop_ignored_notified_ = false;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(DevToolsProxy);
|
DISALLOW_COPY_AND_ASSIGN(DevToolsProxy);
|
||||||
@@ -398,303 +195,68 @@ class EmbeddedWorkerInstance::ScopedLifetimeTracker {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(ScopedLifetimeTracker);
|
DISALLOW_COPY_AND_ASSIGN(ScopedLifetimeTracker);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A handle for a renderer process managed by ServiceWorkerProcessManager on the
|
// A handle for a renderer process managed by ServiceWorkerProcessManager.
|
||||||
// UI thread. Lives on the core thread.
|
//
|
||||||
|
// TODO(https://crbug.com/1138155): Remove this as a clean up of
|
||||||
|
// ServiceWorkerOnUI.
|
||||||
class EmbeddedWorkerInstance::WorkerProcessHandle {
|
class EmbeddedWorkerInstance::WorkerProcessHandle {
|
||||||
public:
|
public:
|
||||||
WorkerProcessHandle(
|
WorkerProcessHandle(
|
||||||
const base::WeakPtr<ServiceWorkerProcessManager>& process_manager,
|
const base::WeakPtr<ServiceWorkerProcessManager>& process_manager,
|
||||||
int embedded_worker_id,
|
int embedded_worker_id,
|
||||||
int process_id,
|
int process_id)
|
||||||
scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
|
|
||||||
: process_manager_(process_manager),
|
: process_manager_(process_manager),
|
||||||
embedded_worker_id_(embedded_worker_id),
|
embedded_worker_id_(embedded_worker_id),
|
||||||
process_id_(process_id),
|
process_id_(process_id) {
|
||||||
ui_task_runner_(std::move(ui_task_runner)) {
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||||
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
|
|
||||||
DCHECK_NE(ChildProcessHost::kInvalidUniqueID, process_id_);
|
DCHECK_NE(ChildProcessHost::kInvalidUniqueID, process_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
~WorkerProcessHandle() {
|
~WorkerProcessHandle() {
|
||||||
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||||
process_manager_->ReleaseWorkerProcess(embedded_worker_id_);
|
process_manager_->ReleaseWorkerProcess(embedded_worker_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_id() const { return process_id_; }
|
int process_id() const { return process_id_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Can be dereferenced on the UI thread only.
|
|
||||||
base::WeakPtr<ServiceWorkerProcessManager> process_manager_;
|
base::WeakPtr<ServiceWorkerProcessManager> process_manager_;
|
||||||
|
|
||||||
const int embedded_worker_id_;
|
const int embedded_worker_id_;
|
||||||
const int process_id_;
|
const int process_id_;
|
||||||
const scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(WorkerProcessHandle);
|
DISALLOW_COPY_AND_ASSIGN(WorkerProcessHandle);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A task to allocate a worker process and to send a start worker message. This
|
// Info that is recorded as UMA on OnStarted().
|
||||||
// is created on EmbeddedWorkerInstance::Start(), owned by the instance and
|
struct EmbeddedWorkerInstance::StartInfo {
|
||||||
// destroyed on EmbeddedWorkerInstance::OnScriptEvaluated().
|
StartInfo(bool is_installed,
|
||||||
// We can abort starting worker by destroying this task anytime during the
|
bool skip_recording_startup_time,
|
||||||
// sequence.
|
|
||||||
// Lives on the core thread.
|
|
||||||
class EmbeddedWorkerInstance::StartTask {
|
|
||||||
public:
|
|
||||||
enum class ProcessAllocationState { NOT_ALLOCATED, ALLOCATING, ALLOCATED };
|
|
||||||
|
|
||||||
StartTask(EmbeddedWorkerInstance* instance,
|
|
||||||
const GURL& script_url,
|
|
||||||
mojo::PendingReceiver<blink::mojom::EmbeddedWorkerInstanceClient>
|
|
||||||
receiver,
|
|
||||||
base::TimeTicks start_time)
|
base::TimeTicks start_time)
|
||||||
: instance_(instance),
|
: is_installed(is_installed),
|
||||||
receiver_(std::move(receiver)),
|
skip_recording_startup_time(skip_recording_startup_time),
|
||||||
state_(ProcessAllocationState::NOT_ALLOCATED),
|
start_time(start_time) {}
|
||||||
is_installed_(false),
|
~StartInfo() = default;
|
||||||
started_during_browser_startup_(false),
|
|
||||||
skip_recording_startup_time_(instance_->devtools_attached()),
|
|
||||||
start_time_(start_time) {
|
|
||||||
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
|
|
||||||
TRACE_EVENT_WITH_FLOW1(
|
|
||||||
"ServiceWorker", "EmbeddedWorkerInstance::StartTask::StartTask",
|
|
||||||
TRACE_ID_WITH_SCOPE(kEmbeddedWorkerInstanceScope,
|
|
||||||
instance_->embedded_worker_id()),
|
|
||||||
TRACE_EVENT_FLAG_FLOW_OUT, "Script", script_url.spec());
|
|
||||||
}
|
|
||||||
|
|
||||||
~StartTask() {
|
|
||||||
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
|
|
||||||
TRACE_EVENT_WITH_FLOW0("ServiceWorker",
|
|
||||||
"EmbeddedWorkerInstance::StartTask::~StartTask",
|
|
||||||
TRACE_ID_WITH_SCOPE(kEmbeddedWorkerInstanceScope,
|
|
||||||
instance_->embedded_worker_id()),
|
|
||||||
TRACE_EVENT_FLAG_FLOW_IN);
|
|
||||||
if (!instance_->context_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (state_) {
|
|
||||||
case ProcessAllocationState::NOT_ALLOCATED:
|
|
||||||
// Not necessary to release a process.
|
|
||||||
break;
|
|
||||||
case ProcessAllocationState::ALLOCATING:
|
|
||||||
// Abort half-baked process allocation on the UI thread.
|
|
||||||
instance_->ui_task_runner_->PostTask(
|
|
||||||
FROM_HERE,
|
|
||||||
base::BindOnce(&ServiceWorkerProcessManager::ReleaseWorkerProcess,
|
|
||||||
instance_->context_->process_manager()->AsWeakPtr(),
|
|
||||||
instance_->embedded_worker_id()));
|
|
||||||
break;
|
|
||||||
case ProcessAllocationState::ALLOCATED:
|
|
||||||
// Otherwise, the process will be released by EmbeddedWorkerInstance.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't have to abort |sent_start_callback_| here. The caller of
|
|
||||||
// EmbeddedWorkerInstance::Start(), that is, ServiceWorkerVersion does not
|
|
||||||
// expect it when the start worker sequence is canceled by Stop() because
|
|
||||||
// the callback, ServiceWorkerVersion::OnStartSentAndScriptEvaluated(),
|
|
||||||
// could drain valid start requests queued in the version. After the worker
|
|
||||||
// is stopped, the version attempts to restart the worker if there are
|
|
||||||
// requests in the queue. See ServiceWorkerVersion::OnStoppedInternal() for
|
|
||||||
// details.
|
|
||||||
// TODO(crbug.com/859912): Reconsider this bizarre layering.
|
|
||||||
}
|
|
||||||
|
|
||||||
base::TimeTicks start_time() const { return start_time_; }
|
|
||||||
|
|
||||||
void set_start_worker_sent_time(base::TimeTicks time) {
|
|
||||||
start_worker_sent_time_ = time;
|
|
||||||
}
|
|
||||||
base::TimeTicks start_worker_sent_time() const {
|
|
||||||
return start_worker_sent_time_;
|
|
||||||
}
|
|
||||||
base::TimeDelta thread_hop_time() const { return thread_hop_time_; }
|
|
||||||
|
|
||||||
void set_skip_recording_startup_time() {
|
|
||||||
skip_recording_startup_time_ = true;
|
|
||||||
}
|
|
||||||
bool skip_recording_startup_time() const {
|
|
||||||
return skip_recording_startup_time_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Start(blink::mojom::EmbeddedWorkerStartParamsPtr params,
|
|
||||||
const base::Optional<network::CrossOriginEmbedderPolicy>&
|
|
||||||
cross_origin_embedder_policy,
|
|
||||||
StatusCallback sent_start_callback) {
|
|
||||||
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
|
|
||||||
DCHECK(instance_->context_);
|
|
||||||
TRACE_EVENT_WITH_FLOW0(
|
|
||||||
"ServiceWorker", "EmbeddedWorkerInstance::StartTask::Start",
|
|
||||||
TRACE_ID_WITH_SCOPE(kEmbeddedWorkerInstanceScope,
|
|
||||||
instance_->embedded_worker_id()),
|
|
||||||
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
|
|
||||||
|
|
||||||
base::WeakPtr<ServiceWorkerContextCore> context = instance_->context_;
|
|
||||||
state_ = ProcessAllocationState::ALLOCATING;
|
|
||||||
sent_start_callback_ = std::move(sent_start_callback);
|
|
||||||
is_installed_ = params->is_installed;
|
|
||||||
|
|
||||||
if (!GetContentClient()->browser()->IsBrowserStartupComplete())
|
|
||||||
started_during_browser_startup_ = true;
|
|
||||||
|
|
||||||
bool can_use_existing_process =
|
|
||||||
context->GetVersionFailureCount(params->service_worker_version_id) <
|
|
||||||
kMaxSameProcessFailureCount;
|
|
||||||
base::WeakPtr<ServiceWorkerProcessManager> process_manager =
|
|
||||||
context->process_manager()->AsWeakPtr();
|
|
||||||
|
|
||||||
// Perform process allocation and setup on the UI thread. We will continue
|
|
||||||
// on the core thread in StartTask::OnSetupCompleted().
|
|
||||||
SetupOnUIThread(
|
|
||||||
instance_->embedded_worker_id(), process_manager,
|
|
||||||
can_use_existing_process, cross_origin_embedder_policy,
|
|
||||||
std::move(params), std::move(receiver_),
|
|
||||||
base::WrapRefCounted(context->wrapper()), base::nullopt,
|
|
||||||
base::BindOnce(&StartTask::OnSetupCompleted, weak_factory_.GetWeakPtr(),
|
|
||||||
process_manager));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_installed() const { return is_installed_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnSetupCompleted(
|
|
||||||
base::WeakPtr<ServiceWorkerProcessManager> process_manager,
|
|
||||||
blink::ServiceWorkerStatusCode status,
|
|
||||||
blink::mojom::EmbeddedWorkerStartParamsPtr params,
|
|
||||||
std::unique_ptr<ServiceWorkerProcessManager::AllocatedProcessInfo>
|
|
||||||
process_info,
|
|
||||||
std::unique_ptr<EmbeddedWorkerInstance::DevToolsProxy> devtools_proxy,
|
|
||||||
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
|
|
||||||
factory_bundle_for_new_scripts,
|
|
||||||
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
|
|
||||||
factory_bundle_for_renderer,
|
|
||||||
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
|
|
||||||
coep_reporter,
|
|
||||||
mojo::PendingReceiver<blink::mojom::ReportingObserver>
|
|
||||||
reporting_observer_receiver,
|
|
||||||
const base::Optional<base::TimeDelta>& thread_hop_time,
|
|
||||||
const base::Optional<base::Time>& ui_post_time) {
|
|
||||||
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
|
|
||||||
|
|
||||||
if (reporting_observer_receiver) {
|
|
||||||
instance_->owner_version_->set_reporting_observer_receiver(
|
|
||||||
std::move(reporting_observer_receiver));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<WorkerProcessHandle> process_handle;
|
|
||||||
if (status == blink::ServiceWorkerStatusCode::kOk) {
|
|
||||||
// If we allocated a process, WorkerProcessHandle has to be created before
|
|
||||||
// returning to ensure the process is eventually released.
|
|
||||||
process_handle = std::make_unique<WorkerProcessHandle>(
|
|
||||||
process_manager, instance_->embedded_worker_id(),
|
|
||||||
process_info->process_id, instance_->ui_task_runner_);
|
|
||||||
|
|
||||||
if (!instance_->context_)
|
|
||||||
status = blink::ServiceWorkerStatusCode::kErrorAbort;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != blink::ServiceWorkerStatusCode::kOk) {
|
|
||||||
TRACE_EVENT_WITH_FLOW1(
|
|
||||||
"ServiceWorker",
|
|
||||||
"EmbeddedWorkerInstance::StartTask::OnSetupCompleted",
|
|
||||||
TRACE_ID_WITH_SCOPE(kEmbeddedWorkerInstanceScope,
|
|
||||||
instance_->embedded_worker_id()),
|
|
||||||
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "Error",
|
|
||||||
blink::ServiceWorkerStatusToString(status));
|
|
||||||
instance_->OnSetupFailed(std::move(sent_start_callback_), status);
|
|
||||||
// |this| may be destroyed.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceWorkerMetrics::StartSituation start_situation =
|
|
||||||
process_info->start_situation;
|
|
||||||
TRACE_EVENT_WITH_FLOW1(
|
|
||||||
"ServiceWorker", "EmbeddedWorkerInstance::StartTask::OnSetupCompleted",
|
|
||||||
TRACE_ID_WITH_SCOPE(kEmbeddedWorkerInstanceScope,
|
|
||||||
instance_->embedded_worker_id()),
|
|
||||||
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "StartSituation",
|
|
||||||
ServiceWorkerMetrics::StartSituationToString(start_situation));
|
|
||||||
|
|
||||||
if (started_during_browser_startup_)
|
|
||||||
start_situation = ServiceWorkerMetrics::StartSituation::DURING_STARTUP;
|
|
||||||
|
|
||||||
// Notify the instance that a process is allocated.
|
|
||||||
state_ = ProcessAllocationState::ALLOCATED;
|
|
||||||
instance_->OnProcessAllocated(std::move(process_handle), start_situation);
|
|
||||||
|
|
||||||
// Notify the instance that it is registered to the DevTools manager.
|
|
||||||
instance_->OnRegisteredToDevToolsManager(std::move(devtools_proxy),
|
|
||||||
params->wait_for_debugger);
|
|
||||||
|
|
||||||
// Send the factory bundle for subresource loading from the service worker
|
|
||||||
// (i.e. fetch()).
|
|
||||||
DCHECK(factory_bundle_for_renderer);
|
|
||||||
params->subresource_loader_factories =
|
|
||||||
std::move(factory_bundle_for_renderer);
|
|
||||||
|
|
||||||
// Build the URLLoaderFactory for loading new scripts, it's only needed if
|
|
||||||
// this is a non-installed service worker.
|
|
||||||
DCHECK(factory_bundle_for_new_scripts || is_installed_);
|
|
||||||
if (factory_bundle_for_new_scripts) {
|
|
||||||
params->provider_info->script_loader_factory_remote =
|
|
||||||
instance_->MakeScriptLoaderFactoryRemote(
|
|
||||||
std::move(factory_bundle_for_new_scripts));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind COEP reporter created on the UI thread, which has the onwership of
|
|
||||||
// the instance. The |coep_reporter| might be null when the COEP value is
|
|
||||||
// not known because the main script has not been loaded yet. In that case,
|
|
||||||
// COEP reporter will be bound after the main script is loaded.
|
|
||||||
if (coep_reporter) {
|
|
||||||
instance_->coep_reporter_.Bind(std::move(coep_reporter));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create cache storage now as an optimization, so the service worker can
|
|
||||||
// use the Cache Storage API immediately on startup.
|
|
||||||
if (base::FeatureList::IsEnabled(
|
|
||||||
blink::features::kEagerCacheStorageSetupForServiceWorkers)) {
|
|
||||||
instance_->BindCacheStorage(params->provider_info->cache_storage
|
|
||||||
.InitWithNewPipeAndPassReceiver());
|
|
||||||
}
|
|
||||||
|
|
||||||
instance_->SendStartWorker(std::move(params));
|
|
||||||
std::move(sent_start_callback_).Run(blink::ServiceWorkerStatusCode::kOk);
|
|
||||||
|
|
||||||
// |this|'s work is done here, but |instance_| still uses its state until
|
|
||||||
// startup is complete.
|
|
||||||
}
|
|
||||||
|
|
||||||
// |instance_| must outlive |this|.
|
|
||||||
EmbeddedWorkerInstance* instance_;
|
|
||||||
|
|
||||||
// Ownership is transferred by a PostTask() call after process allocation.
|
|
||||||
mojo::PendingReceiver<blink::mojom::EmbeddedWorkerInstanceClient> receiver_;
|
|
||||||
|
|
||||||
StatusCallback sent_start_callback_;
|
|
||||||
ProcessAllocationState state_;
|
|
||||||
|
|
||||||
// Used for UMA.
|
// Used for UMA.
|
||||||
bool is_installed_;
|
const bool is_installed;
|
||||||
bool started_during_browser_startup_;
|
bool skip_recording_startup_time;
|
||||||
bool skip_recording_startup_time_;
|
const base::TimeTicks start_time;
|
||||||
base::TimeTicks start_time_;
|
base::TimeTicks start_worker_sent_time;
|
||||||
base::TimeTicks start_worker_sent_time_;
|
|
||||||
base::TimeDelta thread_hop_time_;
|
|
||||||
|
|
||||||
base::WeakPtrFactory<StartTask> weak_factory_{this};
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(StartTask);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
|
EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
|
||||||
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||||
ReleaseProcess();
|
ReleaseProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmbeddedWorkerInstance::Start(
|
void EmbeddedWorkerInstance::Start(
|
||||||
blink::mojom::EmbeddedWorkerStartParamsPtr params,
|
blink::mojom::EmbeddedWorkerStartParamsPtr params,
|
||||||
StatusCallback callback) {
|
StatusCallback callback) {
|
||||||
|
TRACE_EVENT1("ServiceWorker", "EmbeddedWorkerInstance::Start", "script_url",
|
||||||
|
params->script_url.spec());
|
||||||
|
|
||||||
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||||
DCHECK(context_);
|
DCHECK(context_);
|
||||||
restart_count_++;
|
restart_count_++;
|
||||||
DCHECK_EQ(EmbeddedWorkerStatus::STOPPED, status_);
|
DCHECK_EQ(EmbeddedWorkerStatus::STOPPED, status_);
|
||||||
@@ -722,15 +284,192 @@ void EmbeddedWorkerInstance::Start(
|
|||||||
// check is_bound strictly.
|
// check is_bound strictly.
|
||||||
client_.reset();
|
client_.reset();
|
||||||
|
|
||||||
mojo::PendingReceiver<blink::mojom::EmbeddedWorkerInstanceClient> receiver =
|
auto process_info =
|
||||||
client_.BindNewPipeAndPassReceiver();
|
std::make_unique<ServiceWorkerProcessManager::AllocatedProcessInfo>();
|
||||||
|
std::unique_ptr<EmbeddedWorkerInstance::DevToolsProxy> devtools_proxy;
|
||||||
|
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
|
||||||
|
factory_bundle_for_new_scripts;
|
||||||
|
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
|
||||||
|
factory_bundle_for_renderer;
|
||||||
|
mojo::PendingReceiver<blink::mojom::ReportingObserver>
|
||||||
|
reporting_observer_receiver;
|
||||||
|
|
||||||
|
ServiceWorkerProcessManager* process_manager = context_->process_manager();
|
||||||
|
if (!process_manager) {
|
||||||
|
OnSetupFailed(std::move(callback),
|
||||||
|
blink::ServiceWorkerStatusCode::kErrorAbort);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a process.
|
||||||
|
bool can_use_existing_process =
|
||||||
|
context_->GetVersionFailureCount(params->service_worker_version_id) <
|
||||||
|
kMaxSameProcessFailureCount;
|
||||||
|
blink::ServiceWorkerStatusCode status =
|
||||||
|
process_manager->AllocateWorkerProcess(
|
||||||
|
embedded_worker_id(), params->script_url,
|
||||||
|
owner_version_->cross_origin_embedder_policy(),
|
||||||
|
can_use_existing_process, process_info.get());
|
||||||
|
if (status != blink::ServiceWorkerStatusCode::kOk) {
|
||||||
|
OnSetupFailed(std::move(callback), status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int process_id = process_info->process_id;
|
||||||
|
RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
|
||||||
|
// TODO(falken): This CHECK should no longer fail, so turn to a DCHECK it if
|
||||||
|
// crash reports agree. Consider also checking for
|
||||||
|
// rph->IsInitializedAndNotDead().
|
||||||
|
CHECK(rph);
|
||||||
|
rph->BindReceiver(client_.BindNewPipeAndPassReceiver());
|
||||||
client_.set_disconnect_handler(
|
client_.set_disconnect_handler(
|
||||||
base::BindOnce(&EmbeddedWorkerInstance::Detach, base::Unretained(this)));
|
base::BindOnce(&EmbeddedWorkerInstance::Detach, base::Unretained(this)));
|
||||||
inflight_start_task_.reset(
|
|
||||||
new StartTask(this, params->script_url, std::move(receiver), start_time));
|
{
|
||||||
inflight_start_task_->Start(std::move(params),
|
// Create COEP reporter if COEP value is already available (= this worker is
|
||||||
owner_version_->cross_origin_embedder_policy(),
|
// not a worker which is going to be newly registered). The Mojo remote
|
||||||
std::move(callback));
|
// `coep_reporter_` has the onwership of the instance. The `coep_reporter`
|
||||||
|
// might be kept null when the COEP value is not known because the main
|
||||||
|
// script has not been loaded yet. In that case, it will be bound after the
|
||||||
|
// main script is loaded.
|
||||||
|
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
|
||||||
|
coep_reporter_for_devtools;
|
||||||
|
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
|
||||||
|
coep_reporter_for_scripts;
|
||||||
|
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
|
||||||
|
coep_reporter_for_subresources;
|
||||||
|
if (owner_version_->cross_origin_embedder_policy()) {
|
||||||
|
mojo::PendingRemote<blink::mojom::ReportingObserver>
|
||||||
|
reporting_observer_remote;
|
||||||
|
owner_version_->set_reporting_observer_receiver(
|
||||||
|
reporting_observer_remote.InitWithNewPipeAndPassReceiver());
|
||||||
|
auto reporter = std::make_unique<CrossOriginEmbedderPolicyReporter>(
|
||||||
|
rph->GetStoragePartition(), params->script_url,
|
||||||
|
owner_version_->cross_origin_embedder_policy()->reporting_endpoint,
|
||||||
|
owner_version_->cross_origin_embedder_policy()
|
||||||
|
->report_only_reporting_endpoint,
|
||||||
|
// TODO(https://crbug.com/1147281): This is the NetworkIsolationKey of
|
||||||
|
// a top-level browsing context, which shouldn't be use for
|
||||||
|
// ServiceWorkers used in iframes.
|
||||||
|
net::NetworkIsolationKey::ToDoUseTopFrameOriginAsWell(
|
||||||
|
url::Origin::Create(params->script_url)));
|
||||||
|
reporter->BindObserver(std::move(reporting_observer_remote));
|
||||||
|
mojo::MakeSelfOwnedReceiver(std::move(reporter),
|
||||||
|
coep_reporter_.BindNewPipeAndPassReceiver());
|
||||||
|
|
||||||
|
coep_reporter_->Clone(
|
||||||
|
coep_reporter_for_devtools.InitWithNewPipeAndPassReceiver());
|
||||||
|
coep_reporter_->Clone(
|
||||||
|
coep_reporter_for_scripts.InitWithNewPipeAndPassReceiver());
|
||||||
|
coep_reporter_->Clone(
|
||||||
|
coep_reporter_for_subresources.InitWithNewPipeAndPassReceiver());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register to DevTools and update params accordingly.
|
||||||
|
const int routing_id = rph->GetNextRoutingID();
|
||||||
|
ServiceWorkerDevToolsManager::GetInstance()->WorkerStarting(
|
||||||
|
process_id, routing_id, context_->wrapper(),
|
||||||
|
params->service_worker_version_id, params->script_url, params->scope,
|
||||||
|
params->is_installed, owner_version_->cross_origin_embedder_policy(),
|
||||||
|
std::move(coep_reporter_for_devtools), ¶ms->devtools_worker_token,
|
||||||
|
¶ms->wait_for_debugger);
|
||||||
|
params->service_worker_route_id = routing_id;
|
||||||
|
// Create DevToolsProxy here to ensure that the WorkerCreated() call is
|
||||||
|
// balanced by DevToolsProxy's destructor calling WorkerStopped().
|
||||||
|
devtools_proxy = std::make_unique<EmbeddedWorkerInstance::DevToolsProxy>(
|
||||||
|
process_id, routing_id);
|
||||||
|
|
||||||
|
// Create factory bundles for this worker to do loading. These bundles don't
|
||||||
|
// support reconnection to the network service, see below comments.
|
||||||
|
const url::Origin origin = url::Origin::Create(params->script_url);
|
||||||
|
|
||||||
|
// The bundle for new scripts is passed to ServiceWorkerScriptLoaderFactory
|
||||||
|
// and used to request non-installed service worker scripts. It's only
|
||||||
|
// needed for non-installed workers. It's OK to not support reconnection to
|
||||||
|
// the network service because it can only used until the service worker
|
||||||
|
// reaches the 'installed' state.
|
||||||
|
if (!params->is_installed) {
|
||||||
|
factory_bundle_for_new_scripts =
|
||||||
|
EmbeddedWorkerInstance::CreateFactoryBundleOnUI(
|
||||||
|
rph, routing_id, origin,
|
||||||
|
owner_version_->cross_origin_embedder_policy(),
|
||||||
|
std::move(coep_reporter_for_scripts),
|
||||||
|
ContentBrowserClient::URLLoaderFactoryType::kServiceWorkerScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The bundle for the renderer is passed to the service worker, and
|
||||||
|
// used for subresource loading from the service worker (i.e., fetch()).
|
||||||
|
// It's OK to not support reconnection to the network service because the
|
||||||
|
// service worker terminates itself when the connection breaks, so a new
|
||||||
|
// instance can be started.
|
||||||
|
factory_bundle_for_renderer =
|
||||||
|
EmbeddedWorkerInstance::CreateFactoryBundleOnUI(
|
||||||
|
rph, routing_id, origin,
|
||||||
|
owner_version_->cross_origin_embedder_policy(),
|
||||||
|
std::move(coep_reporter_for_subresources),
|
||||||
|
ContentBrowserClient::URLLoaderFactoryType::
|
||||||
|
kServiceWorkerSubResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(crbug.com/862854): Support changes to blink::RendererPreferences while
|
||||||
|
// the worker is running.
|
||||||
|
DCHECK(process_manager->browser_context() || process_manager->IsShutdown());
|
||||||
|
params->renderer_preferences = blink::RendererPreferences();
|
||||||
|
GetContentClient()->browser()->UpdateRendererPreferencesForWorker(
|
||||||
|
process_manager->browser_context(), ¶ms->renderer_preferences);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Create a RendererPreferenceWatcher to observe updates in the preferences.
|
||||||
|
mojo::PendingRemote<blink::mojom::RendererPreferenceWatcher> watcher_remote;
|
||||||
|
params->preference_watcher_receiver =
|
||||||
|
watcher_remote.InitWithNewPipeAndPassReceiver();
|
||||||
|
GetContentClient()->browser()->RegisterRendererPreferenceWatcher(
|
||||||
|
process_manager->browser_context(), std::move(watcher_remote));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we allocated a process, WorkerProcessHandle has to be created before
|
||||||
|
// returning to ensure the process is eventually released.
|
||||||
|
auto process_handle = std::make_unique<WorkerProcessHandle>(
|
||||||
|
process_manager->AsWeakPtr(), embedded_worker_id(),
|
||||||
|
process_info->process_id);
|
||||||
|
|
||||||
|
ServiceWorkerMetrics::StartSituation start_situation =
|
||||||
|
process_info->start_situation;
|
||||||
|
if (!GetContentClient()->browser()->IsBrowserStartupComplete())
|
||||||
|
start_situation = ServiceWorkerMetrics::StartSituation::DURING_STARTUP;
|
||||||
|
|
||||||
|
// Notify the instance that a process is allocated.
|
||||||
|
OnProcessAllocated(std::move(process_handle), start_situation);
|
||||||
|
|
||||||
|
// Notify the instance that it is registered to the DevTools manager.
|
||||||
|
OnRegisteredToDevToolsManager(std::move(devtools_proxy));
|
||||||
|
|
||||||
|
// Send the factory bundle for subresource loading from the service worker
|
||||||
|
// (i.e. fetch()).
|
||||||
|
DCHECK(factory_bundle_for_renderer);
|
||||||
|
params->subresource_loader_factories = std::move(factory_bundle_for_renderer);
|
||||||
|
|
||||||
|
// Build the URLLoaderFactory for loading new scripts, it's only needed if
|
||||||
|
// this is a non-installed service worker.
|
||||||
|
DCHECK(factory_bundle_for_new_scripts || params->is_installed);
|
||||||
|
if (factory_bundle_for_new_scripts) {
|
||||||
|
params->provider_info->script_loader_factory_remote =
|
||||||
|
MakeScriptLoaderFactoryRemote(
|
||||||
|
std::move(factory_bundle_for_new_scripts));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create cache storage now as an optimization, so the service worker can
|
||||||
|
// use the Cache Storage API immediately on startup.
|
||||||
|
if (base::FeatureList::IsEnabled(
|
||||||
|
blink::features::kEagerCacheStorageSetupForServiceWorkers)) {
|
||||||
|
BindCacheStorage(
|
||||||
|
params->provider_info->cache_storage.InitWithNewPipeAndPassReceiver());
|
||||||
|
}
|
||||||
|
|
||||||
|
inflight_start_info_ = std::make_unique<StartInfo>(
|
||||||
|
params->is_installed, params->wait_for_debugger, start_time);
|
||||||
|
|
||||||
|
SendStartWorker(std::move(params));
|
||||||
|
std::move(callback).Run(blink::ServiceWorkerStatusCode::kOk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmbeddedWorkerInstance::Stop() {
|
void EmbeddedWorkerInstance::Stop() {
|
||||||
@@ -738,8 +477,9 @@ void EmbeddedWorkerInstance::Stop() {
|
|||||||
status_ == EmbeddedWorkerStatus::RUNNING)
|
status_ == EmbeddedWorkerStatus::RUNNING)
|
||||||
<< static_cast<int>(status_);
|
<< static_cast<int>(status_);
|
||||||
|
|
||||||
// Abort an inflight start task.
|
// Discard the info for starting a worker because this worker is going to be
|
||||||
inflight_start_task_.reset();
|
// stopped.
|
||||||
|
inflight_start_info_.reset();
|
||||||
|
|
||||||
// Don't send the StopWorker message if the StartWorker message hasn't
|
// Don't send the StopWorker message if the StartWorker message hasn't
|
||||||
// been sent.
|
// been sent.
|
||||||
@@ -785,8 +525,7 @@ EmbeddedWorkerInstance::EmbeddedWorkerInstance(
|
|||||||
thread_id_(ServiceWorkerConsts::kInvalidEmbeddedWorkerThreadId),
|
thread_id_(ServiceWorkerConsts::kInvalidEmbeddedWorkerThreadId),
|
||||||
devtools_attached_(false),
|
devtools_attached_(false),
|
||||||
network_accessed_for_script_(false),
|
network_accessed_for_script_(false),
|
||||||
foreground_notified_(false),
|
foreground_notified_(false) {
|
||||||
ui_task_runner_(GetUIThreadTaskRunner({})) {
|
|
||||||
DCHECK(owner_version_);
|
DCHECK(owner_version_);
|
||||||
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
|
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
|
||||||
DCHECK(context_);
|
DCHECK(context_);
|
||||||
@@ -808,14 +547,11 @@ void EmbeddedWorkerInstance::OnProcessAllocated(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmbeddedWorkerInstance::OnRegisteredToDevToolsManager(
|
void EmbeddedWorkerInstance::OnRegisteredToDevToolsManager(
|
||||||
std::unique_ptr<DevToolsProxy> devtools_proxy,
|
std::unique_ptr<DevToolsProxy> devtools_proxy) {
|
||||||
bool wait_for_debugger) {
|
|
||||||
if (devtools_proxy) {
|
if (devtools_proxy) {
|
||||||
DCHECK(!devtools_proxy_);
|
DCHECK(!devtools_proxy_);
|
||||||
devtools_proxy_ = std::move(devtools_proxy);
|
devtools_proxy_ = std::move(devtools_proxy);
|
||||||
}
|
}
|
||||||
if (wait_for_debugger)
|
|
||||||
inflight_start_task_->set_skip_recording_startup_time();
|
|
||||||
for (auto& observer : listener_list_)
|
for (auto& observer : listener_list_)
|
||||||
observer.OnRegisteredToDevToolsManager();
|
observer.OnRegisteredToDevToolsManager();
|
||||||
}
|
}
|
||||||
@@ -837,7 +573,7 @@ void EmbeddedWorkerInstance::SendStartWorker(
|
|||||||
params->content_settings_proxy.InitWithNewPipeAndPassReceiver());
|
params->content_settings_proxy.InitWithNewPipeAndPassReceiver());
|
||||||
|
|
||||||
const bool is_script_streaming = !params->installed_scripts_info.is_null();
|
const bool is_script_streaming = !params->installed_scripts_info.is_null();
|
||||||
inflight_start_task_->set_start_worker_sent_time(base::TimeTicks::Now());
|
inflight_start_info_->start_worker_sent_time = base::TimeTicks::Now();
|
||||||
|
|
||||||
// The host must be alive as long as |params->provider_info| is alive.
|
// The host must be alive as long as |params->provider_info| is alive.
|
||||||
owner_version_->worker_host()->CompleteStartWorkerPreparation(
|
owner_version_->worker_host()->CompleteStartWorkerPreparation(
|
||||||
@@ -889,7 +625,7 @@ void EmbeddedWorkerInstance::OnReadyForInspection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmbeddedWorkerInstance::OnScriptLoaded() {
|
void EmbeddedWorkerInstance::OnScriptLoaded() {
|
||||||
if (!inflight_start_task_)
|
if (!inflight_start_info_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Renderer side has started to launch the worker thread.
|
// Renderer side has started to launch the worker thread.
|
||||||
@@ -909,7 +645,7 @@ void EmbeddedWorkerInstance::OnWorkerVersionDoomed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmbeddedWorkerInstance::OnScriptEvaluationStart() {
|
void EmbeddedWorkerInstance::OnScriptEvaluationStart() {
|
||||||
if (!inflight_start_task_)
|
if (!inflight_start_info_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
starting_phase_ = SCRIPT_EVALUATION;
|
starting_phase_ = SCRIPT_EVALUATION;
|
||||||
@@ -940,12 +676,12 @@ void EmbeddedWorkerInstance::OnStarted(
|
|||||||
if (status_ == EmbeddedWorkerStatus::STOPPING)
|
if (status_ == EmbeddedWorkerStatus::STOPPING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (inflight_start_task_->is_installed() &&
|
if (inflight_start_info_->is_installed &&
|
||||||
!inflight_start_task_->skip_recording_startup_time()) {
|
!inflight_start_info_->skip_recording_startup_time) {
|
||||||
ServiceWorkerMetrics::StartTimes times;
|
ServiceWorkerMetrics::StartTimes times;
|
||||||
times.local_start = inflight_start_task_->start_time();
|
times.local_start = inflight_start_info_->start_time;
|
||||||
times.local_start_worker_sent =
|
times.local_start_worker_sent =
|
||||||
inflight_start_task_->start_worker_sent_time();
|
inflight_start_info_->start_worker_sent_time;
|
||||||
times.remote_start_worker_received =
|
times.remote_start_worker_received =
|
||||||
start_timing->start_worker_received_time;
|
start_timing->start_worker_received_time;
|
||||||
times.remote_script_evaluation_start =
|
times.remote_script_evaluation_start =
|
||||||
@@ -953,7 +689,6 @@ void EmbeddedWorkerInstance::OnStarted(
|
|||||||
times.remote_script_evaluation_end =
|
times.remote_script_evaluation_end =
|
||||||
start_timing->script_evaluation_end_time;
|
start_timing->script_evaluation_end_time;
|
||||||
times.local_end = base::TimeTicks::Now();
|
times.local_end = base::TimeTicks::Now();
|
||||||
times.thread_hop_time = inflight_start_task_->thread_hop_time();
|
|
||||||
|
|
||||||
ServiceWorkerMetrics::RecordStartWorkerTiming(times, start_situation_);
|
ServiceWorkerMetrics::RecordStartWorkerTiming(times, start_situation_);
|
||||||
}
|
}
|
||||||
@@ -961,7 +696,7 @@ void EmbeddedWorkerInstance::OnStarted(
|
|||||||
DCHECK_EQ(EmbeddedWorkerStatus::STARTING, status_);
|
DCHECK_EQ(EmbeddedWorkerStatus::STARTING, status_);
|
||||||
status_ = EmbeddedWorkerStatus::RUNNING;
|
status_ = EmbeddedWorkerStatus::RUNNING;
|
||||||
thread_id_ = thread_id;
|
thread_id_ = thread_id;
|
||||||
inflight_start_task_.reset();
|
inflight_start_info_.reset();
|
||||||
for (auto& observer : listener_list_) {
|
for (auto& observer : listener_list_) {
|
||||||
observer.OnStarted(start_status, has_fetch_handler);
|
observer.OnStarted(start_status, has_fetch_handler);
|
||||||
// |this| may be destroyed here. Fortunately we know there is only one
|
// |this| may be destroyed here. Fortunately we know there is only one
|
||||||
@@ -1242,8 +977,8 @@ void EmbeddedWorkerInstance::SetDevToolsAttached(bool attached) {
|
|||||||
devtools_attached_ = attached;
|
devtools_attached_ = attached;
|
||||||
if (!attached)
|
if (!attached)
|
||||||
return;
|
return;
|
||||||
if (inflight_start_task_)
|
if (inflight_start_info_)
|
||||||
inflight_start_task_->set_skip_recording_startup_time();
|
inflight_start_info_->skip_recording_startup_time = true;
|
||||||
AbortLifetimeTracking();
|
AbortLifetimeTracking();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1261,7 +996,7 @@ void EmbeddedWorkerInstance::OnNetworkAccessedForScriptLoad() {
|
|||||||
|
|
||||||
void EmbeddedWorkerInstance::ReleaseProcess() {
|
void EmbeddedWorkerInstance::ReleaseProcess() {
|
||||||
// Abort an inflight start task.
|
// Abort an inflight start task.
|
||||||
inflight_start_task_.reset();
|
inflight_start_info_.reset();
|
||||||
|
|
||||||
NotifyForegroundServiceWorkerRemoved();
|
NotifyForegroundServiceWorkerRemoved();
|
||||||
|
|
||||||
|
@@ -59,7 +59,7 @@ FORWARD_DECLARE_TEST(ServiceWorkerNewScriptLoaderTest, AccessedNetwork);
|
|||||||
// may be 'in-waiting' or running in one of the child processes added by
|
// may be 'in-waiting' or running in one of the child processes added by
|
||||||
// AddProcessReference().
|
// AddProcessReference().
|
||||||
//
|
//
|
||||||
// Owned by ServiceWorkerVersion. Lives on the core thread.
|
// Owned by ServiceWorkerVersion.
|
||||||
class CONTENT_EXPORT EmbeddedWorkerInstance
|
class CONTENT_EXPORT EmbeddedWorkerInstance
|
||||||
: public blink::mojom::EmbeddedWorkerInstanceHost {
|
: public blink::mojom::EmbeddedWorkerInstanceHost {
|
||||||
public:
|
public:
|
||||||
@@ -264,7 +264,7 @@ class CONTENT_EXPORT EmbeddedWorkerInstance
|
|||||||
private:
|
private:
|
||||||
typedef base::ObserverList<Listener>::Unchecked ListenerList;
|
typedef base::ObserverList<Listener>::Unchecked ListenerList;
|
||||||
class ScopedLifetimeTracker;
|
class ScopedLifetimeTracker;
|
||||||
class StartTask;
|
struct StartInfo;
|
||||||
class WorkerProcessHandle;
|
class WorkerProcessHandle;
|
||||||
friend class EmbeddedWorkerInstanceTest;
|
friend class EmbeddedWorkerInstanceTest;
|
||||||
FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, StartAndStop);
|
FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, StartAndStop);
|
||||||
@@ -274,21 +274,14 @@ class CONTENT_EXPORT EmbeddedWorkerInstance
|
|||||||
ServiceWorkerNewScriptLoaderTest,
|
ServiceWorkerNewScriptLoaderTest,
|
||||||
AccessedNetwork);
|
AccessedNetwork);
|
||||||
|
|
||||||
// Called back from StartTask after a process is allocated on the UI thread.
|
|
||||||
void OnProcessAllocated(std::unique_ptr<WorkerProcessHandle> handle,
|
void OnProcessAllocated(std::unique_ptr<WorkerProcessHandle> handle,
|
||||||
ServiceWorkerMetrics::StartSituation start_situation);
|
ServiceWorkerMetrics::StartSituation start_situation);
|
||||||
|
|
||||||
// Called back from StartTask after the worker is registered to
|
|
||||||
// WorkerDevToolsManager.
|
|
||||||
void OnRegisteredToDevToolsManager(
|
void OnRegisteredToDevToolsManager(
|
||||||
std::unique_ptr<DevToolsProxy> devtools_proxy,
|
std::unique_ptr<DevToolsProxy> devtools_proxy);
|
||||||
bool wait_for_debugger);
|
|
||||||
|
|
||||||
// Sends the StartWorker message to the renderer.
|
// Sends the StartWorker message to the renderer.
|
||||||
void SendStartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr params);
|
void SendStartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr params);
|
||||||
|
|
||||||
// Implements blink::mojom::EmbeddedWorkerInstanceHost.
|
// Implements blink::mojom::EmbeddedWorkerInstanceHost.
|
||||||
// These functions all run on the core thread.
|
|
||||||
void RequestTermination(RequestTerminationCallback callback) override;
|
void RequestTermination(RequestTerminationCallback callback) override;
|
||||||
void CountFeature(blink::mojom::WebFeature feature) override;
|
void CountFeature(blink::mojom::WebFeature feature) override;
|
||||||
void OnReadyForInspection(
|
void OnReadyForInspection(
|
||||||
@@ -325,7 +318,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance
|
|||||||
blink::ServiceWorkerStatusCode status);
|
blink::ServiceWorkerStatusCode status);
|
||||||
|
|
||||||
// Called when a foreground service worker is added/removed in a process.
|
// Called when a foreground service worker is added/removed in a process.
|
||||||
// Called on the core thread and dispatches task to the UI thread.
|
|
||||||
void NotifyForegroundServiceWorkerAdded();
|
void NotifyForegroundServiceWorkerAdded();
|
||||||
void NotifyForegroundServiceWorkerRemoved();
|
void NotifyForegroundServiceWorkerRemoved();
|
||||||
|
|
||||||
@@ -354,7 +346,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance
|
|||||||
// using it. The renderer process will disconnect the pipe when appropriate.
|
// using it. The renderer process will disconnect the pipe when appropriate.
|
||||||
mojo::Remote<blink::mojom::EmbeddedWorkerInstanceClient> client_;
|
mojo::Remote<blink::mojom::EmbeddedWorkerInstanceClient> client_;
|
||||||
|
|
||||||
// Receiver for EmbeddedWorkerInstanceHost, runs on core thread.
|
|
||||||
mojo::AssociatedReceiver<EmbeddedWorkerInstanceHost> instance_host_receiver_{
|
mojo::AssociatedReceiver<EmbeddedWorkerInstanceHost> instance_host_receiver_{
|
||||||
this};
|
this};
|
||||||
|
|
||||||
@@ -372,7 +363,9 @@ class CONTENT_EXPORT EmbeddedWorkerInstance
|
|||||||
ListenerList listener_list_;
|
ListenerList listener_list_;
|
||||||
std::unique_ptr<DevToolsProxy> devtools_proxy_;
|
std::unique_ptr<DevToolsProxy> devtools_proxy_;
|
||||||
|
|
||||||
std::unique_ptr<StartTask> inflight_start_task_;
|
// Contains info to be recorded on completing StartWorker sequence.
|
||||||
|
// Set on Start() and cleared on OnStarted().
|
||||||
|
std::unique_ptr<StartInfo> inflight_start_info_;
|
||||||
std::unique_ptr<ScopedLifetimeTracker> lifetime_tracker_;
|
std::unique_ptr<ScopedLifetimeTracker> lifetime_tracker_;
|
||||||
|
|
||||||
// This is valid only after a process is allocated for the worker.
|
// This is valid only after a process is allocated for the worker.
|
||||||
@@ -386,8 +379,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance
|
|||||||
mojo::SelfOwnedReceiverRef<network::mojom::URLLoaderFactory>
|
mojo::SelfOwnedReceiverRef<network::mojom::URLLoaderFactory>
|
||||||
script_loader_factory_;
|
script_loader_factory_;
|
||||||
|
|
||||||
const scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
|
|
||||||
|
|
||||||
// Remote interface to talk to a running service worker. Used to update
|
// Remote interface to talk to a running service worker. Used to update
|
||||||
// subresource loader factories in the service worker.
|
// subresource loader factories in the service worker.
|
||||||
mojo::Remote<blink::mojom::SubresourceLoaderUpdater>
|
mojo::Remote<blink::mojom::SubresourceLoaderUpdater>
|
||||||
|
@@ -157,9 +157,6 @@ class ServiceWorkerMetrics {
|
|||||||
|
|
||||||
// The browser received the worker started IPC.
|
// The browser received the worker started IPC.
|
||||||
base::TimeTicks local_end;
|
base::TimeTicks local_end;
|
||||||
|
|
||||||
// Counts the time overhead of UI/IO thread hops during startup.
|
|
||||||
base::TimeDelta thread_hop_time;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Converts an event type to a string. Used for tracing.
|
// Converts an event type to a string. Used for tracing.
|
||||||
|
Reference in New Issue
Block a user