Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "content/browser/service_worker/service_worker_dispatcher_host.h" | 5 #include "content/browser/service_worker/service_worker_dispatcher_host.h" | 
| 6 | 6 | 
| 7 #include <stdint.h> | 7 #include <stdint.h> | 
| 8 #include <utility> | 8 #include <utility> | 
| 9 | 9 | 
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" | 
| 11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" | 
| 12 #include "base/run_loop.h" | 12 #include "base/run_loop.h" | 
| 13 #include "content/browser/browser_thread_impl.h" | 13 #include "content/browser/browser_thread_impl.h" | 
| 14 #include "content/browser/message_port_service.h" | |
| 14 #include "content/browser/service_worker/embedded_worker_instance.h" | 15 #include "content/browser/service_worker/embedded_worker_instance.h" | 
| 15 #include "content/browser/service_worker/embedded_worker_registry.h" | 16 #include "content/browser/service_worker/embedded_worker_registry.h" | 
| 16 #include "content/browser/service_worker/embedded_worker_test_helper.h" | 17 #include "content/browser/service_worker/embedded_worker_test_helper.h" | 
| 17 #include "content/browser/service_worker/service_worker_context_core.h" | 18 #include "content/browser/service_worker/service_worker_context_core.h" | 
| 18 #include "content/browser/service_worker/service_worker_context_wrapper.h" | 19 #include "content/browser/service_worker/service_worker_context_wrapper.h" | 
| 20 #include "content/browser/service_worker/service_worker_handle.h" | |
| 19 #include "content/common/service_worker/embedded_worker_messages.h" | 21 #include "content/common/service_worker/embedded_worker_messages.h" | 
| 20 #include "content/common/service_worker/service_worker_messages.h" | 22 #include "content/common/service_worker/service_worker_messages.h" | 
| 21 #include "content/public/common/content_switches.h" | 23 #include "content/public/common/content_switches.h" | 
| 22 #include "content/public/test/mock_resource_context.h" | 24 #include "content/public/test/mock_resource_context.h" | 
| 23 #include "content/public/test/test_browser_thread_bundle.h" | 25 #include "content/public/test/test_browser_thread_bundle.h" | 
| 24 #include "content/test/test_content_browser_client.h" | 26 #include "content/test/test_content_browser_client.h" | 
| 25 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" | 
| 26 | 28 | 
| 27 namespace content { | 29 namespace content { | 
| 28 | 30 | 
| 29 namespace { | 31 namespace { | 
| 30 | 32 | 
| 31 static void SaveStatusCallback(bool* called, | 33 static void SaveStatusCallback(bool* called, | 
| 32 ServiceWorkerStatusCode* out, | 34 ServiceWorkerStatusCode* out, | 
| 33 ServiceWorkerStatusCode status) { | 35 ServiceWorkerStatusCode status) { | 
| 34 *called = true; | 36 *called = true; | 
| 35 *out = status; | 37 *out = status; | 
| 36 } | 38 } | 
| 37 | 39 | 
| 40 void SetUpDummyMessagePort(std::vector<TransferredMessagePort>* ports) { | |
| 41 int port_id = -1; | |
| 42 MessagePortService::GetInstance()->Create(MSG_ROUTING_NONE, nullptr, | |
| 43 &port_id); | |
| 44 TransferredMessagePort dummy_port; | |
| 45 dummy_port.id = port_id; | |
| 46 ports->push_back(dummy_port); | |
| 38 } | 47 } | 
| 39 | 48 | 
| 49 } // namespace | |
| 50 | |
| 40 static const int kRenderFrameId = 1; | 51 static const int kRenderFrameId = 1; | 
| 41 | 52 | 
| 42 class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { | 53 class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { | 
| 43 public: | 54 public: | 
| 44 TestingServiceWorkerDispatcherHost( | 55 TestingServiceWorkerDispatcherHost( | 
| 45 int process_id, | 56 int process_id, | 
| 46 ServiceWorkerContextWrapper* context_wrapper, | 57 ServiceWorkerContextWrapper* context_wrapper, | 
| 47 ResourceContext* resource_context, | 58 ResourceContext* resource_context, | 
| 48 EmbeddedWorkerTestHelper* helper) | 59 EmbeddedWorkerTestHelper* helper) | 
| 49 : ServiceWorkerDispatcherHost(process_id, NULL, resource_context), | 60 : ServiceWorkerDispatcherHost(process_id, NULL, resource_context), | 
| 50 bad_messages_received_count_(0), | 61 bad_messages_received_count_(0), | 
| 51 helper_(helper) { | 62 helper_(helper) { | 
| 52 Init(context_wrapper); | 63 Init(context_wrapper); | 
| 53 } | 64 } | 
| 54 | 65 | 
| 55 bool Send(IPC::Message* message) override { return helper_->Send(message); } | 66 bool Send(IPC::Message* message) override { return helper_->Send(message); } | 
| 56 | 67 | 
| 57 IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); } | 68 IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); } | 
| 58 | 69 | 
| 59 void ShutdownForBadMessage() override { ++bad_messages_received_count_; } | 70 void ShutdownForBadMessage() override { ++bad_messages_received_count_; } | 
| 60 | 71 | 
| 61 int bad_messages_received_count_; | 72 int bad_messages_received_count_; | 
| 62 | 73 | 
| 63 protected: | 74 protected: | 
| 64 EmbeddedWorkerTestHelper* helper_; | 75 EmbeddedWorkerTestHelper* helper_; | 
| 65 ~TestingServiceWorkerDispatcherHost() override {} | 76 ~TestingServiceWorkerDispatcherHost() override {} | 
| 66 }; | 77 }; | 
| 67 | 78 | 
| 79 class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper { | |
| 80 public: | |
| 81 FailToStartWorkerTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {} | |
| 82 | |
| 83 void OnStartWorker(int embedded_worker_id, | |
| 84 int64_t service_worker_version_id, | |
| 85 const GURL& scope, | |
| 86 const GURL& script_url, | |
| 87 bool pause_after_download) override { | |
| 88 EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); | |
| 89 registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id); | |
| 90 } | |
| 91 }; | |
| 92 | |
| 68 class ServiceWorkerDispatcherHostTest : public testing::Test { | 93 class ServiceWorkerDispatcherHostTest : public testing::Test { | 
| 69 protected: | 94 protected: | 
| 70 ServiceWorkerDispatcherHostTest() | 95 ServiceWorkerDispatcherHostTest() | 
| 71 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} | 96 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} | 
| 72 | 97 | 
| 73 void SetUp() override { | 98 void SetUp() override { | 
| 74 helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath())); | 99 Initialize(make_scoped_ptr(new EmbeddedWorkerTestHelper(base::FilePath()))); | 
| 75 dispatcher_host_ = new TestingServiceWorkerDispatcherHost( | |
| 76 helper_->mock_render_process_id(), context_wrapper(), | |
| 77 &resource_context_, helper_.get()); | |
| 78 } | 100 } | 
| 79 | 101 | 
| 80 void TearDown() override { helper_.reset(); } | 102 void TearDown() override { helper_.reset(); } | 
| 81 | 103 | 
| 82 ServiceWorkerContextCore* context() { return helper_->context(); } | 104 ServiceWorkerContextCore* context() { return helper_->context(); } | 
| 83 ServiceWorkerContextWrapper* context_wrapper() { | 105 ServiceWorkerContextWrapper* context_wrapper() { | 
| 84 return helper_->context_wrapper(); | 106 return helper_->context_wrapper(); | 
| 85 } | 107 } | 
| 86 | 108 | 
| 109 void Initialize(scoped_ptr<EmbeddedWorkerTestHelper> helper) { | |
| 110 helper_.reset(helper.release()); | |
| 111 dispatcher_host_ = new TestingServiceWorkerDispatcherHost( | |
| 112 helper_->mock_render_process_id(), context_wrapper(), | |
| 113 &resource_context_, helper_.get()); | |
| 114 } | |
| 115 | |
| 87 void SendRegister(int64_t provider_id, GURL pattern, GURL worker_url) { | 116 void SendRegister(int64_t provider_id, GURL pattern, GURL worker_url) { | 
| 88 dispatcher_host_->OnMessageReceived( | 117 dispatcher_host_->OnMessageReceived( | 
| 89 ServiceWorkerHostMsg_RegisterServiceWorker( | 118 ServiceWorkerHostMsg_RegisterServiceWorker( | 
| 90 -1, -1, provider_id, pattern, worker_url)); | 119 -1, -1, provider_id, pattern, worker_url)); | 
| 91 base::RunLoop().RunUntilIdle(); | 120 base::RunLoop().RunUntilIdle(); | 
| 92 } | 121 } | 
| 93 | 122 | 
| 94 void Register(int64_t provider_id, | 123 void Register(int64_t provider_id, | 
| 95 GURL pattern, | 124 GURL pattern, | 
| 96 GURL worker_url, | 125 GURL worker_url, | 
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 base::RunLoop().RunUntilIdle(); | 168 base::RunLoop().RunUntilIdle(); | 
| 140 } | 169 } | 
| 141 | 170 | 
| 142 void GetRegistrations(int64_t provider_id, uint32_t expected_message) { | 171 void GetRegistrations(int64_t provider_id, uint32_t expected_message) { | 
| 143 SendGetRegistrations(provider_id); | 172 SendGetRegistrations(provider_id); | 
| 144 EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching( | 173 EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching( | 
| 145 expected_message)); | 174 expected_message)); | 
| 146 dispatcher_host_->ipc_sink()->ClearMessages(); | 175 dispatcher_host_->ipc_sink()->ClearMessages(); | 
| 147 } | 176 } | 
| 148 | 177 | 
| 178 void DispatchExtendableMessageEvent( | |
| 179 scoped_refptr<ServiceWorkerVersion> worker, | |
| 180 const base::string16& message, | |
| 181 const url::Origin& source_origin, | |
| 182 const std::vector<TransferredMessagePort>& sent_message_ports, | |
| 183 ServiceWorkerProviderHost* sender_provider_host, | |
| 184 const ServiceWorkerDispatcherHost::StatusCallback& callback) { | |
| 185 dispatcher_host_->DispatchExtendableMessageEvent( | |
| 186 std::move(worker), message, source_origin, sent_message_ports, | |
| 187 sender_provider_host, callback); | |
| 188 } | |
| 189 | |
| 149 ServiceWorkerProviderHost* CreateServiceWorkerProviderHost(int provider_id) { | 190 ServiceWorkerProviderHost* CreateServiceWorkerProviderHost(int provider_id) { | 
| 150 return new ServiceWorkerProviderHost( | 191 return new ServiceWorkerProviderHost( | 
| 151 helper_->mock_render_process_id(), kRenderFrameId, provider_id, | 192 helper_->mock_render_process_id(), kRenderFrameId, provider_id, | 
| 152 SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), | 193 SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), | 
| 153 dispatcher_host_.get()); | 194 dispatcher_host_.get()); | 
| 154 } | 195 } | 
| 155 | 196 | 
| 156 | |
| 157 TestBrowserThreadBundle browser_thread_bundle_; | 197 TestBrowserThreadBundle browser_thread_bundle_; | 
| 158 content::MockResourceContext resource_context_; | 198 content::MockResourceContext resource_context_; | 
| 159 scoped_ptr<EmbeddedWorkerTestHelper> helper_; | 199 scoped_ptr<EmbeddedWorkerTestHelper> helper_; | 
| 160 scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_; | 200 scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_; | 
| 161 }; | 201 }; | 
| 162 | 202 | 
| 163 class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient { | 203 class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient { | 
| 164 public: | 204 public: | 
| 165 ServiceWorkerTestContentBrowserClient() {} | 205 ServiceWorkerTestContentBrowserClient() {} | 
| 166 bool AllowServiceWorker(const GURL& scope, | 206 bool AllowServiceWorker(const GURL& scope, | 
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 589 process_id, context_wrapper(), &resource_context_, helper_.get())); | 629 process_id, context_wrapper(), &resource_context_, helper_.get())); | 
| 590 | 630 | 
| 591 // To show the new dispatcher can operate, simulate provider creation. Since | 631 // To show the new dispatcher can operate, simulate provider creation. Since | 
| 592 // the old dispatcher cleaned up the old provider host, the new one won't | 632 // the old dispatcher cleaned up the old provider host, the new one won't | 
| 593 // complain. | 633 // complain. | 
| 594 new_dispatcher_host->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( | 634 new_dispatcher_host->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( | 
| 595 kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); | 635 kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); | 
| 596 EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_); | 636 EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_); | 
| 597 } | 637 } | 
| 598 | 638 | 
| 639 TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent) { | |
| 640 GURL pattern = GURL("http://www.example.com/"); | |
| 641 GURL scope = GURL("http://www.example.com/service_worker.js"); | |
| 
 
falken
2016/03/17 06:44:36
script_url
 
nhiroki
2016/03/17 07:58:17
Good eye. I wrote this line while I was thinking a
 
 | |
| 642 int process_id = helper_->mock_render_process_id(); | |
| 643 | |
| 644 // Add a provider for a service worker to send a message. | |
| 645 const int64_t kProviderId = 99; | |
| 646 dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( | |
| 647 kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER)); | |
| 648 helper_->SimulateAddProcessToPattern(pattern, process_id); | |
| 649 ServiceWorkerProviderHost* sender_provider_host = | |
| 650 context()->GetProviderHost(process_id, kProviderId); | |
| 651 | |
| 652 // Set up a registration and service worker to receive a message. | |
| 653 scoped_refptr<ServiceWorkerRegistration> registration( | |
| 654 new ServiceWorkerRegistration(pattern, 1L, | |
| 655 helper_->context()->AsWeakPtr())); | |
| 656 scoped_refptr<ServiceWorkerVersion> version(new ServiceWorkerVersion( | |
| 657 registration.get(), scope, 1L, helper_->context()->AsWeakPtr())); | |
| 658 std::vector<ServiceWorkerDatabase::ResourceRecord> records; | |
| 659 records.push_back( | |
| 660 ServiceWorkerDatabase::ResourceRecord(10, version->script_url(), 100)); | |
| 661 version->script_cache_map()->SetResources(records); | |
| 662 | |
| 663 // Make the registration findable via storage functions. | |
| 664 helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); | |
| 665 base::RunLoop().RunUntilIdle(); | |
| 666 bool called = false; | |
| 667 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; | |
| 668 helper_->context()->storage()->StoreRegistration( | |
| 669 registration.get(), version.get(), | |
| 670 base::Bind(&SaveStatusCallback, &called, &status)); | |
| 671 base::RunLoop().RunUntilIdle(); | |
| 672 EXPECT_TRUE(called); | |
| 673 ASSERT_EQ(SERVICE_WORKER_OK, status); | |
| 
 
