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 "content/browser/media/media_internals_proxy.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/browser/media/media_internals_handler.h"
10 #include "content/public/browser/content_browser_client.h"
11 #include "content/public/browser/notification_service.h"
12 #include "content/public/browser/notification_types.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/browser/web_ui.h"
15
16 namespace content {
17
18 static const int kMediaInternalsProxyEventDelayMilliseconds = 100;
19
20 static const net::NetLog::EventType kNetEventTypeFilter[] = {
21 net::NetLog::TYPE_DISK_CACHE_ENTRY_IMPL,
22 net::NetLog::TYPE_SPARSE_READ,
23 net::NetLog::TYPE_SPARSE_WRITE,
24 net::NetLog::TYPE_URL_REQUEST_START_JOB,
25 net::NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
26 };
27
MediaInternalsProxy()28 MediaInternalsProxy::MediaInternalsProxy() {
29 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
30 NotificationService::AllBrowserContextsAndSources());
31 }
32
Observe(int type,const NotificationSource & source,const NotificationDetails & details)33 void MediaInternalsProxy::Observe(int type,
34 const NotificationSource& source,
35 const NotificationDetails& details) {
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
37 DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
38 RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
39 CallJavaScriptFunctionOnUIThread("media.onRendererTerminated",
40 new base::FundamentalValue(process->GetID()));
41 }
42
Attach(MediaInternalsMessageHandler * handler)43 void MediaInternalsProxy::Attach(MediaInternalsMessageHandler* handler) {
44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
45 handler_ = handler;
46 BrowserThread::PostTask(
47 BrowserThread::IO, FROM_HERE,
48 base::Bind(&MediaInternalsProxy::ObserveMediaInternalsOnIOThread, this));
49 }
50
Detach()51 void MediaInternalsProxy::Detach() {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
53 handler_ = NULL;
54 BrowserThread::PostTask(
55 BrowserThread::IO, FROM_HERE,
56 base::Bind(
57 &MediaInternalsProxy::StopObservingMediaInternalsOnIOThread, this));
58 }
59
GetEverything()60 void MediaInternalsProxy::GetEverything() {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
62
63 // Ask MediaInternals for all its data.
64 BrowserThread::PostTask(
65 BrowserThread::IO, FROM_HERE,
66 base::Bind(&MediaInternalsProxy::GetEverythingOnIOThread, this));
67
68 // Send the page names for constants.
69 CallJavaScriptFunctionOnUIThread("media.onReceiveConstants", GetConstants());
70 }
71
OnUpdate(const base::string16 & update)72 void MediaInternalsProxy::OnUpdate(const base::string16& update) {
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
74 BrowserThread::PostTask(
75 BrowserThread::UI, FROM_HERE,
76 base::Bind(&MediaInternalsProxy::UpdateUIOnUIThread, this, update));
77 }
78
OnAddEntry(const net::NetLog::Entry & entry)79 void MediaInternalsProxy::OnAddEntry(const net::NetLog::Entry& entry) {
80 bool is_event_interesting = false;
81 for (size_t i = 0; i < arraysize(kNetEventTypeFilter); i++) {
82 if (entry.type() == kNetEventTypeFilter[i]) {
83 is_event_interesting = true;
84 break;
85 }
86 }
87
88 if (!is_event_interesting)
89 return;
90
91 BrowserThread::PostTask(
92 BrowserThread::UI, FROM_HERE,
93 base::Bind(&MediaInternalsProxy::AddNetEventOnUIThread, this,
94 entry.ToValue()));
95 }
96
~MediaInternalsProxy()97 MediaInternalsProxy::~MediaInternalsProxy() {}
98
GetConstants()99 base::Value* MediaInternalsProxy::GetConstants() {
100 base::DictionaryValue* event_phases = new base::DictionaryValue();
101 event_phases->SetInteger(
102 net::NetLog::EventPhaseToString(net::NetLog::PHASE_NONE),
103 net::NetLog::PHASE_NONE);
104 event_phases->SetInteger(
105 net::NetLog::EventPhaseToString(net::NetLog::PHASE_BEGIN),
106 net::NetLog::PHASE_BEGIN);
107 event_phases->SetInteger(
108 net::NetLog::EventPhaseToString(net::NetLog::PHASE_END),
109 net::NetLog::PHASE_END);
110
111 base::DictionaryValue* constants = new base::DictionaryValue();
112 constants->Set("eventTypes", net::NetLog::GetEventTypesAsValue());
113 constants->Set("eventPhases", event_phases);
114
115 return constants;
116 }
117
ObserveMediaInternalsOnIOThread()118 void MediaInternalsProxy::ObserveMediaInternalsOnIOThread() {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
120 update_callback_ = base::Bind(&MediaInternalsProxy::OnUpdate,
121 base::Unretained(this));
122 MediaInternals::GetInstance()->AddUpdateCallback(update_callback_);
123 if (GetContentClient()->browser()->GetNetLog()) {
124 net::NetLog* net_log = GetContentClient()->browser()->GetNetLog();
125 net_log->AddThreadSafeObserver(this, net::NetLog::LOG_ALL_BUT_BYTES);
126 }
127 }
128
StopObservingMediaInternalsOnIOThread()129 void MediaInternalsProxy::StopObservingMediaInternalsOnIOThread() {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131 MediaInternals::GetInstance()->RemoveUpdateCallback(update_callback_);
132 if (GetContentClient()->browser()->GetNetLog()) {
133 net::NetLog* net_log = GetContentClient()->browser()->GetNetLog();
134 net_log->RemoveThreadSafeObserver(this);
135 }
136 }
137
GetEverythingOnIOThread()138 void MediaInternalsProxy::GetEverythingOnIOThread() {
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
140 MediaInternals::GetInstance()->SendEverything();
141 }
142
UpdateUIOnUIThread(const base::string16 & update)143 void MediaInternalsProxy::UpdateUIOnUIThread(const base::string16& update) {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145 // Don't forward updates to a destructed UI.
146 if (handler_)
147 handler_->OnUpdate(update);
148 }
149
AddNetEventOnUIThread(base::Value * entry)150 void MediaInternalsProxy::AddNetEventOnUIThread(base::Value* entry) {
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152
153 // Send the updates to the page in kMediaInternalsProxyEventDelayMilliseconds
154 // if an update is not already pending.
155 if (!pending_net_updates_) {
156 pending_net_updates_.reset(new base::ListValue());
157 base::MessageLoop::current()->PostDelayedTask(
158 FROM_HERE,
159 base::Bind(&MediaInternalsProxy::SendNetEventsOnUIThread, this),
160 base::TimeDelta::FromMilliseconds(
161 kMediaInternalsProxyEventDelayMilliseconds));
162 }
163 pending_net_updates_->Append(entry);
164 }
165
SendNetEventsOnUIThread()166 void MediaInternalsProxy::SendNetEventsOnUIThread() {
167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
168 CallJavaScriptFunctionOnUIThread("media.onNetUpdate",
169 pending_net_updates_.release());
170 }
171
CallJavaScriptFunctionOnUIThread(const std::string & function,base::Value * args)172 void MediaInternalsProxy::CallJavaScriptFunctionOnUIThread(
173 const std::string& function, base::Value* args) {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175 scoped_ptr<base::Value> args_value(args);
176 std::vector<const base::Value*> args_vector;
177 args_vector.push_back(args_value.get());
178 base::string16 update = WebUI::GetJavascriptCall(function, args_vector);
179 UpdateUIOnUIThread(update);
180 }
181
182 } // namespace content
183