1 // Copyright 2014 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 "extensions/browser/api/serial/serial_event_dispatcher.h" 6 7 #include "base/lazy_instance.h" 8 #include "extensions/browser/api/serial/serial_connection.h" 9 #include "extensions/browser/event_router.h" 10 #include "extensions/browser/extensions_browser_client.h" 11 12 namespace extensions { 13 14 namespace core_api { 15 16 namespace { 17 18 bool ShouldPauseOnReceiveError(serial::ReceiveError error) { 19 return error == serial::RECEIVE_ERROR_DEVICE_LOST || 20 error == serial::RECEIVE_ERROR_SYSTEM_ERROR || 21 error == serial::RECEIVE_ERROR_DISCONNECTED; 22 } 23 24 } // namespace 25 26 static base::LazyInstance<BrowserContextKeyedAPIFactory<SerialEventDispatcher> > 27 g_factory = LAZY_INSTANCE_INITIALIZER; 28 29 // static 30 BrowserContextKeyedAPIFactory<SerialEventDispatcher>* 31 SerialEventDispatcher::GetFactoryInstance() { 32 return g_factory.Pointer(); 33 } 34 35 // static 36 SerialEventDispatcher* SerialEventDispatcher::Get( 37 content::BrowserContext* context) { 38 return BrowserContextKeyedAPIFactory<SerialEventDispatcher>::Get(context); 39 } 40 41 SerialEventDispatcher::SerialEventDispatcher(content::BrowserContext* context) 42 : thread_id_(SerialConnection::kThreadId), context_(context) { 43 ApiResourceManager<SerialConnection>* manager = 44 ApiResourceManager<SerialConnection>::Get(context_); 45 DCHECK(manager) << "No serial connection manager."; 46 connections_ = manager->data_; 47 } 48 49 SerialEventDispatcher::~SerialEventDispatcher() { 50 } 51 52 SerialEventDispatcher::ReceiveParams::ReceiveParams() { 53 } 54 55 SerialEventDispatcher::ReceiveParams::~ReceiveParams() { 56 } 57 58 void SerialEventDispatcher::PollConnection(const std::string& extension_id, 59 int connection_id) { 60 DCHECK_CURRENTLY_ON(thread_id_); 61 62 ReceiveParams params; 63 params.thread_id = thread_id_; 64 params.browser_context_id = context_; 65 params.extension_id = extension_id; 66 params.connections = connections_; 67 params.connection_id = connection_id; 68 69 StartReceive(params); 70 } 71 72 // static 73 void SerialEventDispatcher::StartReceive(const ReceiveParams& params) { 74 DCHECK_CURRENTLY_ON(params.thread_id); 75 76 SerialConnection* connection = 77 params.connections->Get(params.extension_id, params.connection_id); 78 if (!connection) 79 return; 80 DCHECK(params.extension_id == connection->owner_extension_id()); 81 82 if (connection->paused()) 83 return; 84 85 connection->Receive(base::Bind(&ReceiveCallback, params)); 86 } 87 88 // static 89 void SerialEventDispatcher::ReceiveCallback(const ReceiveParams& params, 90 const std::string& data, 91 serial::ReceiveError error) { 92 DCHECK_CURRENTLY_ON(params.thread_id); 93 94 // Note that an error (e.g. timeout) does not necessarily mean that no data 95 // was read, so we may fire an onReceive regardless of any error code. 96 if (data.length() > 0) { 97 serial::ReceiveInfo receive_info; 98 receive_info.connection_id = params.connection_id; 99 receive_info.data = data; 100 scoped_ptr<base::ListValue> args = serial::OnReceive::Create(receive_info); 101 scoped_ptr<extensions::Event> event( 102 new extensions::Event(serial::OnReceive::kEventName, args.Pass())); 103 PostEvent(params, event.Pass()); 104 } 105 106 if (error != serial::RECEIVE_ERROR_NONE) { 107 serial::ReceiveErrorInfo error_info; 108 error_info.connection_id = params.connection_id; 109 error_info.error = error; 110 scoped_ptr<base::ListValue> args = 111 serial::OnReceiveError::Create(error_info); 112 scoped_ptr<extensions::Event> event( 113 new extensions::Event(serial::OnReceiveError::kEventName, args.Pass())); 114 PostEvent(params, event.Pass()); 115 if (ShouldPauseOnReceiveError(error)) { 116 SerialConnection* connection = 117 params.connections->Get(params.extension_id, params.connection_id); 118 if (connection) 119 connection->set_paused(true); 120 } 121 } 122 123 // Queue up the next read operation. 124 BrowserThread::PostTask( 125 params.thread_id, FROM_HERE, base::Bind(&StartReceive, params)); 126 } 127 128 // static 129 void SerialEventDispatcher::PostEvent(const ReceiveParams& params, 130 scoped_ptr<extensions::Event> event) { 131 DCHECK_CURRENTLY_ON(params.thread_id); 132 133 BrowserThread::PostTask(BrowserThread::UI, 134 FROM_HERE, 135 base::Bind(&DispatchEvent, 136 params.browser_context_id, 137 params.extension_id, 138 base::Passed(event.Pass()))); 139 } 140 141 // static 142 void SerialEventDispatcher::DispatchEvent(void* browser_context_id, 143 const std::string& extension_id, 144 scoped_ptr<extensions::Event> event) { 145 DCHECK_CURRENTLY_ON(BrowserThread::UI); 146 147 content::BrowserContext* context = 148 reinterpret_cast<content::BrowserContext*>(browser_context_id); 149 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context)) 150 return; 151 152 EventRouter* router = EventRouter::Get(context); 153 if (router) 154 router->DispatchEventToExtension(extension_id, event.Pass()); 155 } 156 157 } // namespace core_api 158 159 } // namespace extensions 160