diff --git a/dom/system/gonk/Nfc.js b/dom/system/gonk/Nfc.js index e766f8d48bad..4ea40d75d004 100644 --- a/dom/system/gonk/Nfc.js +++ b/dom/system/gonk/Nfc.js @@ -111,6 +111,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () { }, _shutdown: function _shutdown() { + this.nfc.shutdown(); this.nfc = null; Services.obs.removeObserver(this, NFC.TOPIC_XPCOM_SHUTDOWN); @@ -419,18 +420,22 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () { }); function Nfc() { - debug("Starting Worker"); - this.worker = new ChromeWorker("resource://gre/modules/nfc_worker.js"); - this.worker.onerror = this.onerror.bind(this); - this.worker.onmessage = this.onmessage.bind(this); + debug("Starting Nfc Service"); + + let nfcService = Cc["@mozilla.org/nfc/service;1"].getService(Ci.nsINfcService); + if (!nfcService) { + debug("No nfc service component available!"); + return; + } + + nfcService.start(this); + this.nfcService = nfcService; gMessageManager.init(this); // Maps sessionId (that are generated from nfcd) with a unique guid : 'SessionToken' this.sessionTokenMap = {}; this.targetsByRequestId = {}; - - gSystemWorkerManager.registerNfcWorker(this.worker); } Nfc.prototype = { @@ -438,32 +443,26 @@ Nfc.prototype = { classID: NFC_CID, classInfo: XPCOMUtils.generateCI({classID: NFC_CID, classDescription: "Nfc", - interfaces: [Ci.nsIWorkerHolder]}), + interfaces: [Ci.nsINfcService]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder, Ci.nsIObserver]), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsINfcEventListener]), _currentSessionId: null, powerLevel: NFC.NFC_POWER_LEVEL_UNKNOWN, - onerror: function onerror(event) { - debug("Got an error: " + event.filename + ":" + - event.lineno + ": " + event.message + "\n"); - event.preventDefault(); - }, - /** - * Send arbitrary message to worker. + * Send arbitrary message to Nfc service. * * @param nfcMessageType * A text message type. * @param message [optional] * An optional message object to send. */ - sendToWorker: function sendToWorker(nfcMessageType, message) { + sendToNfcService: function sendToNfcService(nfcMessageType, message) { message = message || {}; message.type = nfcMessageType; - this.worker.postMessage(message); + this.nfcService.sendCommand(message); }, /** @@ -490,11 +489,11 @@ Nfc.prototype = { }, /** - * Process the incoming message from the NFC worker + * Process the incoming message from the NFC Service. */ - onmessage: function onmessage(event) { - let message = event.data; - debug("Received message from NFC worker: " + JSON.stringify(message)); + onEvent: function onEvent(event) { + let message = Cu.cloneInto(event, this); + debug("Received message from NFC Service: " + JSON.stringify(message)); // mapping error code to error message if (message.status !== undefined && message.status !== NFC.NFC_SUCCESS) { @@ -562,8 +561,7 @@ Nfc.prototype = { } }, - // nsINfcWorker - worker: null, + nfcService: null, sessionTokenMap: null, @@ -612,22 +610,22 @@ Nfc.prototype = { switch (message.name) { case "NFC:GetDetailsNDEF": - this.sendToWorker("getDetailsNDEF", message.json); + this.sendToNfcService("getDetailsNDEF", message.json); break; case "NFC:ReadNDEF": - this.sendToWorker("readNDEF", message.json); + this.sendToNfcService("readNDEF", message.json); break; case "NFC:WriteNDEF": - this.sendToWorker("writeNDEF", message.json); + this.sendToNfcService("writeNDEF", message.json); break; case "NFC:MakeReadOnlyNDEF": - this.sendToWorker("makeReadOnlyNDEF", message.json); + this.sendToNfcService("makeReadOnlyNDEF", message.json); break; case "NFC:Connect": - this.sendToWorker("connect", message.json); + this.sendToNfcService("connect", message.json); break; case "NFC:Close": - this.sendToWorker("close", message.json); + this.sendToNfcService("close", message.json); break; case "NFC:SendFile": // Chrome process is the arbitrator / mediator between @@ -658,7 +656,12 @@ Nfc.prototype = { }, setConfig: function setConfig(prop) { - this.sendToWorker("config", prop); + this.sendToNfcService("config", prop); + }, + + shutdown: function shutdown() { + this.nfcService.shutdown(); + this.nfcService = null; } }; diff --git a/dom/system/gonk/NfcMessageHandler.cpp b/dom/system/gonk/NfcMessageHandler.cpp new file mode 100644 index 000000000000..311c67150943 --- /dev/null +++ b/dom/system/gonk/NfcMessageHandler.cpp @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NfcMessageHandler.h" + +#include + +using namespace android; +using namespace mozilla; + +bool +NfcMessageHandler::Marshall(Parcel& aParcel, const CommandOptions& aOptions) +{ + bool result; + // TODO: Implementation will be Bug 933588 - Part 2. + return result; +} + +bool +NfcMessageHandler::Unmarshall(const Parcel& aParcel, EventOptions& aOptions) +{ + bool result; + // TODO: Implementation will be Bug 933588 - Part 2. + return result; +} + diff --git a/dom/system/gonk/NfcMessageHandler.h b/dom/system/gonk/NfcMessageHandler.h new file mode 100644 index 000000000000..a6516d0deb1c --- /dev/null +++ b/dom/system/gonk/NfcMessageHandler.h @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NfcMessageHandler_h +#define NfcMessageHandler_h + +namespace android { +class MOZ_EXPORT Parcel; +} // namespace android + +namespace mozilla { + +class CommandOptions; +class EventOptions; + +class NfcMessageHandler +{ +public: + bool Marshall(android::Parcel& aParcel, const CommandOptions& aOptions); + bool Unmarshall(const android::Parcel& aParcel, EventOptions& aOptions); +}; + +} // namespace mozilla + +#endif // NfcMessageHandler_h diff --git a/dom/system/gonk/NfcOptions.h b/dom/system/gonk/NfcOptions.h new file mode 100644 index 000000000000..bf154d3720a2 --- /dev/null +++ b/dom/system/gonk/NfcOptions.h @@ -0,0 +1,105 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NfcOptions_h +#define NfcOptions_h + +#include "mozilla/dom/NfcOptionsBinding.h" + +namespace mozilla { + +struct NDEFRecordStruct +{ + uint8_t mTnf; + nsTArray mType; + nsTArray mId; + nsTArray mPayload; +}; + +struct CommandOptions +{ + CommandOptions(const mozilla::dom::NfcCommandOptions& aOther) { + +#define COPY_FIELD(prop) prop = aOther.prop; + +#define COPY_OPT_FIELD(prop, defaultValue) \ + if (aOther.prop.WasPassed()) { \ + prop = aOther.prop.Value(); \ + } else { \ + prop = defaultValue; \ + } + + COPY_FIELD(mType) + COPY_FIELD(mRequestId) + COPY_OPT_FIELD(mSessionId, 0) + COPY_OPT_FIELD(mPowerLevel, 0) + COPY_OPT_FIELD(mTechType, 0) + + if (!aOther.mRecords.WasPassed()) { + return; + } + + mozilla::dom::Sequence const & currentValue = aOther.mRecords.InternalValue(); + int count = currentValue.Length(); + for (uint32_t i = 0; i < count; i++) { + NDEFRecordStruct record; + record.mTnf = currentValue[i].mTnf.Value(); + + if (currentValue[i].mType.WasPassed()) { + currentValue[i].mType.Value().ComputeLengthAndData(); + record.mType.AppendElements(currentValue[i].mType.Value().Data(), + currentValue[i].mType.Value().Length()); + } + + if (currentValue[i].mId.WasPassed()) { + currentValue[i].mId.Value().ComputeLengthAndData(); + record.mId.AppendElements(currentValue[i].mId.Value().Data(), + currentValue[i].mId.Value().Length()); + } + + if (currentValue[i].mPayload.WasPassed()) { + currentValue[i].mPayload.Value().ComputeLengthAndData(); + record.mPayload.AppendElements(currentValue[i].mPayload.Value().Data(), + currentValue[i].mPayload.Value().Length()); + } + + mRecords.AppendElement(record); + } + +#undef COPY_FIELD +#undef COPY_OPT_FIELD + } + + nsString mType; + int32_t mSessionId; + nsString mRequestId; + int32_t mPowerLevel; + int32_t mTechType; + nsTArray mRecords; +}; + +struct EventOptions +{ + EventOptions() + : mType(EmptyString()), mStatus(-1), mSessionId(-1), mRequestId(EmptyString()), mMajorVersion(-1), mMinorVersion(-1), + mIsReadOnly(-1), mCanBeMadeReadOnly(-1), mMaxSupportedLength(-1), mPowerLevel(-1) + {} + + nsString mType; + int32_t mStatus; + int32_t mSessionId; + nsString mRequestId; + int32_t mMajorVersion; + int32_t mMinorVersion; + nsTArray mTechList; + nsTArray mRecords; + int32_t mIsReadOnly; + int32_t mCanBeMadeReadOnly; + int32_t mMaxSupportedLength; + int32_t mPowerLevel; +}; + +} // namespace mozilla + +#endif diff --git a/dom/system/gonk/NfcService.cpp b/dom/system/gonk/NfcService.cpp new file mode 100644 index 000000000000..02ed8d611b55 --- /dev/null +++ b/dom/system/gonk/NfcService.cpp @@ -0,0 +1,352 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NfcService.h" +#include +#include "mozilla/ModuleUtils.h" +#include "mozilla/ClearOnShutdown.h" +#include "mozilla/dom/ToJSValue.h" +#include "mozilla/dom/RootedDictionary.h" +#include "nsAutoPtr.h" +#include "nsCxPusher.h" +#include "nsString.h" +#include "nsXULAppAPI.h" +#include "NfcOptions.h" + +#define NS_NFCSERVICE_CID \ + { 0x584c9a21, 0x4e17, 0x43b7, {0xb1, 0x6a, 0x87, 0xa0, 0x42, 0xef, 0xd4, 0x64} } +#define NS_NFCSERVICE_CONTRACTID "@mozilla.org/nfc/service;1" + +using namespace android; +using namespace mozilla::dom; +using namespace mozilla::ipc; + +nsLiteralString NfcTechString[] = { + NS_LITERAL_STRING("NDEF"), + NS_LITERAL_STRING("NDEF_WRITEABLE"), + NS_LITERAL_STRING("NDEF_FORMATABLE"), + NS_LITERAL_STRING("P2P"), + NS_LITERAL_STRING("NFC_A"), + NS_LITERAL_STRING("NFC_B"), + NS_LITERAL_STRING("NFC_F"), + NS_LITERAL_STRING("NFC_V"), + NS_LITERAL_STRING("NFC_ISO_DEP"), + NS_LITERAL_STRING("MIFARE_CLASSIC"), + NS_LITERAL_STRING("MIFARE_ULTRALIGHT"), + NS_LITERAL_STRING("BARCODE") +}; + +namespace mozilla { + +static NfcService* gNfcService; + +NS_IMPL_ISUPPORTS(NfcService, nsINfcService) + +void +assertIsNfcServiceThread() +{ + nsCOMPtr thread = do_GetCurrentThread(); + MOZ_ASSERT(thread == gNfcService->GetThread()); +} + +// Runnable used to call Marshall on the NFC thread. +class NfcCommandRunnable : public nsRunnable +{ +public: + NfcCommandRunnable(NfcMessageHandler* aHandler, NfcConsumer* aConsumer, CommandOptions aOptions) + : mHandler(aHandler), mConsumer(aConsumer), mOptions(aOptions) + { + MOZ_ASSERT(NS_IsMainThread()); + } + + NS_IMETHOD Run() + { + assertIsNfcServiceThread(); + + Parcel parcel; + parcel.writeInt32(0); // Parcel Size. + mHandler->Marshall(parcel, mOptions); + parcel.setDataPosition(0); + uint32_t sizeBE = htonl(parcel.dataSize() - sizeof(int)); + parcel.writeInt32(sizeBE); + mConsumer->PostToNfcDaemon(parcel.data(), parcel.dataSize()); + return NS_OK; + } + +private: + NfcMessageHandler* mHandler; + NfcConsumer* mConsumer; + CommandOptions mOptions; +}; + +// Runnable used dispatch the NfcEventOptions on the main thread. +class NfcEventDispatcher : public nsRunnable +{ +public: + NfcEventDispatcher(EventOptions& aEvent) + : mEvent(aEvent) + { + assertIsNfcServiceThread(); + } + + NS_IMETHOD Run() + { + MOZ_ASSERT(NS_IsMainThread()); + + mozilla::AutoSafeJSContext cx; + RootedDictionary event(cx); + + // the copy constructor is private. +#define COPY_FIELD(prop) event.prop = mEvent.prop; + +#define COPY_OPT_FIELD(prop, defaultValue) \ + if (mEvent.prop != defaultValue) { \ + event.prop.Construct(); \ + event.prop.Value() = mEvent.prop; \ + } + + COPY_FIELD(mType) + COPY_OPT_FIELD(mRequestId, EmptyString()) + COPY_OPT_FIELD(mStatus, -1) + COPY_OPT_FIELD(mSessionId, -1) + COPY_OPT_FIELD(mMajorVersion, -1) + COPY_OPT_FIELD(mMinorVersion, -1) + COPY_OPT_FIELD(mPowerLevel, -1) + + if (mEvent.mTechList.Length() > 0) { + int length = mEvent.mTechList.Length(); + event.mTechList.Construct(); + + if (!event.mTechList.Value().SetCapacity(length)) { + return NS_ERROR_FAILURE; + } + + for (int i = 0; i < length; i++) { + nsString& elem = *event.mTechList.Value().AppendElement(); + elem = NfcTechString[mEvent.mTechList[i]]; + } + } + + if (mEvent.mRecords.Length() > 0) { + int length = mEvent.mRecords.Length(); + event.mRecords.Construct(); + if (!event.mRecords.Value().SetCapacity(length)) { + return NS_ERROR_FAILURE; + } + + for (int i = 0; i < length; i++) { + NDEFRecordStruct& recordStruct = mEvent.mRecords[i]; + NDEFRecord& record = *event.mRecords.Value().AppendElement(); + + record.mTnf.Construct(); + record.mTnf.Value() = recordStruct.mTnf; + + if (recordStruct.mType.Length() > 0) { + record.mType.Construct(); + record.mType.Value().Init(Uint8Array::Create(cx, recordStruct.mType.Length(), recordStruct.mType.Elements())); + } + + if (recordStruct.mId.Length() > 0) { + record.mId.Construct(); + record.mId.Value().Init(Uint8Array::Create(cx, recordStruct.mId.Length(), recordStruct.mId.Elements())); + } + + if (recordStruct.mPayload.Length() > 0) { + record.mPayload.Construct(); + record.mPayload.Value().Init(Uint8Array::Create(cx, recordStruct.mPayload.Length(), recordStruct.mPayload.Elements())); + } + } + } + + COPY_OPT_FIELD(mIsReadOnly, -1) + COPY_OPT_FIELD(mCanBeMadeReadOnly, -1) + COPY_OPT_FIELD(mMaxSupportedLength, -1) + +#undef COPY_FIELD +#undef COPY_OPT_FIELD + + gNfcService->DispatchNfcEvent(event); + return NS_OK; + } + +private: + EventOptions mEvent; +}; + +// Runnable used to call Unmarshall on the NFC thread. +class NfcEventRunnable : public nsRunnable +{ +public: + NfcEventRunnable(NfcMessageHandler* aHandler, UnixSocketRawData* aData) + : mHandler(aHandler), mData(aData) + { + MOZ_ASSERT(NS_IsMainThread()); + } + + NS_IMETHOD Run() + { + assertIsNfcServiceThread(); + + size_t size = mData->mSize; + size_t offset = 0; + + while (size > 0) { + EventOptions event; + const uint8_t* data = mData->mData.get(); + uint32_t parcelSize = ((data[offset + 0] & 0xff) << 24) | + ((data[offset + 1] & 0xff) << 16) | + ((data[offset + 2] & 0xff) << 8) | + (data[offset + 3] & 0xff); + MOZ_ASSERT(parcelSize <= (mData->mSize - offset)); + + Parcel parcel; + parcel.setData(&data[offset], parcelSize + sizeof(int)); + mHandler->Unmarshall(parcel, event); + nsCOMPtr runnable = new NfcEventDispatcher(event); + NS_DispatchToMainThread(runnable); + + size -= parcel.dataSize(); + offset += parcel.dataSize(); + } + + return NS_OK; + } + +private: + NfcMessageHandler* mHandler; + nsAutoPtr mData; +}; + +NfcService::NfcService() + : mConsumer(new NfcConsumer(this)) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!gNfcService); +} + +NfcService::~NfcService() +{ + MOZ_ASSERT(!gNfcService); +} + +already_AddRefed +NfcService::FactoryCreate() +{ + if (XRE_GetProcessType() != GeckoProcessType_Default) { + return nullptr; + } + + MOZ_ASSERT(NS_IsMainThread()); + + if (!gNfcService) { + gNfcService = new NfcService(); + ClearOnShutdown(&gNfcService); + } + + nsRefPtr service = gNfcService; + return service.forget(); +} + +NS_IMETHODIMP +NfcService::Start(nsINfcEventListener* aListener) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aListener); + MOZ_ASSERT(!mThread); + + nsresult rv = NS_NewNamedThread("NfcThread", getter_AddRefs(mThread)); + if (NS_FAILED(rv)) { + NS_WARNING("Can't create Nfc worker thread."); + Shutdown(); + return NS_ERROR_FAILURE; + } + + mListener = aListener; + mHandler = new NfcMessageHandler(); + + return NS_OK; +} + +NS_IMETHODIMP +NfcService::Shutdown() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (mThread) { + mThread->Shutdown(); + mThread = nullptr; + } + + mConsumer->Shutdown(); + + return NS_OK; +} + +NS_IMETHODIMP +NfcService::SendCommand(JS::HandleValue aOptions, JSContext* aCx) +{ + MOZ_ASSERT(NS_IsMainThread()); + + NfcCommandOptions options; + + if (!options.Init(aCx, aOptions)) { + NS_WARNING("Bad dictionary passed to NfcService::SendCommand"); + return NS_ERROR_FAILURE; + } + + // Dispatch the command to the NFC thread. + CommandOptions commandOptions(options); + nsCOMPtr runnable = new NfcCommandRunnable(mHandler, mConsumer, commandOptions); + mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); + return NS_OK; +} + +void +NfcService::DispatchNfcEvent(const mozilla::dom::NfcEventOptions& aOptions) +{ + MOZ_ASSERT(NS_IsMainThread()); + + mozilla::AutoSafeJSContext cx; + JS::RootedValue val(cx); + + if (!ToJSValue(cx, aOptions, &val)) { + return; + } + + mListener->OnEvent(val); +} + +void +NfcService::ReceiveSocketData(nsAutoPtr& aData) +{ + MOZ_ASSERT(mHandler); + nsCOMPtr runnable = new NfcEventRunnable(mHandler, aData.forget()); + mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); +} + +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NfcService, + NfcService::FactoryCreate) + +NS_DEFINE_NAMED_CID(NS_NFCSERVICE_CID); + +static const mozilla::Module::CIDEntry kNfcServiceCIDs[] = { + { &kNS_NFCSERVICE_CID, false, nullptr, NfcServiceConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kNfcServiceContracts[] = { + { NS_NFCSERVICE_CONTRACTID, &kNS_NFCSERVICE_CID }, + { nullptr } +}; + +static const mozilla::Module kNfcServiceModule = { + mozilla::Module::kVersion, + kNfcServiceCIDs, + kNfcServiceContracts, + nullptr +}; + +} // namespace mozilla + +NSMODULE_DEFN(NfcServiceModule) = &mozilla::kNfcServiceModule; diff --git a/dom/system/gonk/NfcService.h b/dom/system/gonk/NfcService.h new file mode 100644 index 000000000000..94f0191c48f9 --- /dev/null +++ b/dom/system/gonk/NfcService.h @@ -0,0 +1,51 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NfcService_h +#define NfcService_h + +#include "mozilla/ipc/Nfc.h" +#include "mozilla/ipc/UnixSocket.h" +#include "nsCOMPtr.h" +#include "nsINfcService.h" +#include "NfcMessageHandler.h" + +class nsIThread; + +namespace mozilla { +namespace dom { +class NfcEventOptions; +} // namespace dom + +class NfcService MOZ_FINAL : public nsINfcService, + public mozilla::ipc::NfcSocketListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSINFCSERVICE + + static already_AddRefed FactoryCreate(); + + void DispatchNfcEvent(const mozilla::dom::NfcEventOptions& aOptions); + + virtual void + ReceiveSocketData(nsAutoPtr& aData) MOZ_OVERRIDE; + + nsCOMPtr GetThread() { + return mThread; + } + +private: + NfcService(); + ~NfcService(); + + nsCOMPtr mThread; + nsCOMPtr mListener; + nsRefPtr mConsumer; + nsAutoPtr mHandler; +}; + +} // namespace mozilla + +#endif // NfcService_h diff --git a/dom/system/gonk/SystemWorkerManager.cpp b/dom/system/gonk/SystemWorkerManager.cpp index a968fc9cbbcf..5830dacce456 100644 --- a/dom/system/gonk/SystemWorkerManager.cpp +++ b/dom/system/gonk/SystemWorkerManager.cpp @@ -30,9 +30,6 @@ #ifdef MOZ_B2G_RIL #include "mozilla/ipc/Ril.h" #endif -#ifdef MOZ_NFC -#include "mozilla/ipc/Nfc.h" -#endif #include "mozilla/ipc/KeyStore.h" #include "nsIObserverService.h" #include "nsCxPusher.h" @@ -125,10 +122,6 @@ SystemWorkerManager::Shutdown() RilConsumer::Shutdown(); #endif -#ifdef MOZ_NFC - NfcConsumer::Shutdown(); -#endif - nsCOMPtr wifi(do_QueryInterface(mWifiWorker)); if (wifi) { wifi->Shutdown(); @@ -207,28 +200,6 @@ SystemWorkerManager::RegisterRilWorker(unsigned int aClientId, #endif // MOZ_B2G_RIL } -nsresult -SystemWorkerManager::RegisterNfcWorker(JS::Handle aWorker, - JSContext* aCx) -{ -#ifndef MOZ_NFC - return NS_ERROR_NOT_IMPLEMENTED; -#else - NS_ENSURE_TRUE(aWorker.isObject(), NS_ERROR_UNEXPECTED); - - JSAutoCompartment ac(aCx, &aWorker.toObject()); - - WorkerCrossThreadDispatcher* wctd = - GetWorkerCrossThreadDispatcher(aCx, aWorker); - if (!wctd) { - NS_WARNING("Failed to GetWorkerCrossThreadDispatcher for nfc"); - return NS_ERROR_FAILURE; - } - - return NfcConsumer::Register(wctd); -#endif // MOZ_NFC -} - nsresult SystemWorkerManager::InitWifi(JSContext *cx) { diff --git a/dom/system/gonk/moz.build b/dom/system/gonk/moz.build index 2422bb6a4b9e..a12cc060577d 100644 --- a/dom/system/gonk/moz.build +++ b/dom/system/gonk/moz.build @@ -96,8 +96,13 @@ if CONFIG['MOZ_B2G_RIL']: ] if CONFIG['MOZ_NFC']: + SOURCES += [ + 'NfcMessageHandler.cpp', + 'NfcService.cpp', + ] XPIDL_SOURCES += [ 'nsINfcContentHelper.idl', + 'nsINfcService.idl', ] EXTRA_COMPONENTS += [ 'Nfc.js', diff --git a/dom/system/gonk/nsINfcService.idl b/dom/system/gonk/nsINfcService.idl new file mode 100644 index 000000000000..dfd614e4900f --- /dev/null +++ b/dom/system/gonk/nsINfcService.idl @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +[scriptable, uuid(976d2074-cb40-41f7-a195-8feee42eaace)] +interface nsINfcEventListener : nsISupports +{ + void onEvent(in jsval event); +}; + +[scriptable, uuid(0329e687-87ff-4cf5-8aa5-e876d9d4a375)] +interface nsINfcService : nsISupports +{ + void start(in nsINfcEventListener listener); + void shutdown(); + + [implicit_jscontext] + void sendCommand(in jsval param); +}; diff --git a/dom/system/gonk/nsISystemWorkerManager.idl b/dom/system/gonk/nsISystemWorkerManager.idl index f928400db197..a77e253e4b68 100644 --- a/dom/system/gonk/nsISystemWorkerManager.idl +++ b/dom/system/gonk/nsISystemWorkerManager.idl @@ -7,13 +7,10 @@ /** * Information about networks that is exposed to network manager API consumers. */ -[scriptable, builtinclass, uuid(a9ea96a0-407d-11e3-aa6e-0800200c9a66)] +[scriptable, builtinclass, uuid(4984b669-0ee0-4809-ae96-3358a325a6b0)] interface nsISystemWorkerManager : nsISupports { [implicit_jscontext] void registerRilWorker(in unsigned long aClientId, in jsval aWorker); - - [implicit_jscontext] - void registerNfcWorker(in jsval aWorker); }; diff --git a/dom/webidl/NfcOptions.webidl b/dom/webidl/NfcOptions.webidl new file mode 100644 index 000000000000..dd2509eb2edc --- /dev/null +++ b/dom/webidl/NfcOptions.webidl @@ -0,0 +1,46 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +dictionary NDEFRecord +{ + byte tnf; + Uint8Array type; + Uint8Array id; + Uint8Array payload; +}; + +dictionary NfcCommandOptions +{ + DOMString type = ""; + + long sessionId; + DOMString requestId = ""; + + long powerLevel; + + long techType; + + sequence records; +}; + +dictionary NfcEventOptions +{ + DOMString type = ""; + + long status; + long sessionId; + DOMString requestId; + + long majorVersion; + long minorVersion; + + sequence techList; + sequence records; + + boolean isReadOnly; + boolean canBeMadeReadOnly; + long maxSupportedLength; + + long powerLevel; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 6fd8439ba41e..b179bc114d00 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -602,6 +602,7 @@ if CONFIG['MOZ_NFC']: 'MozNFC.webidl', 'MozNFCPeer.webidl', 'MozNFCTag.webidl', + 'NfcOptions.webidl', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': diff --git a/ipc/nfc/Nfc.cpp b/ipc/nfc/Nfc.cpp index c43f9c60155a..04f6fca4298c 100644 --- a/ipc/nfc/Nfc.cpp +++ b/ipc/nfc/Nfc.cpp @@ -24,7 +24,6 @@ #include "mozilla/ArrayUtils.h" #include "nsThreadUtils.h" // For NS_IsMainThread. -USING_WORKERS_NAMESPACE using namespace mozilla::ipc; namespace { @@ -35,142 +34,33 @@ const char* NFC_SOCKET_NAME = "/dev/socket/nfcd"; // desktop development. const uint32_t NFC_TEST_PORT = 6400; -nsRefPtr sNfcConsumer; - -class ConnectWorkerToNFC : public WorkerTask -{ -public: - ConnectWorkerToNFC() - { } - - virtual bool RunTask(JSContext* aCx); -}; - class SendNfcSocketDataTask : public nsRunnable { public: - SendNfcSocketDataTask(UnixSocketRawData* aRawData) - : mRawData(aRawData) + SendNfcSocketDataTask(NfcConsumer* aConsumer, UnixSocketRawData* aRawData) + : mConsumer(aConsumer), mRawData(aRawData) { } NS_IMETHOD Run() { MOZ_ASSERT(NS_IsMainThread()); - if (!sNfcConsumer || - sNfcConsumer->GetConnectionStatus() != SOCKET_CONNECTED) { + if (!mConsumer || + mConsumer->GetConnectionStatus() != SOCKET_CONNECTED) { // Probably shuting down. delete mRawData; return NS_OK; } - sNfcConsumer->SendSocketData(mRawData); + mConsumer->SendSocketData(mRawData); return NS_OK; } private: + NfcConsumer* mConsumer; UnixSocketRawData* mRawData; }; -bool -PostToNFC(JSContext* aCx, - unsigned aArgc, - JS::Value* aVp) -{ - JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp); - NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread"); - - if (args.length() != 1) { - JS_ReportError(aCx, "Expecting one argument with the NFC message"); - return false; - } - - JS::Value v = args[0]; - - JSAutoByteString abs; - void* data; - size_t size; - if (v.isString()) { - JS::Rooted str(aCx, v.toString()); - if (!abs.encodeUtf8(aCx, str)) { - return false; - } - - data = abs.ptr(); - size = abs.length(); - } else if (!v.isPrimitive()) { - JSObject* obj = v.toObjectOrNull(); - if (!JS_IsTypedArrayObject(obj)) { - JS_ReportError(aCx, "Object passed in wasn't a typed array"); - return false; - } - - uint32_t type = JS_GetArrayBufferViewType(obj); - if (type != js::Scalar::Int8 && - type != js::Scalar::Uint8 && - type != js::Scalar::Uint8Clamped) { - JS_ReportError(aCx, "Typed array data is not octets"); - return false; - } - - size = JS_GetTypedArrayByteLength(obj); - data = JS_GetArrayBufferViewData(obj); - } else { - JS_ReportError(aCx, - "Incorrect argument. Expecting a string or a typed array"); - return false; - } - - UnixSocketRawData* raw = new UnixSocketRawData(data, size); - - nsRefPtr task = - new SendNfcSocketDataTask(raw); - NS_DispatchToMainThread(task); - return true; -} - -bool -ConnectWorkerToNFC::RunTask(JSContext* aCx) -{ - // Set up the postNFCMessage on the function for worker -> NFC thread - // communication. - NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread"); - NS_ASSERTION(!JS_IsRunning(aCx), "Are we being called somehow?"); - JS::Rooted workerGlobal(aCx, JS::CurrentGlobalOrNull(aCx)); - - return !!JS_DefineFunction(aCx, workerGlobal, - "postNfcMessage", PostToNFC, 1, 0); -} - -class DispatchNFCEvent : public WorkerTask -{ -public: - DispatchNFCEvent(UnixSocketRawData* aMessage) - : mMessage(aMessage) - { } - - virtual bool RunTask(JSContext* aCx); - -private: - nsAutoPtr mMessage; -}; - -bool -DispatchNFCEvent::RunTask(JSContext* aCx) -{ - JS::Rooted obj(aCx, JS::CurrentGlobalOrNull(aCx)); - - JSObject* array = JS_NewUint8Array(aCx, mMessage->mSize); - if (!array) { - return false; - } - JS::Rooted arrayVal(aCx, JS::ObjectValue(*array)); - - memcpy(JS_GetArrayBufferViewData(array), mMessage->mData, mMessage->mSize); - JS::Rooted rval(aCx); - return JS_CallFunctionName(aCx, obj, "onNfcMessage", JS::HandleValueArray(arrayVal), &rval); -} - class NfcConnector : public mozilla::ipc::UnixSocketConnector { public: @@ -279,8 +169,8 @@ NfcConnector::GetSocketAddr(const sockaddr_any& aAddr, namespace mozilla { namespace ipc { -NfcConsumer::NfcConsumer(WorkerCrossThreadDispatcher* aDispatcher) - : mDispatcher(aDispatcher) +NfcConsumer::NfcConsumer(NfcSocketListener* aListener) + : mListener(aListener) , mShutdown(false) { mAddress = NFC_SOCKET_NAME; @@ -288,44 +178,34 @@ NfcConsumer::NfcConsumer(WorkerCrossThreadDispatcher* aDispatcher) ConnectSocket(new NfcConnector(), mAddress.get()); } -nsresult -NfcConsumer::Register(WorkerCrossThreadDispatcher* aDispatcher) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (sNfcConsumer) { - return NS_ERROR_FAILURE; - } - - nsRefPtr connection = new ConnectWorkerToNFC(); - if (!aDispatcher->PostTask(connection)) { - return NS_ERROR_UNEXPECTED; - } - - // Now that we're set up, connect ourselves to the NFC thread. - sNfcConsumer = new NfcConsumer(aDispatcher); - return NS_OK; -} - void NfcConsumer::Shutdown() { MOZ_ASSERT(NS_IsMainThread()); - if (sNfcConsumer) { - sNfcConsumer->mShutdown = true; - sNfcConsumer->CloseSocket(); - sNfcConsumer = nullptr; - } + mShutdown = true; + CloseSocket(); +} + +bool +NfcConsumer::PostToNfcDaemon(const uint8_t* aData, size_t aSize) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + UnixSocketRawData* raw = new UnixSocketRawData(aData, aSize); + nsRefPtr task = new SendNfcSocketDataTask(this, raw); + NS_DispatchToMainThread(task); + return true; } void -NfcConsumer::ReceiveSocketData(nsAutoPtr& aMessage) +NfcConsumer::ReceiveSocketData(nsAutoPtr& aData) { MOZ_ASSERT(NS_IsMainThread()); - nsRefPtr dre(new DispatchNFCEvent(aMessage.forget())); - mDispatcher->PostTask(dre); + if (mListener) { + mListener->ReceiveSocketData(aData); + } } void diff --git a/ipc/nfc/Nfc.h b/ipc/nfc/Nfc.h index 7448827c9729..56cbd9600e2a 100644 --- a/ipc/nfc/Nfc.h +++ b/ipc/nfc/Nfc.h @@ -9,31 +9,35 @@ #ifndef mozilla_ipc_Nfc_h #define mozilla_ipc_Nfc_h 1 -#include #include namespace mozilla { namespace ipc { +class NfcSocketListener +{ +public: + virtual void ReceiveSocketData(nsAutoPtr& aData) = 0; +}; + class NfcConsumer : public mozilla::ipc::UnixSocketConsumer { public: + NfcConsumer(NfcSocketListener* aListener); virtual ~NfcConsumer() { } - static nsresult Register(mozilla::dom::workers::WorkerCrossThreadDispatcher* aDispatcher); - static void Shutdown(); + void Shutdown(); + bool PostToNfcDaemon(const uint8_t* aData, size_t aSize); private: - NfcConsumer(mozilla::dom::workers::WorkerCrossThreadDispatcher* aDispatcher); - - virtual void ReceiveSocketData(nsAutoPtr& aMessage); + virtual void ReceiveSocketData(nsAutoPtr& aData); virtual void OnConnectSuccess(); virtual void OnConnectError(); virtual void OnDisconnect(); private: - nsRefPtr mDispatcher; + NfcSocketListener* mListener; nsCString mAddress; bool mShutdown; };