- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / prerender / prerender_tracker.cc
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/prerender/prerender_tracker.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/prerender/prerender_manager.h"
11 #include "chrome/browser/prerender/prerender_resource_throttle.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/render_view_host.h"
14 #include "content/public/browser/resource_context.h"
15 #include "net/base/load_flags.h"
16
17 using content::BrowserThread;
18 using content::RenderViewHost;
19
20 namespace prerender {
21
22 namespace {
23
24 void DestroyPrerenderForRenderViewOnUI(
25     const base::WeakPtr<PrerenderManager>& prerender_manager_weak_ptr,
26     int render_process_id,
27     int render_view_id,
28     FinalStatus final_status) {
29   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
30   PrerenderManager* prerender_manager = prerender_manager_weak_ptr.get();
31   if (!prerender_manager)
32     return;
33
34   prerender_manager->DestroyPrerenderForRenderView(
35       render_process_id, render_view_id, final_status);
36 }
37
38 }  // namespace
39
40 struct RenderViewInfo {
41   explicit RenderViewInfo(PrerenderManager* prerender_manager)
42       : final_status(FINAL_STATUS_MAX),
43         prerender_manager(prerender_manager->AsWeakPtr()) {
44   }
45   ~RenderViewInfo() {}
46
47   FinalStatus final_status;
48   base::WeakPtr<PrerenderManager> prerender_manager;
49 };
50
51 PrerenderTracker::PrerenderTracker() {
52   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
53 }
54
55 PrerenderTracker::~PrerenderTracker() {
56   DCHECK(final_status_map_.empty());
57 }
58
59 bool PrerenderTracker::TryUse(int child_id, int route_id) {
60   DCHECK(CalledOnValidThread());
61   return SetFinalStatus(child_id, route_id, FINAL_STATUS_USED, NULL);
62 }
63
64 bool PrerenderTracker::TryCancel(
65     int child_id,
66     int route_id,
67     FinalStatus final_status) {
68   DCHECK_NE(FINAL_STATUS_USED, final_status);
69   DCHECK(final_status >= 0 && final_status < FINAL_STATUS_MAX);
70
71   FinalStatus actual_final_status;
72   SetFinalStatus(child_id, route_id, final_status, &actual_final_status);
73   return actual_final_status != FINAL_STATUS_USED &&
74          actual_final_status != FINAL_STATUS_MAX;
75 }
76
77 bool PrerenderTracker::TryCancelOnIOThread(
78     int child_id,
79     int route_id,
80     FinalStatus final_status) {
81   DCHECK_NE(FINAL_STATUS_USED, final_status);
82   DCHECK_LE(0, final_status);
83   DCHECK_GT(FINAL_STATUS_MAX, final_status);
84
85   if (!IsPrerenderingOnIOThread(child_id, route_id))
86     return false;
87   return TryCancel(child_id, route_id, final_status);
88 }
89
90 bool PrerenderTracker::GetFinalStatus(int child_id, int route_id,
91                                       FinalStatus* final_status) const {
92   ChildRouteIdPair child_route_id_pair(child_id, route_id);
93
94   base::AutoLock lock(final_status_map_lock_);
95   FinalStatusMap::const_iterator final_status_it =
96       final_status_map_.find(child_route_id_pair);
97   if (final_status_it == final_status_map_.end())
98     return false;
99   *final_status = final_status_it->second.final_status;
100   return true;
101 }
102
103 void PrerenderTracker::OnPrerenderStart(
104     PrerenderContents* prerender_contents) {
105   DCHECK(CalledOnValidThread());
106   int child_id, route_id;
107   bool got_child_id = prerender_contents->GetChildId(&child_id);
108   DCHECK(got_child_id);
109   bool got_route_id = prerender_contents->GetRouteId(&route_id);
110   DCHECK(got_route_id);
111
112   ChildRouteIdPair child_route_id_pair(child_id, route_id);
113
114   BrowserThread::PostTask(
115       BrowserThread::IO, FROM_HERE,
116       base::Bind(&AddPrerenderOnIOThreadTask, child_route_id_pair));
117
118   base::AutoLock lock(final_status_map_lock_);
119   // The RenderView should not already be prerendering.
120   DCHECK_EQ(0u, final_status_map_.count(child_route_id_pair));
121
122   final_status_map_.insert(
123       std::make_pair(child_route_id_pair,
124                      RenderViewInfo(prerender_contents->prerender_manager())));
125 }
126
127 void PrerenderTracker::OnPrerenderStop(
128     PrerenderContents* prerender_contents) {
129   DCHECK(CalledOnValidThread());
130   int child_id, route_id;
131   bool got_child_id = prerender_contents->GetChildId(&child_id);
132   DCHECK(got_child_id);
133   bool got_route_id = prerender_contents->GetRouteId(&route_id);
134   DCHECK(got_route_id);
135
136   ChildRouteIdPair child_route_id_pair(child_id, route_id);
137
138   DCHECK_LT(prerender_contents->final_status(), FINAL_STATUS_MAX);
139   BrowserThread::PostTask(
140       BrowserThread::IO, FROM_HERE,
141       base::Bind(&RemovePrerenderOnIOThreadTask, child_route_id_pair,
142                  prerender_contents->final_status()));
143
144   base::AutoLock lock(final_status_map_lock_);
145   size_t num_erased = final_status_map_.erase(child_route_id_pair);
146   DCHECK_EQ(1u, num_erased);
147 }
148
149 bool PrerenderTracker::SetFinalStatus(int child_id, int route_id,
150                                       FinalStatus desired_final_status,
151                                       FinalStatus* actual_final_status) {
152   DCHECK(desired_final_status >= FINAL_STATUS_USED &&
153          desired_final_status < FINAL_STATUS_MAX);
154
155   ChildRouteIdPair child_route_id_pair(child_id, route_id);
156
157   base::AutoLock lock(final_status_map_lock_);
158   FinalStatusMap::iterator final_status_it =
159       final_status_map_.find(child_route_id_pair);
160   if (final_status_it == final_status_map_.end()) {
161     // The RenderView has already been either used or destroyed.
162     if (actual_final_status)
163       *actual_final_status = FINAL_STATUS_MAX;
164     return false;
165   }
166
167   if (final_status_it->second.final_status == FINAL_STATUS_MAX) {
168     final_status_it->second.final_status = desired_final_status;
169     if (desired_final_status != FINAL_STATUS_USED) {
170       BrowserThread::PostTask(
171           BrowserThread::UI, FROM_HERE,
172           base::Bind(&DestroyPrerenderForRenderViewOnUI,
173                      final_status_it->second.prerender_manager, child_id,
174                      route_id, desired_final_status));
175     }
176
177     if (actual_final_status)
178       *actual_final_status = desired_final_status;
179     return true;
180   }
181
182   if (actual_final_status)
183     *actual_final_status = final_status_it->second.final_status;
184   return false;
185 }
186
187 bool PrerenderTracker::IsPrerenderingOnIOThread(int child_id,
188                                                 int route_id) const {
189   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
190
191   ChildRouteIdPair child_route_id_pair(child_id, route_id);
192   return resource_throttle_io_thread_map_.count(child_route_id_pair) > 0;
193 }
194
195 void PrerenderTracker::AddResourceThrottleOnIOThread(
196     int child_id,
197     int route_id,
198     const base::WeakPtr<PrerenderResourceThrottle>& throttle) {
199   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
200
201   ChildRouteIdPair child_route_id_pair(child_id, route_id);
202   ResourceThrottleMap::iterator resource_throttle_map_it =
203       resource_throttle_io_thread_map_.find(child_route_id_pair);
204   DCHECK(resource_throttle_map_it != resource_throttle_io_thread_map_.end());
205   resource_throttle_map_it->second.push_back(throttle);
206 }
207
208 void PrerenderTracker::AddPrerenderOnIOThread(
209     const ChildRouteIdPair& child_route_id_pair) {
210   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211   DCHECK(!IsPrerenderingOnIOThread(child_route_id_pair.first,
212                                    child_route_id_pair.second));
213
214   resource_throttle_io_thread_map_.insert(
215       std::make_pair(child_route_id_pair, ResourceThrottleList()));
216 }
217
218 void PrerenderTracker::RemovePrerenderOnIOThread(
219     const ChildRouteIdPair& child_route_id_pair,
220     FinalStatus final_status) {
221   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
222   DCHECK(IsPrerenderingOnIOThread(child_route_id_pair.first,
223                                   child_route_id_pair.second));
224
225   // Cancel or resume all throttled resources.
226   ResourceThrottleMap::iterator resource_throttle_map_it =
227       resource_throttle_io_thread_map_.find(child_route_id_pair);
228   DCHECK(resource_throttle_map_it != resource_throttle_io_thread_map_.end());
229   ResourceThrottleList& throttles = resource_throttle_map_it->second;
230   for (size_t i = 0; i < throttles.size(); i++) {
231     if (throttles[i]) {
232       if (final_status == FINAL_STATUS_USED) {
233         throttles[i]->Resume();
234       } else {
235         throttles[i]->Cancel();
236       }
237     }
238   }
239   resource_throttle_io_thread_map_.erase(resource_throttle_map_it);
240 }
241
242 // static
243 PrerenderTracker* PrerenderTracker::GetDefault() {
244   return g_browser_process->prerender_tracker();
245 }
246
247 // static
248 void PrerenderTracker::AddPrerenderOnIOThreadTask(
249     const ChildRouteIdPair& child_route_id_pair) {
250   GetDefault()->AddPrerenderOnIOThread(child_route_id_pair);
251 }
252
253 // static
254 void PrerenderTracker::RemovePrerenderOnIOThreadTask(
255     const ChildRouteIdPair& child_route_id_pair,
256     FinalStatus final_status) {
257   GetDefault()->RemovePrerenderOnIOThread(child_route_id_pair, final_status);
258 }
259
260 }  // namespace prerender