diff --git a/cobalt/browser/browser_module.cc b/cobalt/browser/browser_module.cc index ca7144a6c9676..187021197adb5 100644 --- a/cobalt/browser/browser_module.cc +++ b/cobalt/browser/browser_module.cc @@ -1712,7 +1712,10 @@ void BrowserModule::InstantiateRendererModule() { void BrowserModule::DestroyRendererModule() { DCHECK(task_runner_->RunsTasksInCurrentSequence()); DCHECK(renderer_module_); - + base::task_runner_util::PostBlockingTask( + web_module_->task_runner(), FROM_HERE, + base::Bind(&WebModule::WaitForItall, + base::Unretained(web_module_.get()))); screen_shot_writer_.reset(); renderer_module_.reset(); } diff --git a/cobalt/browser/web_module.cc b/cobalt/browser/web_module.cc index 8dab0833f7c64..09b65e0f372c4 100644 --- a/cobalt/browser/web_module.cc +++ b/cobalt/browser/web_module.cc @@ -295,7 +295,8 @@ class WebModule::Impl { class DocumentLoadedObserver; // Purge all resource caches owned by the WebModule. - void PurgeResourceCaches(bool should_retain_remote_typeface_cache); + void PurgeResourceCaches(bool should_retain_remote_typeface_cache, + bool on_conceal = false); // Disable callbacks in all resource caches owned by the WebModule. void DisableCallbacksInResourceCaches(); @@ -1130,6 +1131,7 @@ void WebModule::Impl::Conceal(render_tree::ResourceProvider* resource_provider, // Purge the cached resources prior to the freeze. That may cancel pending // loads, allowing the freeze to occur faster and preventing unnecessary // callbacks. + loader_factory_->Conceal(); window_->document()->PurgeCachedResources(); // Clear out any currently tracked animating images. @@ -1137,7 +1139,7 @@ void WebModule::Impl::Conceal(render_tree::ResourceProvider* resource_provider, // Purge the resource caches before running any freeze logic. This will force // any pending callbacks that the caches are batching to run. - PurgeResourceCaches(should_retain_remote_typeface_cache_on_freeze_); + PurgeResourceCaches(should_retain_remote_typeface_cache_on_freeze_, true); #if defined(ENABLE_DEBUGGER) // The debug overlay may be holding onto a render tree, clear that out. @@ -1184,6 +1186,7 @@ void WebModule::Impl::Reveal(render_tree::ResourceProvider* resource_provider, DCHECK(resource_provider); SetResourceProvider(resource_provider); + image_cache_->OnReveal(); window_->document()->PurgeCachedResources(); PurgeResourceCaches(should_retain_remote_typeface_cache_on_freeze_); @@ -1244,8 +1247,8 @@ void WebModule::Impl::InjectWindowOnOfflineEvent() { } void WebModule::Impl::PurgeResourceCaches( - bool should_retain_remote_typeface_cache) { - image_cache_->Purge(); + bool should_retain_remote_typeface_cache, bool on_conceal) { + image_cache_->Purge(on_conceal); if (should_retain_remote_typeface_cache) { remote_typeface_cache_->ProcessPendingCallbacks(); } else { diff --git a/cobalt/browser/web_module.h b/cobalt/browser/web_module.h index c42f71edf7f73..cf8f90d673df9 100644 --- a/cobalt/browser/web_module.h +++ b/cobalt/browser/web_module.h @@ -90,6 +90,12 @@ namespace browser { class WebModule : public base::CurrentThread::DestructionObserver, public LifecycleObserver { public: + // The task runner this object is running on. + base::SequencedTaskRunner* task_runner() const { + DCHECK(web_agent_); + return web_agent_ ? web_agent_->task_runner() : nullptr; + } + void WaitForItall() {} struct Options { typedef base::Callback( WebModule*, web::EnvironmentSettings*)> @@ -482,12 +488,6 @@ class WebModule : public base::CurrentThread::DestructionObserver, void GetIsReadyToFreeze(volatile bool* is_ready_to_freeze); - // The task runner this object is running on. - base::SequencedTaskRunner* task_runner() const { - DCHECK(web_agent_); - return web_agent_ ? web_agent_->task_runner() : nullptr; - } - // Private implementation object. std::unique_ptr impl_; diff --git a/cobalt/loader/decoder.h b/cobalt/loader/decoder.h index e7d7a7cf6e06a..426ee354fc4aa 100644 --- a/cobalt/loader/decoder.h +++ b/cobalt/loader/decoder.h @@ -67,6 +67,8 @@ class Decoder { // aborted. virtual bool Suspend() = 0; + virtual void Conceal() {} + // Resumes the decode of this resource, starting over from the zero state. virtual void Resume(render_tree::ResourceProvider* resource_provider) = 0; diff --git a/cobalt/loader/image/threaded_image_decoder_proxy.cc b/cobalt/loader/image/threaded_image_decoder_proxy.cc index 8f51e86479b8a..232c78c80fc69 100644 --- a/cobalt/loader/image/threaded_image_decoder_proxy.cc +++ b/cobalt/loader/image/threaded_image_decoder_proxy.cc @@ -115,6 +115,8 @@ void ThreadedImageDecoderProxy::DecodeChunkPassed( } void ThreadedImageDecoderProxy::Finish() { + base::AutoLock auto_lock(conceal_lock_); + if (is_concealed_) return; load_task_runner_->PostTask( FROM_HERE, base::Bind(&ImageDecoder::Finish, base::Unretained(image_decoder_.get()))); @@ -135,6 +137,11 @@ void ThreadedImageDecoderProxy::Resume( resource_provider)); } +void ThreadedImageDecoderProxy::Conceal() { + base::AutoLock auto_lock(conceal_lock_); + is_concealed_ = true; +} + } // namespace image } // namespace loader } // namespace cobalt diff --git a/cobalt/loader/image/threaded_image_decoder_proxy.h b/cobalt/loader/image/threaded_image_decoder_proxy.h index 7ba7080422f3d..2f9302f9d7111 100644 --- a/cobalt/loader/image/threaded_image_decoder_proxy.h +++ b/cobalt/loader/image/threaded_image_decoder_proxy.h @@ -27,6 +27,7 @@ #include "cobalt/loader/image/image_data_decoder.h" #include "cobalt/loader/image/image_decoder.h" #include "cobalt/render_tree/resource_provider.h" +#include "starboard/common/mutex.h" namespace cobalt { namespace loader { @@ -64,6 +65,7 @@ class ThreadedImageDecoderProxy : public Decoder { void Finish() override; bool Suspend() override; void Resume(render_tree::ResourceProvider* resource_provider) override; + void Conceal() override; private: ThreadedImageDecoderProxy( @@ -84,6 +86,9 @@ class ThreadedImageDecoderProxy : public Decoder { // The actual image decoder. std::unique_ptr image_decoder_; + + mutable base::Lock conceal_lock_; + bool is_concealed_ = false; }; } // namespace image diff --git a/cobalt/loader/loader.cc b/cobalt/loader/loader.cc index 6fb39c513c754..ec77e123ec20c 100644 --- a/cobalt/loader/loader.cc +++ b/cobalt/loader/loader.cc @@ -143,6 +143,11 @@ void Loader::Resume(render_tree::ResourceProvider* resource_provider) { if (!is_load_complete_) Start(); } +void Loader::Conceal() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + decoder_->Conceal(); +} + bool Loader::DidFailFromTransientError() const { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); return fetcher_ && fetcher_->did_fail_from_transient_error(); diff --git a/cobalt/loader/loader.h b/cobalt/loader/loader.h index 1a999613c6634..90f6fa0b79c8e 100644 --- a/cobalt/loader/loader.h +++ b/cobalt/loader/loader.h @@ -62,6 +62,8 @@ class Loader { // called. void Resume(render_tree::ResourceProvider* resource_provider); + void Conceal(); + bool DidFailFromTransientError() const; void LoadComplete(const base::Optional& status); diff --git a/cobalt/loader/loader_factory.cc b/cobalt/loader/loader_factory.cc index b3382bd3bdc05..b11a9a0de1dea 100644 --- a/cobalt/loader/loader_factory.cc +++ b/cobalt/loader/loader_factory.cc @@ -178,6 +178,11 @@ void LoaderFactory::Resume(render_tree::ResourceProvider* resource_provider) { ResumeActiveLoaders(resource_provider); } +void LoaderFactory::Conceal() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + ConcealActiveLoaders(); +} + void LoaderFactory::UpdateResourceProvider( render_tree::ResourceProvider* resource_provider) { DCHECK(resource_provider); @@ -208,5 +213,15 @@ void LoaderFactory::ResumeActiveLoaders( base::task_runner_util::WaitForFence(load_thread_.task_runner(), FROM_HERE); } +void LoaderFactory::ConcealActiveLoaders() { + for (LoaderSet::const_iterator iter = active_loaders_.begin(); + iter != active_loaders_.end(); ++iter) { + (*iter)->Conceal(); + } + + // Wait for all loader thread messages to be flushed before returning. + base::task_runner_util::WaitForFence(load_thread_.task_runner(), FROM_HERE); +} + } // namespace loader } // namespace cobalt diff --git a/cobalt/loader/loader_factory.h b/cobalt/loader/loader_factory.h index 9865adc5857d0..a2c74b1664b66 100644 --- a/cobalt/loader/loader_factory.h +++ b/cobalt/loader/loader_factory.h @@ -93,6 +93,7 @@ class LoaderFactory : public ScriptLoaderFactory { // previous resource provider must have been cleared before this method is // called. void Resume(render_tree::ResourceProvider* resource_provider); + void Conceal(); // Resets a new resource provider for this loader factory to use. The // previous resource provider must have been cleared before this method is @@ -106,6 +107,7 @@ class LoaderFactory : public ScriptLoaderFactory { private: void SuspendActiveLoaders(); void ResumeActiveLoaders(render_tree::ResourceProvider* resource_provider); + void ConcealActiveLoaders(); // Used to cache the fetched raw data. Note that currently the cache is only // used to cache Image data. We may introduce more caches once we want to diff --git a/cobalt/loader/resource_cache.cc b/cobalt/loader/resource_cache.cc index d5f1d6b0b273b..c4cd84d7fd52a 100644 --- a/cobalt/loader/resource_cache.cc +++ b/cobalt/loader/resource_cache.cc @@ -189,10 +189,10 @@ void ResourceCacheBase::SetCapacity(uint32 capacity) { ReclaimMemoryAndMaybeProcessPendingCallbacks(cache_capacity_); } -void ResourceCacheBase::Purge() { +void ResourceCacheBase::Purge(bool on_conceal) { DCHECK_CALLED_ON_VALID_THREAD(resource_cache_thread_checker_); ProcessPendingCallbacks(); - reclaim_memory_func_.Run(0, true); + reclaim_memory_func_.Run(0, true, on_conceal); } void ResourceCacheBase::ProcessPendingCallbacks() { @@ -289,8 +289,9 @@ void ResourceCacheBase::NotifyResourceLoadingRetryScheduled( void ResourceCacheBase::ReclaimMemoryAndMaybeProcessPendingCallbacks( uint32 bytes_to_reclaim_down_to) { + bool on_conceal = false; reclaim_memory_func_.Run(bytes_to_reclaim_down_to, - false /*log_warning_if_over*/); + false /*log_warning_if_over*/, on_conceal); // If the current size of the cache is still greater than // |bytes_to_reclaim_down_to| after reclaiming memory, then process any // pending callbacks and try again. References to the cached resources are @@ -299,7 +300,7 @@ void ResourceCacheBase::ReclaimMemoryAndMaybeProcessPendingCallbacks( if (memory_size_in_bytes_ > bytes_to_reclaim_down_to) { ProcessPendingCallbacks(); reclaim_memory_func_.Run(bytes_to_reclaim_down_to, - true /*log_warning_if_over*/); + true /*log_warning_if_over*/, on_conceal); } } diff --git a/cobalt/loader/resource_cache.h b/cobalt/loader/resource_cache.h index 5872e09e0025e..0c0af92bbdb0b 100644 --- a/cobalt/loader/resource_cache.h +++ b/cobalt/loader/resource_cache.h @@ -266,6 +266,7 @@ class CachedResource : public CachedResourceBase { // returns |resource_| even if it is NULL to indicate no resource is // available. scoped_refptr TryGetResource(); + void SetIsConcealed(bool val) { is_concealed_ = val; } private: friend class ResourceCache; @@ -286,6 +287,7 @@ class CachedResource : public CachedResourceBase { const base::Callback on_resource_destroyed_; scoped_refptr resource_; + bool is_concealed_ = false; DISALLOW_COPY_AND_ASSIGN(CachedResource); }; @@ -347,6 +349,7 @@ void CachedResource::OnContentProduced( DCHECK_CALLED_ON_VALID_THREAD(cached_resource_thread_checker_); DCHECK(!resource_); + if (is_concealed_) return; resource_ = resource; } @@ -402,7 +405,7 @@ class CachedResourceReferenceWithCallbacks { class ResourceCacheBase { public: typedef base::Callback + bool log_warning_if_over, bool on_conceal)> ReclaimMemoryFunc; // Set a callback that the loader will query to determine if the URL is safe @@ -419,7 +422,7 @@ class ResourceCacheBase { uint32 capacity() const { return cache_capacity_; } void SetCapacity(uint32 capacity); - void Purge(); + void Purge(bool on_conceal = false); // Processes all pending callbacks regardless of the state of // |callback_blocking_loading_resource_set_|. @@ -508,6 +511,7 @@ class ResourceCacheBase { bool is_processing_pending_callbacks_ = false; // Whether or not callbacks are currently disabled. bool are_callbacks_disabled_ = false; + bool is_concealed_ = false; base::CVal memory_size_in_bytes_; base::CVal @@ -570,6 +574,11 @@ class ResourceCache : public ResourceCacheBase { // all unreferenced resources are released. std::unique_ptr CreateWeakCachedResource( const scoped_refptr& cached_resource); + void OnReveal() { + for (auto& it : cached_resource_map_) { + it.second->SetIsConcealed(false); + } + } private: typedef base::hash_map CachedResourceMap; @@ -601,7 +610,8 @@ class ResourceCache : public ResourceCacheBase { // Releases unreferenced cache objects until our total cache memory usage is // less than or equal to |bytes_to_reclaim_down_to|, or until there are no // more unreferenced cache objects to release. - void ReclaimMemory(uint32 bytes_to_reclaim_down_to, bool log_warning_if_over); + void ReclaimMemory(uint32 bytes_to_reclaim_down_to, bool log_warning_if_over, + bool on_conceal = false); const CreateLoaderFunction create_loader_function_; const NotifyResourceRequestedFunction notify_resource_requested_function_; @@ -907,12 +917,19 @@ void ResourceCache::NotifyWeakResourceDestroyed( template void ResourceCache::ReclaimMemory(uint32 bytes_to_reclaim_down_to, - bool log_warning_if_over) { + bool log_warning_if_over, + bool on_conceal) { DCHECK_CALLED_ON_VALID_THREAD(resource_cache_thread_checker_); ResourceMap* resource_maps[] = {&unreferenced_cached_resource_map_, &weak_referenced_cached_resource_map_}; + if (on_conceal) { + for (auto& it : cached_resource_map_) { + it.second->SetIsConcealed(true); + } + } + for (size_t i = 0; i < SB_ARRAY_SIZE(resource_maps); ++i) { while (memory_size_in_bytes_ > bytes_to_reclaim_down_to && !resource_maps[i]->empty()) {