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