profile_destroyer.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/profiles/profile_destroyer.h" 6 7#include "base/bind.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/message_loop.h" 10#include "chrome/browser/profiles/profile.h" 11#include "content/public/browser/notification_source.h" 12#include "content/public/browser/notification_types.h" 13#include "content/public/browser/render_process_host.h" 14 15 16namespace { 17 18const int64 kTimerDelaySeconds = 1; 19 20} // namespace 21 22std::vector<ProfileDestroyer*>* ProfileDestroyer::pending_destroyers_ = NULL; 23 24// static 25void ProfileDestroyer::DestroyProfileWhenAppropriate(Profile* const profile) { 26 DCHECK(profile); 27 profile->MaybeSendDestroyedNotification(); 28 29 std::vector<content::RenderProcessHost*> hosts; 30 // Testing profiles can simply be deleted directly. Some tests don't setup 31 // RenderProcessHost correctly and don't necessary run on the UI thread 32 // anyway, so we can't use the AllHostIterator. 33 if (profile->AsTestingProfile() == NULL) { 34 GetHostsForProfile(profile, &hosts); 35 if (!profile->IsOffTheRecord() && profile->HasOffTheRecordProfile()) 36 GetHostsForProfile(profile->GetOffTheRecordProfile(), &hosts); 37 } 38 // This should never happen for non Off the record profile, this means that 39 // there is a leak in a render process host that MUST BE FIXED!!! 40 DCHECK(hosts.empty() || profile->IsOffTheRecord()); 41 // Note that we still test for !profile->IsOffTheRecord here even though we 42 // DCHECK'd above because we want to protect Release builds against this even 43 // we need to identify if there are leaks when we run Debug builds. 44 if (hosts.empty() || !profile->IsOffTheRecord()) { 45 if (profile->IsOffTheRecord()) 46 profile->GetOriginalProfile()->DestroyOffTheRecordProfile(); 47 else 48 delete profile; 49 } else { 50 // The instance will destroy itself once all render process hosts referring 51 // to it are properly terminated. 52 scoped_refptr<ProfileDestroyer> profile_destroyer( 53 new ProfileDestroyer(profile, hosts)); 54 } 55} 56 57// This can be called to cancel any pending destruction and destroy the profile 58// now, e.g., if the parent profile is being destroyed while the incognito one 59// still pending... 60void ProfileDestroyer::DestroyOffTheRecordProfileNow(Profile* const profile) { 61 DCHECK(profile); 62 DCHECK(profile->IsOffTheRecord()); 63 if (pending_destroyers_) { 64 for (size_t i = 0; i < pending_destroyers_->size(); ++i) { 65 if ((*pending_destroyers_)[i]->profile_ == profile) { 66 // We want to signal this in debug builds so that we don't lose sight of 67 // these potential leaks, but we handle it in release so that we don't 68 // crash or corrupt profile data on disk. 69 NOTREACHED() << "A render process host wasn't destroyed early enough."; 70 (*pending_destroyers_)[i]->profile_ = NULL; 71 break; 72 } 73 } 74 } 75 DCHECK(profile->GetOriginalProfile()); 76 profile->GetOriginalProfile()->DestroyOffTheRecordProfile(); 77} 78 79ProfileDestroyer::ProfileDestroyer( 80 Profile* const profile, 81 const std::vector<content::RenderProcessHost*>& hosts) 82 : timer_(false, false), 83 num_hosts_(0), 84 profile_(profile) { 85 if (pending_destroyers_ == NULL) 86 pending_destroyers_ = new std::vector<ProfileDestroyer*>; 87 pending_destroyers_->push_back(this); 88 for (size_t i = 0; i < hosts.size(); ++i) { 89 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 90 content::Source<content::RenderProcessHost>(hosts[i])); 91 // For each of the notifications, we bump up our reference count. 92 // It will go back to 0 and free us when all hosts are terminated. 93 ++num_hosts_; 94 } 95 // If we are going to wait for render process hosts, we don't want to do it 96 // for longer than kTimerDelaySeconds. 97 if (num_hosts_) { 98 timer_.Start(FROM_HERE, 99 base::TimeDelta::FromSeconds(kTimerDelaySeconds), 100 base::Bind(&ProfileDestroyer::DestroyProfile, this)); 101 } 102} 103 104ProfileDestroyer::~ProfileDestroyer() { 105 // Check again, in case other render hosts were added while we were 106 // waiting for the previous ones to go away... 107 if (profile_) 108 DestroyProfileWhenAppropriate(profile_); 109 110 // We shouldn't be deleted with pending notifications. 111 DCHECK(registrar_.IsEmpty()); 112 113 DCHECK(pending_destroyers_ != NULL); 114 std::vector<ProfileDestroyer*>::iterator iter = std::find( 115 pending_destroyers_->begin(), pending_destroyers_->end(), this); 116 DCHECK(iter != pending_destroyers_->end()); 117 pending_destroyers_->erase(iter); 118 DCHECK(pending_destroyers_->end() == std::find(pending_destroyers_->begin(), 119 pending_destroyers_->end(), 120 this)); 121 if (pending_destroyers_->empty()) { 122 delete pending_destroyers_; 123 pending_destroyers_ = NULL; 124 } 125} 126 127void ProfileDestroyer::Observe(int type, 128 const content::NotificationSource& source, 129 const content::NotificationDetails& details) { 130 DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_TERMINATED); 131 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 132 source); 133 DCHECK(num_hosts_ > 0); 134 --num_hosts_; 135 if (num_hosts_ == 0) { 136 // Delay the destruction one step further in case other observers of this 137 // notification need to look at the profile attached to the host. 138 MessageLoop::current()->PostTask( 139 FROM_HERE, base::Bind(&ProfileDestroyer::DestroyProfile, this)); 140 } 141} 142 143void ProfileDestroyer::DestroyProfile() { 144 // We might have been cancelled externally before the timer expired. 145 if (profile_ == NULL) 146 return; 147 DCHECK(profile_->IsOffTheRecord()); 148 DCHECK(profile_->GetOriginalProfile()); 149 profile_->GetOriginalProfile()->DestroyOffTheRecordProfile(); 150 profile_ = NULL; 151 152 // Don't wait for pending registrations, if any, these hosts are buggy. 153 DCHECK(registrar_.IsEmpty()) << "Some render process hosts where not " 154 << "destroyed early enough!"; 155 registrar_.RemoveAll(); 156 157 // And stop the timer so we can be released early too. 158 timer_.Stop(); 159} 160 161// static 162bool ProfileDestroyer::GetHostsForProfile( 163 Profile* const profile, std::vector<content::RenderProcessHost*>* hosts) { 164 for (content::RenderProcessHost::iterator iter( 165 content::RenderProcessHost::AllHostsIterator()); 166 !iter.IsAtEnd(); iter.Advance()) { 167 content::RenderProcessHost* render_process_host = iter.GetCurrentValue(); 168 if (render_process_host && Profile::FromBrowserContext( 169 render_process_host->GetBrowserContext()) == profile) { 170 hosts->push_back(render_process_host); 171 } 172 } 173 return !hosts->empty(); 174} 175