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 28 MediaInternalsProxy::MediaInternalsProxy() { 29 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED, 30 NotificationService::AllBrowserContextsAndSources()); 31 } 32 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 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 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 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 72 void MediaInternalsProxy::OnUpdate(const 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 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 97 MediaInternalsProxy::~MediaInternalsProxy() {} 98 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 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 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 138 void MediaInternalsProxy::GetEverythingOnIOThread() { 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 140 MediaInternals::GetInstance()->SendEverything(); 141 } 142 143 void MediaInternalsProxy::UpdateUIOnUIThread(const 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 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 166 void MediaInternalsProxy::SendNetEventsOnUIThread() { 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 168 CallJavaScriptFunctionOnUIThread("media.onNetUpdate", 169 pending_net_updates_.release()); 170 } 171 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 string16 update = WebUI::GetJavascriptCall(function, args_vector); 179 UpdateUIOnUIThread(update); 180 } 181 182 } // namespace content 183