falken
2016/03/17 06:44:36
Maybe it's time to refactor lines 640-673 and the
 
nhiroki
2016/03/17 07:58:17
Done.
 
 | |
| 674 | |
| 675 // Set the running hosted version so that we can retrieve a valid service | |
| 676 // worker object information for the source attribute of the message event. | |
| 677 sender_provider_host->running_hosted_version_ = version; | |
| 678 | |
| 679 // Set aside the initial refcount of the worker handle. | |
| 680 sender_provider_host->GetOrCreateServiceWorkerHandle(version.get()); | |
| 681 ServiceWorkerHandle* sender_worker_handle = | |
| 682 dispatcher_host_->FindServiceWorkerHandle( | |
| 683 sender_provider_host->provider_id(), version->version_id()); | |
| 684 const int ref_count = sender_worker_handle->ref_count(); | |
| 685 | |
| 686 // Dispatch ExtendableMessageEvent. | |
| 687 std::vector<TransferredMessagePort> ports; | |
| 688 SetUpDummyMessagePort(&ports); | |
| 689 called = false; | |
| 690 status = SERVICE_WORKER_ERROR_MAX_VALUE; | |
| 691 DispatchExtendableMessageEvent( | |
| 692 version, base::string16(), url::Origin(version->scope().GetOrigin()), | |
| 693 ports, sender_provider_host, | |
| 694 base::Bind(&SaveStatusCallback, &called, &status)); | |
| 695 for (TransferredMessagePort port : ports) | |
| 696 EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); | |
| 697 EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); | |
| 698 base::RunLoop().RunUntilIdle(); | |
| 699 EXPECT_TRUE(called); | |
| 700 EXPECT_EQ(SERVICE_WORKER_OK, status); | |
| 701 | |
| 702 // Messages should be held until ports are created at the destination. | |
| 703 for (TransferredMessagePort port : ports) | |
| 704 EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); | |
| 705 | |
| 706 EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); | |
| 707 } | |
| 708 | |
| 709 TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent_Fail) { | |
| 710 Initialize(make_scoped_ptr(new FailToStartWorkerTestHelper)); | |
| 711 | |
| 712 GURL pattern = GURL("http://www.example.com/"); | |
| 713 GURL scope = GURL("http://www.example.com/service_worker.js"); | |
| 
 
falken
2016/03/17 06:44:36
script_url
 
nhiroki
2016/03/17 07:58:17
Done.
 
 | |
| 714 int process_id = helper_->mock_render_process_id(); | |
| 715 | |
| 716 // Add a provider for a service worker to send a message. | |
| 717 const int64_t kProviderId = 99; | |
| 718 dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( | |
| 719 kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER)); | |
| 720 helper_->SimulateAddProcessToPattern(pattern, process_id); | |
| 721 ServiceWorkerProviderHost* sender_provider_host = | |
| 722 context()->GetProviderHost(process_id, kProviderId); | |
| 723 | |
| 724 // Set up a registration and service worker to receive a message. | |
| 725 scoped_refptr<ServiceWorkerRegistration> registration( | |
| 726 new ServiceWorkerRegistration(pattern, 1L, | |
| 727 helper_->context()->AsWeakPtr())); | |
| 728 scoped_refptr<ServiceWorkerVersion> version(new ServiceWorkerVersion( | |
| 729 registration.get(), scope, 1L, helper_->context()->AsWeakPtr())); | |
| 730 std::vector<ServiceWorkerDatabase::ResourceRecord> records; | |
| 731 records.push_back( | |
| 732 ServiceWorkerDatabase::ResourceRecord(10, version->script_url(), 100)); | |
| 733 version->script_cache_map()->SetResources(records); | |
| 734 | |
| 735 // Make the registration findable via storage functions. | |
| 736 helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); | |
| 737 base::RunLoop().RunUntilIdle(); | |
| 738 bool called = false; | |
| 739 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; | |
| 740 helper_->context()->storage()->StoreRegistration( | |
| 741 registration.get(), version.get(), | |
| 742 base::Bind(&SaveStatusCallback, &called, &status)); | |
| 743 base::RunLoop().RunUntilIdle(); | |
| 744 EXPECT_TRUE(called); | |
| 745 ASSERT_EQ(SERVICE_WORKER_OK, status); | |
| 746 | |
| 747 // Set the running hosted version so that we can retrieve a valid service | |
| 748 // worker object information for the source attribute of the message event. | |
| 749 sender_provider_host->running_hosted_version_ = version; | |
| 750 | |
| 751 // Set aside the initial refcount of the worker handle. | |
| 752 sender_provider_host->GetOrCreateServiceWorkerHandle(version.get()); | |
| 753 ServiceWorkerHandle* sender_worker_handle = | |
| 754 dispatcher_host_->FindServiceWorkerHandle( | |
| 755 sender_provider_host->provider_id(), version->version_id()); | |
| 756 const int ref_count = sender_worker_handle->ref_count(); | |
| 757 | |
| 758 // Try to dispatch ExtendableMessageEvent. This should fail to start the | |
| 759 // worker and to dispatch the event. | |
| 760 std::vector<TransferredMessagePort> ports; | |
| 761 SetUpDummyMessagePort(&ports); | |
| 762 called = false; | |
| 763 status = SERVICE_WORKER_ERROR_MAX_VALUE; | |
| 764 DispatchExtendableMessageEvent( | |
| 765 version, base::string16(), url::Origin(version->scope().GetOrigin()), | |
| 766 ports, sender_provider_host, | |
| 767 base::Bind(&SaveStatusCallback, &called, &status)); | |
| 768 for (TransferredMessagePort port : ports) | |
| 769 EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); | |
| 770 EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); | |
| 771 base::RunLoop().RunUntilIdle(); | |
| 772 EXPECT_TRUE(called); | |
| 773 EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status); | |
| 774 | |
| 775 // The error callback should clean up the ports and handle. | |
| 776 for (TransferredMessagePort port : ports) | |
| 777 EXPECT_FALSE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); | |
| 778 EXPECT_EQ(ref_count, sender_worker_handle->ref_count()); | |
| 779 } | |
| 780 | |
| 599 } // namespace content | 781 } // namespace content | 
| OLD | NEW |