зеркало из https://github.com/mozilla/gecko-dev.git
Bug 933588 - Part 1: NFC service. r=khuey
This commit is contained in:
Родитель
1305f5ccb1
Коммит
c3e7baef48
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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 <binder/Parcel.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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<uint8_t> mType;
|
||||
nsTArray<uint8_t> mId;
|
||||
nsTArray<uint8_t> 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<mozilla::dom::NDEFRecord> 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<NDEFRecordStruct> 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<uint8_t> mTechList;
|
||||
nsTArray<NDEFRecordStruct> mRecords;
|
||||
int32_t mIsReadOnly;
|
||||
int32_t mCanBeMadeReadOnly;
|
||||
int32_t mMaxSupportedLength;
|
||||
int32_t mPowerLevel;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -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 <binder/Parcel.h>
|
||||
#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<nsIThread> 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<NfcEventOptions> 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<nsIRunnable> runnable = new NfcEventDispatcher(event);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
|
||||
size -= parcel.dataSize();
|
||||
offset += parcel.dataSize();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
NfcMessageHandler* mHandler;
|
||||
nsAutoPtr<UnixSocketRawData> mData;
|
||||
};
|
||||
|
||||
NfcService::NfcService()
|
||||
: mConsumer(new NfcConsumer(this))
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!gNfcService);
|
||||
}
|
||||
|
||||
NfcService::~NfcService()
|
||||
{
|
||||
MOZ_ASSERT(!gNfcService);
|
||||
}
|
||||
|
||||
already_AddRefed<NfcService>
|
||||
NfcService::FactoryCreate()
|
||||
{
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!gNfcService) {
|
||||
gNfcService = new NfcService();
|
||||
ClearOnShutdown(&gNfcService);
|
||||
}
|
||||
|
||||
nsRefPtr<NfcService> 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<nsIRunnable> 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<UnixSocketRawData>& aData)
|
||||
{
|
||||
MOZ_ASSERT(mHandler);
|
||||
nsCOMPtr<nsIRunnable> 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;
|
|
@ -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<NfcService> FactoryCreate();
|
||||
|
||||
void DispatchNfcEvent(const mozilla::dom::NfcEventOptions& aOptions);
|
||||
|
||||
virtual void
|
||||
ReceiveSocketData(nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aData) MOZ_OVERRIDE;
|
||||
|
||||
nsCOMPtr<nsIThread> GetThread() {
|
||||
return mThread;
|
||||
}
|
||||
|
||||
private:
|
||||
NfcService();
|
||||
~NfcService();
|
||||
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
nsCOMPtr<nsINfcEventListener> mListener;
|
||||
nsRefPtr<mozilla::ipc::NfcConsumer> mConsumer;
|
||||
nsAutoPtr<NfcMessageHandler> mHandler;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // NfcService_h
|
|
@ -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<nsIWifi> 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<JS::Value> 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)
|
||||
{
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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);
|
||||
};
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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<NDEFRecord> records;
|
||||
};
|
||||
|
||||
dictionary NfcEventOptions
|
||||
{
|
||||
DOMString type = "";
|
||||
|
||||
long status;
|
||||
long sessionId;
|
||||
DOMString requestId;
|
||||
|
||||
long majorVersion;
|
||||
long minorVersion;
|
||||
|
||||
sequence<DOMString> techList;
|
||||
sequence<NDEFRecord> records;
|
||||
|
||||
boolean isReadOnly;
|
||||
boolean canBeMadeReadOnly;
|
||||
long maxSupportedLength;
|
||||
|
||||
long powerLevel;
|
||||
};
|
|
@ -602,6 +602,7 @@ if CONFIG['MOZ_NFC']:
|
|||
'MozNFC.webidl',
|
||||
'MozNFCPeer.webidl',
|
||||
'MozNFCTag.webidl',
|
||||
'NfcOptions.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
|
|
170
ipc/nfc/Nfc.cpp
170
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<mozilla::ipc::NfcConsumer> 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<JSString*> 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<SendNfcSocketDataTask> 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<JSObject*> 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<UnixSocketRawData> mMessage;
|
||||
};
|
||||
|
||||
bool
|
||||
DispatchNFCEvent::RunTask(JSContext* aCx)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
|
||||
JSObject* array = JS_NewUint8Array(aCx, mMessage->mSize);
|
||||
if (!array) {
|
||||
return false;
|
||||
}
|
||||
JS::Rooted<JS::Value> arrayVal(aCx, JS::ObjectValue(*array));
|
||||
|
||||
memcpy(JS_GetArrayBufferViewData(array), mMessage->mData, mMessage->mSize);
|
||||
JS::Rooted<JS::Value> 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<ConnectWorkerToNFC> 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<SendNfcSocketDataTask> task = new SendNfcSocketDataTask(this, raw);
|
||||
NS_DispatchToMainThread(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
NfcConsumer::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
|
||||
NfcConsumer::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<DispatchNFCEvent> dre(new DispatchNFCEvent(aMessage.forget()));
|
||||
mDispatcher->PostTask(dre);
|
||||
if (mListener) {
|
||||
mListener->ReceiveSocketData(aData);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -9,31 +9,35 @@
|
|||
#ifndef mozilla_ipc_Nfc_h
|
||||
#define mozilla_ipc_Nfc_h 1
|
||||
|
||||
#include <mozilla/dom/workers/Workers.h>
|
||||
#include <mozilla/ipc/UnixSocket.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class NfcSocketListener
|
||||
{
|
||||
public:
|
||||
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& 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<UnixSocketRawData>& aMessage);
|
||||
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aData);
|
||||
|
||||
virtual void OnConnectSuccess();
|
||||
virtual void OnConnectError();
|
||||
virtual void OnDisconnect();
|
||||
|
||||
private:
|
||||
nsRefPtr<mozilla::dom::workers::WorkerCrossThreadDispatcher> mDispatcher;
|
||||
NfcSocketListener* mListener;
|
||||
nsCString mAddress;
|
||||
bool mShutdown;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче