blob: b6545a1937d54986508692fd73d5a4146f32e4c4 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/task_manager/providers/service_worker_task_provider.h"
#include "base/stl_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/service_worker_running_info.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/child_process_host.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
using content::BrowserThread;
namespace task_manager {
ServiceWorkerTaskProvider::ServiceWorkerTaskProvider() = default;
ServiceWorkerTaskProvider::~ServiceWorkerTaskProvider() = default;
Task* ServiceWorkerTaskProvider::GetTaskOfUrlRequest(int child_id,
int route_id) {
return nullptr;
}
void ServiceWorkerTaskProvider::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PROFILE_CREATED: {
OnProfileCreated(content::Source<Profile>(source).ptr());
break;
}
default:
NOTREACHED() << type;
}
}
void ServiceWorkerTaskProvider::OnVersionStartedRunning(
content::ServiceWorkerContext* context,
int64_t version_id,
const content::ServiceWorkerRunningInfo& running_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
CreateTask(context, version_id, running_info);
}
void ServiceWorkerTaskProvider::OnVersionStoppedRunning(
content::ServiceWorkerContext* context,
int64_t version_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DeleteTask(context, version_id);
}
void ServiceWorkerTaskProvider::OnDestruct(
content::ServiceWorkerContext* context) {
scoped_context_observer_.Remove(context);
}
void ServiceWorkerTaskProvider::StartUpdating() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
content::NotificationService::AllBrowserContextsAndSources());
ProfileManager* profile_manager = g_browser_process->profile_manager();
if (profile_manager) {
auto loaded_profiles = profile_manager->GetLoadedProfiles();
for (auto* profile : loaded_profiles) {
CreateTasksForProfile(profile);
// If the incognito window is open, we have to check its profile and
// create the tasks if there are any.
if (profile->HasOffTheRecordProfile())
CreateTasksForProfile(profile->GetOffTheRecordProfile());
}
}
}
void ServiceWorkerTaskProvider::StopUpdating() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Stop listening to NOTIFICATION_PROFILE_CREATED.
registrar_.RemoveAll();
// Stop observing contexts.
scoped_context_observer_.RemoveAll();
// Delete all tracked tasks.
service_worker_task_map_.clear();
}
void ServiceWorkerTaskProvider::CreateTasksForProfile(Profile* profile) {
content::ServiceWorkerContext* context =
content::BrowserContext::GetDefaultStoragePartition(profile)
->GetServiceWorkerContext();
if (!scoped_context_observer_.IsObserving(context))
scoped_context_observer_.Add(context);
for (const auto& kv : context->GetRunningServiceWorkerInfos()) {
const int64_t version_id = kv.first;
const content::ServiceWorkerRunningInfo& running_info = kv.second;
CreateTask(context, version_id, running_info);
}
}
void ServiceWorkerTaskProvider::CreateTask(
content::ServiceWorkerContext* context,
int64_t version_id,
const content::ServiceWorkerRunningInfo& running_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const ServiceWorkerTaskKey key(context, version_id);
DCHECK(!base::Contains(service_worker_task_map_, key));
const int render_process_id = running_info.render_process_id;
auto* host = content::RenderProcessHost::FromID(render_process_id);
auto result = service_worker_task_map_.emplace(
key, std::make_unique<ServiceWorkerTask>(host->GetProcess().Handle(),
render_process_id,
running_info.script_url));
DCHECK(result.second);
NotifyObserverTaskAdded(result.first->second.get());
}
void ServiceWorkerTaskProvider::DeleteTask(
content::ServiceWorkerContext* context,
int version_id) {
const ServiceWorkerTaskKey key(context, version_id);
auto it = service_worker_task_map_.find(key);
DCHECK(it != service_worker_task_map_.end());
NotifyObserverTaskRemoved(it->second.get());
service_worker_task_map_.erase(it);
}
void ServiceWorkerTaskProvider::OnProfileCreated(Profile* profile) {
content::ServiceWorkerContext* context =
content::BrowserContext::GetDefaultStoragePartition(profile)
->GetServiceWorkerContext();
scoped_context_observer_.Add(context);
}
} // namespace task_manager