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