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/extensions/extension_system.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/browser/profiles/profile_manager.h" 12#include "extensions/browser/event_router.h" 13 14namespace extensions { 15 16namespace api { 17 18namespace { 19 20bool ShouldPauseOnReceiveError(serial::ReceiveError error) { 21 return error == serial::RECEIVE_ERROR_DEVICE_LOST || 22 error == serial::RECEIVE_ERROR_SYSTEM_ERROR || 23 error == serial::RECEIVE_ERROR_DISCONNECTED; 24} 25 26} // namespace 27 28static base::LazyInstance<ProfileKeyedAPIFactory<SerialEventDispatcher> > 29 g_factory = LAZY_INSTANCE_INITIALIZER; 30 31// static 32ProfileKeyedAPIFactory<SerialEventDispatcher>* 33 SerialEventDispatcher::GetFactoryInstance() { 34 return &g_factory.Get(); 35} 36 37// static 38SerialEventDispatcher* SerialEventDispatcher::Get(Profile* profile) { 39 return ProfileKeyedAPIFactory<SerialEventDispatcher>::GetForProfile(profile); 40} 41 42SerialEventDispatcher::SerialEventDispatcher(Profile* profile) 43 : thread_id_(SerialConnection::kThreadId), 44 profile_(profile) { 45 ApiResourceManager<SerialConnection>* manager = 46 ApiResourceManager<SerialConnection>::Get(profile); 47 DCHECK(manager) << "No serial connection manager."; 48 connections_ = manager->data_; 49} 50 51SerialEventDispatcher::~SerialEventDispatcher() {} 52 53SerialEventDispatcher::ReceiveParams::ReceiveParams() {} 54 55SerialEventDispatcher::ReceiveParams::~ReceiveParams() {} 56 57void SerialEventDispatcher::PollConnection(const std::string& extension_id, 58 int connection_id) { 59 DCHECK(BrowserThread::CurrentlyOn(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 72void SerialEventDispatcher::StartReceive(const ReceiveParams& params) { 73 DCHECK(BrowserThread::CurrentlyOn(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 88void SerialEventDispatcher::ReceiveCallback(const ReceiveParams& params, 89 const std::string& data, 90 serial::ReceiveError error) { 91 DCHECK(BrowserThread::CurrentlyOn(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 129void SerialEventDispatcher::PostEvent(const ReceiveParams& params, 130 scoped_ptr<extensions::Event> event) { 131 DCHECK(BrowserThread::CurrentlyOn(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 142void SerialEventDispatcher::DispatchEvent(void* profile_id, 143 const std::string& extension_id, 144 scoped_ptr<extensions::Event> event) { 145 DCHECK(BrowserThread::CurrentlyOn(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 = ExtensionSystem::Get(profile)->event_router(); 152 if (router) 153 router->DispatchEventToExtension(extension_id, event.Pass()); 154} 155 156} // namespace api 157 158} // namespace extensions 159