diff options
11 files changed, 135 insertions, 51 deletions
diff --git a/chrome/browser/extensions/api/api_function.cc b/chrome/browser/extensions/api/api_function.cc index 18f5320..6d24c66 100644 --- a/chrome/browser/extensions/api/api_function.cc +++ b/chrome/browser/extensions/api/api_function.cc @@ -9,13 +9,16 @@ #include "chrome/browser/extensions/api/api_resource_event_notifier.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" -#include "content/public/browser/browser_thread.h" using content::BrowserThread; namespace extensions { -bool AsyncIOAPIFunction::RunImpl() { +AsyncAPIFunction::AsyncAPIFunction() + : work_thread_id_(BrowserThread::IO) { +} + +bool AsyncAPIFunction::RunImpl() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); extension_service_ = profile()->GetExtensionService(); @@ -23,42 +26,46 @@ bool AsyncIOAPIFunction::RunImpl() { return false; } bool rv = BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&AsyncIOAPIFunction::WorkOnIOThread, this)); + work_thread_id_, FROM_HERE, + base::Bind(&AsyncAPIFunction::WorkOnWorkThread, this)); DCHECK(rv); return true; } -void AsyncIOAPIFunction::Work() { +void AsyncAPIFunction::Work() { } -void AsyncIOAPIFunction::AsyncWorkStart() { +void AsyncAPIFunction::AsyncWorkStart() { Work(); AsyncWorkCompleted(); } -void AsyncIOAPIFunction::AsyncWorkCompleted() { +void AsyncAPIFunction::AsyncWorkCompleted() { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { bool rv = BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind(&AsyncIOAPIFunction::RespondOnUIThread, this)); + base::Bind(&AsyncAPIFunction::RespondOnUIThread, this)); DCHECK(rv); } else { SendResponse(Respond()); } } -void AsyncIOAPIFunction::WorkOnIOThread() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); +void AsyncAPIFunction::WorkOnWorkThread() { + DCHECK(BrowserThread::CurrentlyOn(work_thread_id_)); + DCHECK(work_thread_id_ != BrowserThread::UI) << + "You have specified that AsyncAPIFunction::Work() should happen on " + "the UI thread. This nullifies the point of this class. Either " + "specify a different thread or derive from a different class."; AsyncWorkStart(); } -void AsyncIOAPIFunction::RespondOnUIThread() { +void AsyncAPIFunction::RespondOnUIThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); SendResponse(Respond()); } -int AsyncIOAPIFunction::ExtractSrcId(size_t argument_position) { +int AsyncAPIFunction::ExtractSrcId(size_t argument_position) { scoped_ptr<DictionaryValue> options(new DictionaryValue()); if (args_->GetSize() > argument_position) { DictionaryValue* temp_options = NULL; @@ -76,17 +83,16 @@ int AsyncIOAPIFunction::ExtractSrcId(size_t argument_position) { return src_id; } -APIResourceEventNotifier* AsyncIOAPIFunction::CreateEventNotifier(int src_id) { +APIResourceEventNotifier* AsyncAPIFunction::CreateEventNotifier(int src_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); return new APIResourceEventNotifier( profile()->GetExtensionEventRouter(), profile(), extension_id(), src_id, source_url()); } -APIResourceController* AsyncIOAPIFunction::controller() { +APIResourceController* AsyncAPIFunction::controller() { // ExtensionService's APIResourceController is set exactly once, long before - // this code is reached, so it's safe to access it on either the IO or UI - // thread. + // this code is reached, so it's safe to access it on any thread. return extension_service_->api_resource_controller(); } diff --git a/chrome/browser/extensions/api/api_function.h b/chrome/browser/extensions/api/api_function.h index 229d1c5..ad48a2d 100644 --- a/chrome/browser/extensions/api/api_function.h +++ b/chrome/browser/extensions/api/api_function.h @@ -8,6 +8,7 @@ #include "chrome/browser/extensions/extension_function.h" #include "chrome/browser/extensions/api/api_resource.h" +#include "content/public/browser/browser_thread.h" class ExtensionService; @@ -16,11 +17,12 @@ namespace extensions { class APIResourceController; class APIResourceEventNotifier; -// AsyncIOAPIFunction provides convenient thread management for APIs that -// need to do essentially all their work on the IO thread. -class AsyncIOAPIFunction : public AsyncExtensionFunction { +// AsyncAPIFunction provides convenient thread management for APIs that need to +// do essentially all their work on the IO or FILE thread. +class AsyncAPIFunction : public AsyncExtensionFunction { protected: - virtual ~AsyncIOAPIFunction() {} + AsyncAPIFunction(); + virtual ~AsyncAPIFunction() {} // Set up for work (e.g., validate arguments). Guaranteed to happen on UI // thread. @@ -48,11 +50,16 @@ class AsyncIOAPIFunction : public AsyncExtensionFunction { // Access to the controller singleton. APIResourceController* controller(); - // ExtensionFunction: + // ExtensionFunction::RunImpl() virtual bool RunImpl() OVERRIDE; + protected: + // If you don't want your Work() method to happen on the IO thread, then set + // this to the thread that you do want, preferably in Prepare(). + content::BrowserThread::ID work_thread_id_; + private: - void WorkOnIOThread(); + void WorkOnWorkThread(); void RespondOnUIThread(); ExtensionService* extension_service_; diff --git a/chrome/browser/extensions/api/serial/serial_api.cc b/chrome/browser/extensions/api/serial/serial_api.cc index e25b8cf..93855f2 100644 --- a/chrome/browser/extensions/api/serial/serial_api.cc +++ b/chrome/browser/extensions/api/serial/serial_api.cc @@ -9,14 +9,43 @@ #include "base/values.h" #include "chrome/browser/extensions/api/api_resource_controller.h" #include "chrome/browser/extensions/api/serial/serial_connection.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; namespace extensions { const char kConnectionIdKey[] = "connectionId"; +const char kPortsKey[] = "ports"; const char kDataKey[] = "data"; const char kBytesReadKey[] = "bytesRead"; const char kBytesWrittenKey[] = "bytesWritten"; +SerialGetPortsFunction::SerialGetPortsFunction() {} + +bool SerialGetPortsFunction::Prepare() { + work_thread_id_ = BrowserThread::FILE; + return true; +} + +void SerialGetPortsFunction::Work() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + ListValue* ports = new ListValue(); + SerialConnection::StringSet port_names = + SerialConnection::GenerateValidSerialPortNames(); + SerialConnection::StringSet::const_iterator i = port_names.begin(); + while (i != port_names.end()) { + ports->Append(Value::CreateStringValue(*i++)); + } + + result_.reset(ports); +} + +bool SerialGetPortsFunction::Respond() { + return true; +} + SerialOpenFunction::SerialOpenFunction() : src_id_(-1) {} bool SerialOpenFunction::Prepare() { diff --git a/chrome/browser/extensions/api/serial/serial_api.h b/chrome/browser/extensions/api/serial/serial_api.h index 902d641..7965d87 100644 --- a/chrome/browser/extensions/api/serial/serial_api.h +++ b/chrome/browser/extensions/api/serial/serial_api.h @@ -16,7 +16,22 @@ namespace extensions { extern const char kConnectionIdKey[]; -class SerialOpenFunction : public AsyncIOAPIFunction { +class SerialGetPortsFunction : public AsyncAPIFunction { + public: + DECLARE_EXTENSION_FUNCTION_NAME("experimental.serial.getPorts") + + SerialGetPortsFunction(); + + protected: + virtual ~SerialGetPortsFunction() {} + + // AsyncAPIFunction: + virtual bool Prepare() OVERRIDE; + virtual void Work() OVERRIDE; + virtual bool Respond() OVERRIDE; +}; + +class SerialOpenFunction : public AsyncAPIFunction { public: DECLARE_EXTENSION_FUNCTION_NAME("experimental.serial.open") @@ -25,7 +40,7 @@ class SerialOpenFunction : public AsyncIOAPIFunction { protected: virtual ~SerialOpenFunction() {} - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void Work() OVERRIDE; virtual bool Respond() OVERRIDE; @@ -35,14 +50,14 @@ class SerialOpenFunction : public AsyncIOAPIFunction { std::string port_; }; -class SerialCloseFunction : public AsyncIOAPIFunction { +class SerialCloseFunction : public AsyncAPIFunction { public: DECLARE_EXTENSION_FUNCTION_NAME("experimental.serial.close") protected: virtual ~SerialCloseFunction() {} - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void Work() OVERRIDE; virtual bool Respond() OVERRIDE; @@ -51,14 +66,14 @@ class SerialCloseFunction : public AsyncIOAPIFunction { int connection_id_; }; -class SerialReadFunction : public AsyncIOAPIFunction { +class SerialReadFunction : public AsyncAPIFunction { public: DECLARE_EXTENSION_FUNCTION_NAME("experimental.serial.read") protected: virtual ~SerialReadFunction() {} - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void Work() OVERRIDE; virtual bool Respond() OVERRIDE; @@ -67,7 +82,7 @@ class SerialReadFunction : public AsyncIOAPIFunction { int connection_id_; }; -class SerialWriteFunction : public AsyncIOAPIFunction { +class SerialWriteFunction : public AsyncAPIFunction { public: DECLARE_EXTENSION_FUNCTION_NAME("experimental.serial.write") @@ -76,7 +91,7 @@ class SerialWriteFunction : public AsyncIOAPIFunction { protected: virtual ~SerialWriteFunction(); - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void Work() OVERRIDE; virtual bool Respond() OVERRIDE; diff --git a/chrome/browser/extensions/api/serial/serial_connection.cc b/chrome/browser/extensions/api/serial/serial_connection.cc index ed9314b..d17a707 100644 --- a/chrome/browser/extensions/api/serial/serial_connection.cc +++ b/chrome/browser/extensions/api/serial/serial_connection.cc @@ -8,7 +8,7 @@ namespace extensions { -const char kSerialConnectionNotFoundError[] = "Serial conenction not found"; +const char kSerialConnectionNotFoundError[] = "Serial connection not found"; // static bool SerialConnection::DoesPortExist(const StringSet& name_set, diff --git a/chrome/browser/extensions/api/serial/serial_connection.h b/chrome/browser/extensions/api/serial/serial_connection.h index d62189d..7dca2aa 100644 --- a/chrome/browser/extensions/api/serial/serial_connection.h +++ b/chrome/browser/extensions/api/serial/serial_connection.h @@ -44,11 +44,9 @@ class SerialConnection : public APIResource { static bool DoesPortExist(const StringSet& port_patterns, const std::string& port_name); - private: - // TODO(miket): expose this functionality via API. Otherwise developers have - // to guess at valid names. static StringSet GenerateValidSerialPortNames(); + private: // Returns a StringSet of patterns to be used with MatchPattern. static StringSet GenerateValidPatterns(); diff --git a/chrome/browser/extensions/api/serial/serial_connection_posix.cc b/chrome/browser/extensions/api/serial/serial_connection_posix.cc index 4e1fa5d..8e6e567 100644 --- a/chrome/browser/extensions/api/serial/serial_connection_posix.cc +++ b/chrome/browser/extensions/api/serial/serial_connection_posix.cc @@ -14,6 +14,9 @@ #include "base/file_path.h" #include "base/file_util.h" #include "base/string_util.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; namespace extensions { @@ -105,6 +108,7 @@ SerialConnection::StringSet SerialConnection::GenerateValidPatterns() { // TODO(miket): this might be refactorable into serial_connection.cc, if // Windows serial-port enumeration also entails looking through a directory. SerialConnection::StringSet SerialConnection::GenerateValidSerialPortNames() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); const FilePath DEV_ROOT("/dev"); const file_util::FileEnumerator::FileType FILES_AND_SYM_LINKS = static_cast<file_util::FileEnumerator::FileType>( diff --git a/chrome/browser/extensions/api/socket/socket_api.h b/chrome/browser/extensions/api/socket/socket_api.h index 4ed01df..f919708 100644 --- a/chrome/browser/extensions/api/socket/socket_api.h +++ b/chrome/browser/extensions/api/socket/socket_api.h @@ -21,7 +21,7 @@ extern const char kBytesWrittenKey[]; extern const char kSocketIdKey[]; extern const char kUdpSocketType[]; -class SocketExtensionFunction : public AsyncIOAPIFunction { +class SocketExtensionFunction : public AsyncAPIFunction { public: virtual void Work() OVERRIDE; virtual bool Respond() OVERRIDE; @@ -42,7 +42,7 @@ class SocketCreateFunction : public SocketExtensionFunction { protected: virtual ~SocketCreateFunction(); - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void Work() OVERRIDE; @@ -65,7 +65,7 @@ class SocketDestroyFunction : public SocketExtensionFunction { protected: virtual ~SocketDestroyFunction() {} - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void Work() OVERRIDE; @@ -82,7 +82,7 @@ class SocketConnectFunction : public SocketExtensionFunction { protected: virtual ~SocketConnectFunction() {} - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void AsyncWorkStart() OVERRIDE; @@ -99,7 +99,7 @@ class SocketDisconnectFunction : public SocketExtensionFunction { protected: virtual ~SocketDisconnectFunction() {} - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void Work() OVERRIDE; @@ -129,7 +129,7 @@ class SocketReadFunction : public SocketExtensionFunction { protected: virtual ~SocketReadFunction() {} - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void AsyncWorkStart() OVERRIDE; @@ -147,7 +147,7 @@ class SocketWriteFunction : public SocketExtensionFunction { protected: virtual ~SocketWriteFunction(); - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void AsyncWorkStart() OVERRIDE; @@ -168,7 +168,7 @@ class SocketRecvFromFunction : public SocketExtensionFunction { protected: virtual ~SocketRecvFromFunction(); - // AsyncIOAPIFunction + // AsyncAPIFunction virtual bool Prepare() OVERRIDE; virtual void AsyncWorkStart() OVERRIDE; @@ -186,7 +186,7 @@ class SocketSendToFunction : public SocketExtensionFunction { virtual ~SocketSendToFunction(); void OnCompleted(int result); - // AsyncIOAPIFunction: + // AsyncAPIFunction: virtual bool Prepare() OVERRIDE; virtual void AsyncWorkStart() OVERRIDE; diff --git a/chrome/browser/extensions/api/usb/usb_api.h b/chrome/browser/extensions/api/usb/usb_api.h index b182f65..402eb9b 100644 --- a/chrome/browser/extensions/api/usb/usb_api.h +++ b/chrome/browser/extensions/api/usb/usb_api.h @@ -15,7 +15,7 @@ namespace extensions { class APIResourceEventNotifier; -class UsbFindDeviceFunction : public AsyncIOAPIFunction { +class UsbFindDeviceFunction : public AsyncAPIFunction { public: UsbFindDeviceFunction(); virtual ~UsbFindDeviceFunction(); @@ -32,7 +32,7 @@ class UsbFindDeviceFunction : public AsyncIOAPIFunction { DECLARE_EXTENSION_FUNCTION_NAME("experimental.usb.findDevice"); }; -class UsbCloseDeviceFunction : public AsyncIOAPIFunction { +class UsbCloseDeviceFunction : public AsyncAPIFunction { public: UsbCloseDeviceFunction(); virtual ~UsbCloseDeviceFunction(); @@ -49,7 +49,7 @@ class UsbCloseDeviceFunction : public AsyncIOAPIFunction { DECLARE_EXTENSION_FUNCTION_NAME("experimental.usb.closeDevice"); }; -class UsbControlTransferFunction : public AsyncIOAPIFunction { +class UsbControlTransferFunction : public AsyncAPIFunction { public: UsbControlTransferFunction(); virtual ~UsbControlTransferFunction(); @@ -66,7 +66,7 @@ class UsbControlTransferFunction : public AsyncIOAPIFunction { DECLARE_EXTENSION_FUNCTION_NAME("experimental.usb.controlTransfer"); }; -class UsbBulkTransferFunction : public AsyncIOAPIFunction { +class UsbBulkTransferFunction : public AsyncAPIFunction { public: UsbBulkTransferFunction(); virtual ~UsbBulkTransferFunction(); @@ -83,7 +83,7 @@ class UsbBulkTransferFunction : public AsyncIOAPIFunction { DECLARE_EXTENSION_FUNCTION_NAME("experimental.usb.bulkTransfer"); }; -class UsbInterruptTransferFunction : public AsyncIOAPIFunction { +class UsbInterruptTransferFunction : public AsyncAPIFunction { public: UsbInterruptTransferFunction(); virtual ~UsbInterruptTransferFunction(); diff --git a/chrome/common/extensions/api/experimental.serial.idl b/chrome/common/extensions/api/experimental.serial.idl index ebc6c06..dab96431 100644 --- a/chrome/common/extensions/api/experimental.serial.idl +++ b/chrome/common/extensions/api/experimental.serial.idl @@ -6,6 +6,8 @@ [nodoc] namespace experimental.serial { + callback GetPortsCallback = void (DOMString[] ports); + dictionary OpenInfo { // The id of the opened connection. long connectionId; @@ -35,6 +37,13 @@ callback WriteCallback = void (WriteInfo writeInfo); interface Functions { + // Returns names of valid ports on this machine, each of which is likely to + // be valid to pass as the port argument to open(). The list is regenerated + // each time this method is called, as port validity is dynamic. + // + // |callback| : Called with the list of ports. + static void getPorts(GetPortsCallback callback); + // Opens a connection to the given serial port. // |port| : The name of the serial port to open. // |callback| : Called when the connection has been opened. diff --git a/chrome/test/data/extensions/api_test/serial/api/background.js b/chrome/test/data/extensions/api_test/serial/api/background.js index 60d62bb..7bb35da 100644 --- a/chrome/test/data/extensions/api_test/serial/api/background.js +++ b/chrome/test/data/extensions/api_test/serial/api/background.js @@ -32,11 +32,27 @@ var testSerial = function() { chrome.experimental.serial.open(serialPort, onOpen); }; +var testGetPorts = function() { + var onGetPorts = function(ports) { + // Any length is potentially valid, because we're on unknown hardware. But + // we are testing at least that the ports member was filled in, so it's + // still a somewhat meaningful test. + chrome.test.assertTrue(ports.length >= 0); + chrome.test.succeed(); + } + + chrome.experimental.serial.getPorts(onGetPorts); +}; + var onMessageReply = function(message) { serialPort = message; - if (message == 'none') { - chrome.test.runTests([]); - } else { + var generalTests = [ testGetPorts ]; + + chrome.test.runTests(generalTests); + if (message != 'none') { + // We have a specific serial port set up to respond to test traffic. This + // is a rare situation. TODO(miket): mock to make it testable under any + // hardware conditions. chrome.test.runTests([ testSerial ]); } }; |