15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/memory_purger.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/allocator/allocator_extension.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_service_factory.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/database_manager.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_service.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/webdata/web_data_service.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/webdata/web_data_service_factory.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/render_messages.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_widget_host.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/resource_context.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_resolver.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_service.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserContext;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::ResourceContext;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PurgeMemoryHelper -----------------------------------------------------------
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is a small helper class used to ensure that the objects we want to use
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on multiple threads are properly refed, so they don't get deleted out from
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// under us.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PurgeMemoryIOHelper
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<PurgeMemoryIOHelper> {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PurgeMemoryIOHelper() {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    safe_browsing_service_ = g_browser_process->safe_browsing_service();
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddRequestContextGetter(
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<net::URLRequestContextGetter> request_context_getter);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void PurgeMemoryOnIOThread();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<PurgeMemoryIOHelper>;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~PurgeMemoryIOHelper() {}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef scoped_refptr<net::URLRequestContextGetter> RequestContextGetter;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<RequestContextGetter> request_context_getters_;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SafeBrowsingService> safe_browsing_service_;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(PurgeMemoryIOHelper);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PurgeMemoryIOHelper::AddRequestContextGetter(
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_context_getters_.push_back(request_context_getter);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PurgeMemoryIOHelper::PurgeMemoryOnIOThread() {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ask ProxyServices to purge any memory they can (generally garbage in the
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // wrapped ProxyResolver's JS engine).
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < request_context_getters_.size(); ++i) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_context_getters_[i]->GetURLRequestContext()->proxy_service()->
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PurgeMemory();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(FULL_SAFE_BROWSING)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  safe_browsing_service_->database_manager()->PurgeMemory();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -----------------------------------------------------------------------------
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryPurger::PurgeAll() {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PurgeBrowser();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PurgeRenderers();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting):
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * Tell the plugin processes to release their free memory?  Other stuff?
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * Enumerate what other processes exist and what to do for them.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryPurger::PurgeBrowser() {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Dump the backing stores.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::RenderWidgetHost::RemoveAllBackingStores();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Per-profile cleanup.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<PurgeMemoryIOHelper> purge_memory_io_helper(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new PurgeMemoryIOHelper());
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileManager* profile_manager = g_browser_process->profile_manager();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < profiles.size(); ++i) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    purge_memory_io_helper->AddRequestContextGetter(
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        make_scoped_refptr(profiles[i]->GetRequestContext()));
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE: Some objects below may be duplicates across profiles.  We could
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // conceivably put all these in sets and then iterate over the sets.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unload all history backends (freeing memory used to cache sqlite).
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Spinning up the history service is expensive, so we avoid doing it if it
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // hasn't been done already.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryService* history_service =
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        HistoryServiceFactory::GetForProfileWithoutCreating(profiles[i]);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (history_service)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history_service->UnloadBackend();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unload all web databases (freeing memory used to cache sqlite).
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WebDataServiceWrapper* wds_wrapper =
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        WebDataServiceFactory::GetForProfileIfExists(
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            profiles[i], Profile::EXPLICIT_ACCESS);
1237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (wds_wrapper && wds_wrapper->GetWebData().get())
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      wds_wrapper->GetWebData()->UnloadDatabase();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserContext::PurgeMemory(profiles[i]);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO, FROM_HERE,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&PurgeMemoryIOHelper::PurgeMemoryOnIOThread,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 purge_memory_io_helper.get()));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting):
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * Purge AppCache memory.  Not yet implemented sufficiently.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * Browser-side DatabaseTracker.  Not implemented sufficiently.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tell our allocator to release any free pages it's still holding.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): A lot of the above calls kick off actions on other threads.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Maybe we should find a way to avoid calling this until those actions
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // complete?
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::allocator::ReleaseFreeMemory();
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryPurger::PurgeRenderers() {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Direct all renderers to free everything they can.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Concern: Telling a bunch of renderer processes to destroy their data may
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cause them to page everything in to do it, which could take a lot of time/
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cause jank.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (content::RenderProcessHost::iterator i(
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::RenderProcessHost::AllHostsIterator());
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !i.IsAtEnd(); i.Advance())
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PurgeRendererForHost(i.GetCurrentValue());
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryPurger::PurgeRendererForHost(content::RenderProcessHost* host) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Direct the renderer to free everything it can.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  host->Send(new ChromeViewMsg_PurgeMemory());
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
164